app native和 h5的通信方式-- jsbridge

什么是移动端通信?

有哪些是需要了解的开发背景知识?

怎么样开始一个移动端项目开发和调试呢?

看这篇文档记录,够入门  go--->

 

1   IOS 和Android底层和js的交互原理

 

ios提供UIWebView 组件,是一个可加载网页的对象,提供类似浏览器的功能,可以通过js代码调用一些原生的功能,比如:获取GPS信息。

Safari浏览器的控件和原生 UIWebView不兼容,在ios8版本之后提供了WKWebView对象,提供了4个属性、8个api供js调用:

 

loading:是否处于加载中,

canGoBack:只读,是否可以接受后退

canGoForward: 只读,是否可接受向前

request: url 请求

 

loadData: 设置主页类型,MIME类型,文档编码,base url 。

loadRequest: 加载网络资源

loadHTMLString: 加载本地 html 资源

stopLoading: 停止加载

goBack: 后退

goForward:  前进

reload: 重新加载

stringByEvaluatingJavaScriptFromString: 执行一段 js 脚本,并返回执行结果。

 

2   IOS 系统

Native 调用 JavaScript的方法 (object-c swift)

是获取 stringByEvaluatingJavaScriptFromString 方法执行的放回结果。

// Swift
webview.stringByEvaluatingJavaScriptFromString("Math.random()")
// OC
[webView stringByEvaluatingJavaScriptFromString:@"Math.random();"];

以上例子的函数都是相当于在 window 下的方法,所以如果js的方法放在 window 下是可以被 webview的接口调用的。

类似: 

"Math.random()"

 

 

JS 调用 Native 方法

native没有现成的api给js调用,可以通过发送网络请求的方式,在 native 层得到通知。

UIWebView 层内发起网络请求,格式是这样的,例如 object-c 和 swift

jsbridge://methodName?param1=value1&param2=value2    // js 调用原生的一般传参格式。

所以,在UIWebView层如果看到这样的schema就进行逻辑处理,不进行网络请求。

发起这种网络请求的方式,h5可以用 location.href 和 iframe 的方式。

location.href 会有点问题  连续发送多个请求时,在 Native 层只能接收到最后一次的调用。

所以使用 iframe发送请求。

var url = 'jsbridge://doAction?title=标题'; // 定义请求的url,设置好对终端有效的schema。方便拦截。
var iframe = document.createElement('iframe');
iframe.style.width = '1px';
iframe.style.height = '1px';
iframe.style.display = 'none';
iframe.src = url;
document.body.appendChild(iframe); // 将iframe添加到document,发起请求
setTimeout(function() {
    iframe.remove();  // 只需要一次请求,所以需要把 iframe 标签从HTML文档中移除。
}, 100);

WebView 可以拦截这个请求并获取对应的参数,参考如下代码

func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
        print("shouldStartLoadWithRequest")  // 开始处理这个请求
        let url = request.URL
        let scheme = url?.scheme
        let method = url?.host   // 获取host值,判断执行的动作,交给 Object-c 处理。
        let query = url?.query   // 获取执行的传参

        if url != nil && scheme == "jsbridge" {
            print("scheme == \(scheme)")
            print("method == \(method)")
            print("query == \(query)")

            switch method! {
                case "getData":
                    self.getData()
                case "putData":
                    self.putData()
                case "gotoWebview":
                    self.gotoWebview()
                case "gotoNative":
                    self.gotoNative()
                case "doAction":
                    self.doAction()
                case "configNative":
                    self.configNative()
                default:
                    print("default")
            }
            return false;
        } else {
            return true;
        }
    }

 

3   Android 系统

js 调用 native 的方式

在 Android 系统中有 2 种方式可以实现,js调用 native方法。好像还有第3中,重写console.log方法不明觉厉中。。

方法一:

通过schema方式,使用shouldOverrideUrlLoading方法对url协议进行解析。这种js的调用方式与ios的一样,使用iframe来调用native代码。

 

方法二:

使用原生webview提供的接口,addJavaScriptInterface 方法来实现。

class JSInterface {
    @JavascriptInterface           //注意这个代码一定要加上,Java 代码对类型方法的修饰。
    public String getUserData() {
        return "---- native 定义的方法";
    }
}

webView.addJavascriptInterface(new JSInterface(), "AndroidJS");复制代码上面的代码就是在页面的window对象里注入了AndroidJS对象。在js里可以直接调用

console.log(AndroidJS.getUserData()) // ---- native 定义的方法  JSInterface 接口的方法。 对应在 Android WebView 方法中定义的被修饰后的方法。

 

