(防盗镇楼)本文地址:https://blog.csdn.net/cbaili/article/details/128651549
前言
最近在撸VUE,想要实现一份代码既能构建Web又能构建Electron应用
并且能够判断环境是浏览器还是Electron,随后在Electron中做一些特定的事情
以往的Electron通信依靠IPC通信完成,但是发布到Web端运行会报错找不到__dirname
这是因为网页浏览器与Electron不同,Electron集成了Node环境,所以Electron能够访问到.
苦寻良久,终于在一个帖子上发现了解决方案:网页与Electron通信
解决方案
这个方案利用Electron的自定义协议实现.
在前端项目中无需引用任何Electron库即可实现与Electron通信,过程可控,完美!
什么是自定义协议?
标准协议就是http https这类的,自定义协议顾名思义就是允许你定义一个协议,自己来实现通信数据处理过程。
你大概率见到过一些网页唤醒本机应用程序的案例,比如百度网盘、Steam等.它们都是利用了这个机制实现。
你可以自定义一个myapp的协议,通过myAPP://lala/?data=123这样的url访问资源
但我们需要的不同,我们不希望去唤醒应用程序,而是直接让Electron拦截掉这个请求。
来看看API
Electron为我们提供了protocol类,它用于注册自定义协议和拦截自定义请求并允许自定义数据处理过程.
这东西用起来很简单,看代码案例:
//electron项目的index.js
const URL = require('url');
const { app, BrowserWindow, protocol } = require('electron')
const MY_CUSTOM_PROTOCOL_SCHEMA="myapp";//命名需要遵循URL PROTOCOL协议
//#第一步:注册自定义协议,必须在app ready之前完成,且只能调用一次
protocol.registerSchemesAsPrivileged([ { scheme: MY_CUSTOM_PROTOCOL_SCHEMA}])
app.on('ready', () => {
win = new BrowserWindow({ width: 800, height: 600 })
win.loadURL('http://127.0.0.1:5173/#/')
if (!process.env.IS_TEST) win.webContents.openDevTools();
//#第二步:定义刚刚注册的自定义协议返回数据类型
//protocol.registerBufferProtocol
//protocol.registerFileProtocol
//protocol.registerHttpProtocol
//protocol.registerStreamProtocol
//protocol.registerStringProtocol
//这里以返回文本为例
protocol.registerStringProtocol(MY_CUSTOM_PROTOCOL_SCHEMA, (req, res) => {
//我们可以使用node.js的url模块对地址进行解析
//参考:https://cloud.tencent.com/developer/article/1653911
let url = URL.parse(req.url, true)
console.log("myapp:// Requested", req, res,url);
//do something it here..
res("lalala")//返回给网页的数据,你可以做成JSON返回
})
})
//前端js调用部分
callMyapp("asd/ccc?eee=123")
function callMyapp(path){
const MY_CUSTOM_PROTOCOL_SCHEMA="myapp"
const url=`${MY_CUSTOM_PROTOCOL_SCHEMA}://${path}`
//构建get请求(axios不支持自定义协议会报错)
var httpRequest = new XMLHttpRequest();
httpRequest.open('GET', url, true);
httpRequest.send();
httpRequest.onreadystatechange = () => {
if (httpRequest.readyState == 4 && httpRequest.status == 200) {
console.log(httpRequest.responseText);
}
};
}
以上就实现了简单的通信请求,我们可以通过在Electron中判断请求URL做一些事情了.
还有,URL最大支持2083个字符,所以你要传递的数据文本长度不可以超过这个数字…
辅助
判断网页是否运行在Electron中
const isElectron = /electron/i.test(navigator.userAgent);
上面的代码实现了判断是否运行在Electron中
但运行的Electron不一定是我们自己的app,它内部没有我们注册的自定义协议,这样会导致调用请求的时候报错
所以我们还需要更精准的判断:
我们可以通过查看输出navigator.userAgent,发现其中有一段包含了我们app的名字和版本号
所以,我们可以通过修改上面的判断条件实现
const isRunInApp = /MGPS_DESKTOP/i.test(navigator.userAgent)
安全考虑
这个方案显然还有一些安全上的问题需要处理,比如:
- 接口来源认证:不能说随便一个网站用了这个方法就都能调用我们APP的接口
- 暴力请求过滤:防止系统资源耗尽
- 加密通信数据:加密get请求的url
- 防注入等等
- …
所以我们尽量不要在接口中进行一些高危操作,如果要有必须要加验证机制.
最终
有了以上两部分内容,我们可以针对网站运行在我们自己的客户端情况下,做出一些特殊功能支持,比如一些情景:
- 模拟窗口:在网页浏览器中不显示标题栏按钮 但在Electron中显示并能够让Election响应最大化最小化关闭等按钮事件
- 绕过一些安全限制:可以从Elecron访问文件系统、操作硬件之类的(注意安全)
话说,这个文章标题真难起…
好用别忘了一按三联哦~