页面和应用之间的交互

前言

公司某个项目有一个功能,需要在网页上通过用户上传文件后,拉起本机的应用,然后应用显示上传速度等各种各样的详细信息,网页上显示上传进度等简短信息。类似zoom的完美体现。我们知道js是运行在浏览器的,所以拉起应用肯定需要各个桥梁相互配合。本篇文章也是这个探索过程的总结。

URI

看到功能第一下就想到了通过URI来实现。通过安装应用时的注册表来拉起应用。这是一个很普遍的拉起应用的方式,腾讯qq就是这种。但是不能做到交互。拉起就完事了。这不是我们想要的东西。

浏览器扩展

本文主要讲的就是浏览器扩展。
浏览器扩展赋予了js操作浏览器的能力,我们可以通过扩展来实现很多功能,如去除广告,浏览网页翻译,检测莫名的js或者病毒的植入等等,当然也包括了与其他应用的通信。其中用到的就是native Message。其中浏览器扩展的开发就不做过多的阐述了,网上很多。

大部分用户应该是使用win来浏览网页。我们主要也是讲win。win平台下的浏览器也是五花八门但是总结下来基本上就是谷歌,火狐,EDGE,IE。其中IE仅支持activeX来扩展,目前基本已经淘汰,不在我们这次的考虑中,但是ie也需要实现这项功能,暂时留着以后讨论。

首先扩展的核心代码为

1
2
3
4
5
6
7
8
9
10
11
12
/// background.js
const nativeHostName = 'your nativeHostName'; // 定义nativeHostName,通常为com.chrome.app这种形式
const port = chrome.runtime.connectNative(nativeHostName);// 谷歌扩展下的写法
const port = browser.runtime.connectNative(nativeHostName);// edge,火狐下的写法
/// 获得一个port对象,后面port的方法是一致的。
port.onDisconnect.addListener(function(){
// 失去连接port = null;
});
port.onMessage.addListener(function(message){
// 获取应用端传回来的message
});
port.postMessage({});// 给应用端发送消息

插件写法虽然类似,但是注册方法却各不相同。其中谷歌的注册清单json为

1
2
3
4
5
6
7
8
9
{"name": "com.chrome.test",
"description": "Chrome call native app and sent message to app.",
"path": "C:\\Users\\Public\\GoogleNativeClient\\NativeMessagingApp.exe",
"type": "stdio",

"allowed_origins": [
"chrome-extension://dkeepngffocdigjfgmbpffbcjpijdgppp/"
]}
//json文件,请记住name,因为注册时需要这个name.path为拉起应用的路径,type固定为'stdio',然后allowed_origins为数组,记录该扩展的id,即谷歌浏览器加载扩展后该扩展的id要与清单此处的id一直。

火狐的注册清单json为

1
2
3
4
5
6
7
8
9
{
"name": "com.firefox.test",
"description": "Chrome call native app and sent message to app.",
"path": "C:\\Users\\Public\\GoogleNativeClient\\NativeMessagingApp.exe",
"type": "stdio",
"allowed_extensions": [ "testFirefox@example.org" ]
}
//和谷歌类似,但是最后为allowed_extensions,这里为火狐浏览器的uid,可以通过manifest.json自定义.
// 注意!! 看似谷歌和火狐只是最后一个key不同,可以何必为同一个json,但是事实证明合并后是不能用的。

edge需要用到c#技术,所以微软这个注册清单的方式怎么不跟风呢?因为涉猎技术不够所以停止了edge的研究。

接下来是注册位置,win+R –> regedit

1
2
3
4

HKEY_CURRENT_USER\Software\Google\Chrome\NativeMessagingHosts\com.chrome.test // 谷歌路径
HKEY_LOCAL_MACHINE\SOFTWARE\Mozilla\NativeMessagingHosts\com.firefox.test // 火狐路径
默认值都为我们清单json的绝对路径

此时就可以在拉起应用并通信了。linux和mac下谷歌和火狐拉起应用方式一致,区别就是在于注册清单方式不同,这里就不过多讨论了。

扩展的方式虽然可以很精确的和应用通信,但是不难发现,不同浏览器需要开发不同的扩展,安装不同的注册表和json。safari甚至还需要mac才能开发扩展,并且收费,还有诸如ie这种需要更底层的技术,难以做到统一。

websocket

ws可能是能够找到的更加适合用来和应用通信的东西了。一来都是js写法,这样子可以统一各个浏览器的通信代码,二来支持ie10以上浏览器,兼容性还可以。现在就存在一个如何拉起应用和确定websocket服务端接口的问题了。其实细细思考也不是很难,URI拉起应用,应用通知后台拉起的应用的端口,后台通知网页已经拉起了应用和他的端口,网页和应用建立ws连接通信。看似简单,而且代码统一,但是还有很多坑要去踩,如ws的安全性等…

总结

与应用通信如果仅仅在单一系统下可以通过扩展的形式来实现,但是如果是多端多浏览器建议使用websocket。也许后面也会有更多更好的技术。


*作者简介: 张栓,人和未来大数据前端工程师,专注于 html/css/js 的学习与开发。