【踩坑记】在electron中使用webview加载第三方登录页面,若页面重定向的网址非我们想要的,如何拉起浏览器去加载?

需求背景:

在软件里加入第三方登录小窗进行软件的登录。

方案

方案一

第一个方案决定使用 iframe 加载第三方 web 登录网址。但是发现当页面点击登录重定向到二级过度登录页面时,会报跨域的错误。

方案二

于是决定尝试使用 webview 来内嵌这个第三方登录页面。

踩坑过程

electron : 10.0.1
vue : 2.5.16

1、在主进程里需要允许主窗口使用 webviewTag:

const win = new Browser({
...,
webPreferences: {
      nodeIntegration: true,
      nodeIntegrationInWorker: true,
      webviewTag: true, // 启用 <webview> tag 标签
    },
});

2、然后在登录界面上增加一个登陆按钮,并且点击后弹出第三方登录窗口:

<button @click="login">第三方登录</button>
...

<div class="login-wrap" ref="loginWrap" v-show="showLogin">
  <!-- 这里不进行静态加载 webview 是因为在 electron 中每次点击登录按钮就变更 webview 的 src 会报错 -->
  <!-- <webview ref="qcloudLogin" nodeintegration></webview> -->
  
  <button class="login__close" type="icon" title="关闭" @click="onCloseLoginDialog">
     <i class="close"></i>
   <button>
</div>

3、点击登录按钮后,动态向 $(".login-wrap") 插入 webview 并加载第三方 web 登录链接。

export default {
	mounted(){},
	method:{
	  async login(){
	      this.loginLoading = true;
	      const url = await dao.getLoginUrl(); // 获取第三方登录链接
	      this.loginLoading = false;
	      if (!url) return;
	
		  // 动态加入 webview 标签
	      this.webview = document.createElement('webview');
	      this.webview.src = url;
	      this.webview.style.height = '100%';
	      $(this.webview).attr('nodeintegration', ''); // 内嵌页面需要调用 node 则开启该开关
	      this.$refs.loginWrap.appendChild(this.webview);
	
	      this.webview.addEventListener('ipc-message', this.handleLogin);
	      this.showLogin = true;
	  },
	  // ipc-message:可与内嵌的页面进行通信,处理第三方登录成功与失败
	  handleLogin(event){},
	  // 关闭登录时记得移除事件与 webview 标签
	  onCloseLoginDialog() {
	    this.showQcloudLogin = false;
	    this.webview.removeEventListener('ipc-message', this.handleQcloudLogin);
	    this.$refs.loginWrap.removeChild(this.webview);
	    this.webview = {};
	  },
	},
}

这里明显埋了一个坑,第三方做的 web 登录页面中肯定除了登录,它还要为自己的网站引流,比如说会有注册账号,忘记密码等功能。在我们的软件里也不想预加载一个脚本去把这些跳转按钮给隐藏了(要为新注册用户导量呀),所以要将这些非登录的页面跳转到浏览器去让用户做接下来的操作。因此,这里需要去处理。

4、对于第三方页面可能有的新开页跳转,我们在渲染进程中可以直接监听 webview 的新窗口打开事件来处理:

注意,在创建 webview 标签时千万不要给其加 allowpopups 属性,因为在 ‘new-window’ 事件中调用 event.preventDefault() 阻止 electron 自己弹窗是不生效的。

this.webview.addEventListener('new-window', (e) => {
    const { protocol } = require('url').parse(e.url)
    if (protocol === 'http:' || protocol === 'https:') {
      await require('electron').shell.openExternal(e.url);
    }
});

5、如果第三方页面是重定向已有页面,不进行新开页面跳转,在渲染进程监听 webview 标签的 “will-navigate” (导航即将跳转)事件并调用 event.preventDefault() 是阻止不了 webview 的窗口跳转的。官方文档 webview 事件里也有进行说明。

在网上找了很久,看别人是怎么解决的,终于让我找到了这篇博客:截獲 <webview> will-navigate 事件, 為內容來源實作白名單

其实是借助主进程来帮忙。在主进程创建的窗口上的一个 webContents 有一个事件:‘did-attach-webview’,当<webview>被挂载到页面内容中时,该事件会被触发。这使得当<webview>挂载到登陆页面时,可以通过 ‘did-attach-webview’ 事件取到这个 webview 标签的 webContent。

然后在这个 webContent 的 will-navigate 事件里就可以截获页面跳转,阻止 webview 跳转到我们不想要的页面并可以拉取浏览器进行跳转。

// 注意这份代码应该写在主进程里,而不是渲染进程哦
win.webContents.on('did-attach-webview', (e, webContent)=>  {
  webContent.on('will-navigate', (e, url) => {
    if (util.isUrlAllowed(url)) return;
    // 不允许的网址则阻止页面跳转并拉取浏览器展示页面
    e.preventDefault();
    require('electron').shell.openExternal(url);
  });
});
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值