native 调用 js 的方式

webView.loadUrl("javascript:Bridge.doSomething('hello.')");

调用 JavaScript 中的 Bridge.doSomething() 方法。

 

 

4  库的封装

js  调用 native 的封装

基于之前对 IOS 和Android 和js通信的了解,再封装一层,保证js代码操作系统兼容性。 https://juejin.im/post/599a58f6f265da247b4e756b  这段代码来自掘金的文章。

我再整理下逻辑并注释。^_^

HaveJsBridge = {
    doCall: function(functionName, data, callback) {
        var _this = this;
        // 这里其实是一个节流,不让你点太快或响应太快
        if (this.lastCallTime && (Date.now() - this.lastCallTime) < 100) {
            setTimeout(function() {
                _this.doCall(functionName, data, callback);
            }, 100);
            return;
        }
        this.lastCallTime = Date.now();

        data = data || {};
        if (callback) {
            $.extend(data, { callback: callback });
        }

        if (UA.isIOS()) {
            $.each(data, function(key, value) {  // 每个 data key value 进行序列化
                if ($.isPlainObject(value) || $.isArray(value)) {
                    data[key] = JSON.stringify(value);
                }
            });
            var url = Args.addParameter('jsbridge://' + functionName, data);
            var iframe = document.createElement('iframe');
            iframe.style.width = '1px';
            iframe.style.height = '1px';
            iframe.style.display = 'none';
            iframe.src = url;
            document.body.appendChild(iframe);
            setTimeout(function() {
                iframe.remove();   //  和上面的代码执行一样,清除dom
            }, 100);
        } else if (UA.isAndroid()) {
// 此处对接上面👆代码中的 webView.addJavascriptInterface 接口方法 window.androidJS
&& window.androidJS[functionName] && window.androidJS[functionName](JSON.stringify(data)); } else { console.error('未获取platform信息,调取api失败'); } } }

好,兼容性准备工作就绪,现在开始封装几个 常用的 js可以调用 native 的方法。

!!这几个方法都对应上面的 func  webView 函数 👆!!

1  getData(datatype, callback, extra) H5从Native APP获取数据 

JSBridge.getData('userInfo',function(data) {
    console.log(data);
});

 

2  putData(datatype, data) H5告诉Native APP一些数据

JSBridge.putData('userInfo', { username: 'zhangsan', age: 20 });

 

3   gotoWebview(url, page, data)  打开相应网页传参,打开新的webview 窗口,可以再 webView函数中调用

JSBridge.gotoWebview('http://www.youzan.com', 'goodsDetail', {
    goods_id: 10000,
    title: '这是商品的标题',
    desc: '这是商品的描述'
});

 

4  打开某个原生 Native APP 的页面

JSBridge.gotoNative('loginPage', {
    username: '张三'
});

 

5  做一些操作

// 封装一个复制函数,比如点击复制
JSBridge.doAction('copy', {
    content: '这是要复制的内容'
});

// 封装一个分享函数,比如点击分享到 哪哪哪。
JSBridge.doAction('share', {
    title: '分享标题',
    desc: '分享描述',
    link: 'http://www.youzan.com',
    imgs_url: 'http://wap.koudaitong.com/v2/common/url/create?type=homepage&index%2Findex=&kdt_id=63077&alias=63077'
});


// 注意,这些代码还只是方法的伪代码实现不要当真。

 

 

5    Safari 上的调试

第一步: 首先需要打开Safari的调试模式,在Safari的菜单中,选择“Safari”→“Preference”→“Advanced”,勾选上“Show Develop menu in menu bar”选项

第二步: 打开iPhone模拟器的调试模式,在真机或iPhone模拟器中打开设置界面,选择“Safari”→“高级”→“Web检查器”,选择开启

第三步: 将真机通过USB连上电脑,或者开启模拟器,Safari的“Develop”菜单下便会多出相应的菜单项

第四步: Safari连接上UIWebView之后,我们就可以直接在Safari中直接修改HTML、CSS,以及调试Javascript

什么是 UIWebView 启动呢?

这个是Android开发需要Java环境,起一个Android的项目,在手机或模拟器上安装这个项目,就跑起来了。

 

6  参考文档

UIWebView  https://developer.apple.com/documentation/uikit/uiwebview

WKWebView  

Github JSBridge    https://github.com/marcuswestin/WebViewJavascriptBridge

搭建简单webview调试    https://www.jianshu.com/p/4f783cd34ab1

 

posted @ 2019-09-29 17:06  kimoon  阅读(2490)  评论(0编辑  收藏  举报