Hybris开发

原理

$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, 实现这个功能有三种常见的方案:

  1. API注入,原理其实就是 Native 获取 JavaScript环境上下文,并直接在上面挂载对象或者方法,使 js 可以直接调用,Android 与 IOS 分别拥有对应的挂载方式
  2. WebView 中的 prompt/console/alert 拦截,通常使用 prompt,因为这个方法在前端中使用频率低,比较不会出现冲突
  3. 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
13
var 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);
}

  1. log定义log=console.log.bind(this,'h5Debug|')在ios中没有报错,但在android中会出错,阻止后面代码的执行
  2. iosvar arr=stack.split("\n")[2].split(":");会出错,好像是stack是未定义的,没有仔细研究,直接取消行号/或者取消ios的log
  3. android还没有核查

数据传递

传递json字符串,可能有的不支持传递数组或对象
注意把/r,/r,/t等影响JSON.parse()的字符串替换/转义

android不知道怎么做的,传了几次都不对-_-。提供一个链接(不知道对不对):
JAVA中使用JSON进行数据传递

一 CEF

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
const IsCEF=!!window.cefQuery;
var log;
if(IsCEF){
// log=console.log.bind(this,'h5Debug|') // if not need string info,but right num
log=function(){ // if need string info and right line num
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];
console.log('h5Debug('+line+')|'+str);
}
}else{
log=console.log.bind(this)
}
function msgCef(cmd,data){
// log('msg cef cmd/data',cmd,data)
if(!IsCEF) return;
window.cefQuery({
request: JSON.stringify({cmd,data}),
// onSuccess:res=>log('msg cef success:',res), //DEBUG
// onFailure:res=>log('msg cef error:',res) //DEBUG
// ## 2.0 switch
// onSuccess:onCef
})
}
// ## 2.1 callback
// ## 2 Promise
function msgCef(cmd,data){
// log('msg cef cmd/data',cmd,data)
if(!IsCEF) return new Promise((res,rej)=>{
setTimeout(res,1500,{code:0})
});
return new Promise((res,rej)=>{
window.cefQuery({
request: JSON.stringify({cmd,data}),
onSuccess:response=>res(response),
onFailure:response=>rej(response)
})
})
}
// 2.0 switch
function onCef(res){
var res=JSON.parse(res)
const {cmd,data}=res;
switch(cmd){
case '':
break;
default:
break;
}
}

二 WKWebView

非UIWebView

1
2
3
4
5
6
7
8
var 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
13
const 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var _gbDebug = false; 
function DebugMsg(sInfo) {
if ( _gbDebug ) {
alert(sInfo);
}
}

window._callFun = function(){
if(!PreventRepeatedClick()) return;
var fun;
if(false && window.external && window.external.CB_CustomFunction ) {
fun = "window.external.CB_CustomFunction(";
for(i=0;i<arguments.length;i++){
if(i!=0)
fun = fun+",";
fun = fun+"\""+arguments[i]+"\"";
}
fun = fun+")";
//alert(fun);
return (eval(fun));
}else {
fun = "";
for(i=0;i<arguments.length;i++){
if(i!=0)
fun = fun+",";
fun = fun + arguments[i];
}
_gaCMDToControl[_gaCMDToControl.length] = fun;
document.title = GetJSCommand();
}
}

网页调用exe

自定义协议,而且可以传第参数,比如
sutdent.batcloudclass.exe "cloudclass://mhjnhpjenfhpmmfioljfjcfephkgdfkm...jbpbgmkailkigc"

knowledge is no pay,reward is kindness
0%