原理
$1 2019.2.15 星期五 14:21
# [JSBridge的原理]
4.1.1 JavaScript 调用 Native
JavaScript 调用 Native 的方式,主要有两种:注入 API 和 拦截 URL SCHEME。
4.1.2 Native 调用 JavaScript
不管是 iOS 的 UIWebView 还是 WKWebView,还是 Android 的 WebView 组件,都以子组件的形式存在于 View/Activity 中,直接调用相应的 API 即可。
Native 调用 JavaScript,其实就是执行拼接 JavaScript 字符串,从外部调用 JavaScript 中的方法,因此 JavaScript 的方法必须在全局的 window 上。(闭包里的方法,JavaScript 自己都调用不了,更不用想让 Native 去调用了)
# [什么是 Native、Web App、Hybrid、React Native 和 Weex]
# [Hybrid App技术解析 – 原理篇]
现有混合方案
Hybrid App,俗称混合应用,即混合了 Native技术 与 Web技术 进行开发的移动应用。现在比较流行的混合方案主要有三种,主要是在UI渲染机制上的不同:
1) 基于 WebView UI 的基础方案,市面上大部分主流 App 都有采用,例如微信JS-SDK,通过 JSBridge 完成 H5 与 Native 的双向通讯,从而赋予H5一定程度的原生能力。
2) 基于 Native UI 的方案,例如 React-Native、Weex。在赋予 H5 原生API能力的基础上,进一步通过 JSBridge 将js解析成的虚拟节点树(Virtual DOM)传递到 Native 并使用原生渲染。
3) 另外还有近期比较流行的小程序方案,也是通过更加定制化的 JSBridge,并使用双 WebView 双线程的模式隔离了JS逻辑与UI渲染,形成了特殊的开发模式,加强了 H5 与 Native 混合程度,提高了页面性能及开发体验。
最核心的点就是 Native端 与 H5端 之间的双向通讯层
这个方案就是我们所说的 JSBridge,而实现的关键,便是作为容器的 WebView,一切的原理都是基于 WebView 的机制。
(一) JavaScript 通知 Native
基于 WebView 的机制和开放的 API, 实现这个功能有三种常见的方案:
- API注入,原理其实就是 Native 获取 JavaScript环境上下文,并直接在上面挂载对象或者方法,使 js 可以直接调用,Android 与 IOS 分别拥有对应的挂载方式
- WebView 中的 prompt/console/alert 拦截,通常使用 prompt,因为这个方法在前端中使用频率低,比较不会出现冲突
- WebView URL Scheme 跳转拦截
(二) Native 通知 Javascript
由于 Native 可以算作 H5 的宿主,因此拥有更大的权限,上面也提到了 Native 可以通过 WebView API直接执行 Js 代码。
$1 15:02
2018.7.31 星期二
三端共适
都需要注意编码问题
ios白屏问题android也更换的布局方式
android webview不支持 filter,需要添加前缀 -webkit-filter
页面加载方式
本地加载页面-html(沙箱),所以不能向网络发起请求获得数据;需要中间件访问网络后,通过api传递给本地页面
本地快?为什么是本地加载html,不用服务器http(s)加载页面
#### icon-font图标在android闪烁
如果是本地都应该是 file:///D:/dev/../html/ 的加载方式,所以icon-font不需要添加crossorigin了
但是android中不论加不加,都会先看到细长的空图标占位然后变圆
不确定是否是由于android版本低造成fetch不兼容。*font-display:swap
估计也不行
#### 多语言
lang.js为ajax,而不是类似jquery/ng的i18n,所以需要exe提供服务:调用lang.js的api
定义log函数
如果是alert移动端需要做相应的设置;cef不确定1
2
3
4
5
6
7
8
9
10
11
12
13var log;
if(IsAndroid){
log=function(){
var str='';
[...arguments].forEach(v=>str+=(JSON.stringify(v)+';'))
var stack = new Error().stack;
var arr=stack.split("\n")[2].split(":");
var line = arr[arr.length-2];
window.androidCallback['h5Debug']('h5Debug('+line+')|'+str)
}
}else{
log=console.log.bind(this);
}
- log定义
log=console.log.bind(this,'h5Debug|')
在ios中没有报错,但在android中会出错,阻止后面代码的执行 - ios
var arr=stack.split("\n")[2].split(":");
会出错,好像是stack是未定义的,没有仔细研究,直接取消行号/或者取消ios的log - android还没有核查
数据传递
传递json字符串,可能有的不支持传递数组或对象
注意把/r,/r,/t
等影响JSON.parse()的字符串替换/转义
android不知道怎么做的,传了几次都不对-_-。提供一个链接(不知道对不对):
JAVA中使用JSON进行数据传递
一 CEF
1 | const IsCEF=!!window.cefQuery; |
二 WKWebView
非UIWebView1
2
3
4
5
6
7
8var log=console.log.bing(this);
const IsWKWV=!!window.webkit;
function msgMob(method,data){
// log('msg cef cmd/data',cmd,data)
if(!IsWKWV) return;
window.webkit.messageHandlers[method].postMessage(JSON.stringify(data))
// window.webkit.messageHandlers.method.postMessage(JSON.stringify(data))//error
}
白屏(只有IOS)
非内存,初步判定为滚动:只有出现定位,且内容过多(50条的时候还ok)的时候会白屏;
不要问怎么找到是css定位的问题。常理上css即使出错也不会有影响
#### 过程重现
1. 没有切换布局(每行显示4个->单行显示)前,同样的数据是ok的
1. 换布局后,.stuList ul li > div.speaker
出现定位position:absolute/relative
就会白屏
去掉定位后就是ok的
#### 解决方案
1. width: 把li下两个div inline-block,第一个设置宽度百分比
缺点:1) 右边的内容不会右对齐;2) 不同宽度下右边空离距离不同
2. headerFixed: 把.main{overflow-y:;}
取消掉,.header{position:fixed}
缺点:实际滚动的是body,滚动条会从header开始滚动
3. flex: li{display:flex;justify-content:space-between;}
滚动渲染机制可能是对的,解决方案(参考)在本case中没有作用
所以,干脆采用了新的布局方案flex,第一个div给定宽度(也不需要改display),也可以设置text-overflow
参考:
iOS WebView加载网页触摸白屏bug排查及修复
其他:
WKWebView刷新机制小探
http://www.poorren.com/ios-webview-white-screen-bug-fixes
三 Android Webkit
window.jsInterfaceName.methodName(parameterValues)1
2
3
4
5
6
7
8
9
10
11
12
13const IsWKWV=!!window.webkit;// ios WKWebView
const IsAndroid=!!window.androidCallback;// android point definded
function msgMob(method,data){
// log('msg cef cmd/data',cmd,data)
//if(!IsWKWV) return;
if(IsWKWV){
window.webkit.messageHandlers[method].postMessage(JSON.stringify(data));return;
}
if(IsAndroid){// android webkit
window.androidCallback[method](JSON.stringify(data));return;
}
return;
}
零 IE Interface
IE7,当时可是吃了亏,做的ie8
1 | var _gbDebug = false; |
网页调用exe
自定义协议,而且可以传第参数,比如
sutdent.batcloudclass.exe "cloudclass://mhjnhpjenfhpmmfioljfjcfephkgdfkm...jbpbgmkailkigc"