Hybrid APP基础篇(三)->Hybrid APP之Native和H5页面交互原理

本文已经不维护,新地址:

http://www.cnblogs.com/dailc/p/8097598.htmljavascript

说明

Hybrid模式原生和H5交互原理html

目录

前言

参考来源

前人栽树,后台乘凉,本文参考了如下来源java

前置技术要求

阅读本文前,建议先阅读如下文章web

楔子

Hybrid APP的关键是原生页面与H5页面直接的交互,本文作简单介绍api

Android、iOS原生和H5的基本通讯机制

在Hybrid APP中,原生与H5的交互方式在Android和iOS上的实现是有异同的,缘由是Android、iOS的通讯机制有所区别,下面介绍原生和H5相互调用的方法安全

Android端

Native调JS

4.4版本以前架构

// mWebView = new WebView(this); //即当前webview对象			
mWebView.loadUrl("javascript: 方法名('参数,须要转为字符串')"); 

//ui线程中运行
 runOnUiThread(new Runnable() {  
        @Override  
        public void run() {  
            mWebView.loadUrl("javascript: 方法名('参数,须要转为字符串')");  
            Toast.makeText(Activity名.this, "调用方法...", Toast.LENGTH_SHORT).show();  
        }  
});  
			

4.4之后(包括4.4)app

//异步执行JS代码,并获取返回值	
mWebView.evaluateJavascript("javascript: 方法名('参数,须要转为字符串')", new ValueCallback() {
        @Override
        public void onReceiveValue(String value) {
    		//这里的value即为对应JS方法的返回值
        }
});
			

如上所示,Native用H5页面中的JS方法,有以下特色异步

  • 4.4以前Native经过loadUrl来调用JS方法,只能让某个JS方法执行,可是没法获取该方法的返回值
  • 4.4以后,经过evaluateJavascript异步调用JS方法,而且能在onReceiveValue中拿到返回值
  • 不适合传输大量数据(大量数据建议用接口方式获取)
  • mWebView.loadUrl("javascript: 方法名('参数,须要转为字符串')");函数需在UI线程运行,由于mWebView为UI控件(可是有一个坏处是会阻塞UI线程)

JS调Native

 WebSettings webSettings = mWebView.getSettings();  
 //Android容器容许JS脚本,必需要
webSettings.setJavaScriptEnabled(true);
//Android容器设置侨连对象
mWebView.addJavascriptInterface(getJSBridge(), "JSBridge");
			

Android中JSBridge的代码ide

//Android4.2版本以上,本地方法要加上注解@JavascriptInterface,不然会找不到方法。
private Object getJSBridge(){  
    Object insertObj = new Object(){  
    	@JavascriptInterface
        public String foo(){  
            return "foo";  
        }  
        
        @JavascriptInterface
        public String foo2(final String param){  
            return "foo2:" + param;  
        }  
          
    };  
    return insertObj;  
}  
			

Html中JS调用原生的代码

//调用方法一
window.JSBridge.foo(); //返回:'foo'
//调用方法二
window.JSBridge.foo2('test');//返回:'foo2:test'
			

如上所示,Native中经过addJavascriptInterface添加暴露出来的JS桥对象,而后再该对象内部声明对应的API方法,有以下特色:

  • 在Android4.2以上(api17后),暴露的api要加上注解@JavascriptInterface,不然会找不到方法。
  • 在api17之前,addJavascriptInterface有风险,hacker能够经过反编译获取Native注册的Js对象,而后在页面经过反射Java的内置 静态类,获取一些敏感的信息和破坏

    因此,也就是为何Android中也会使用JSBridge来进行交互,而不是addJavascriptInterface直接暴露api

  • JS能调用到已经暴露的api,而且能获得相应返回值

iOS端

Native调JS

//能够取得JS函数执行的返回值
//方法必须是Html页面绑定在最顶层的window上对象的
//如window.top.foo
//Swift
webview.stringByEvaluatingJavaScriptFromString("方法名(参数)")
//OC
[webView stringByEvaluatingJavaScriptFromString:@"方法名(参数);"];
			

如上所示,Native经过stringByEvaluatingJavaScriptFromString调用Html绑定在window上的函数,有以下特色

  • Native调用JS方法时,能拿到JS方法的返回值
  • 不适合传输大量数据(大量数据建议用接口方式获取)

JS调Native

引入官方的库文件

#import <JavaScriptCore/JavaScriptCore.h>

Native注册api函数(OC)

//webview加载完毕后设置一些js接口
-(void)webViewDidFinishLoad:(UIWebView *)webView{
    [self hideProgress];
    [self setJSInterface];
}

-(void)setJSInterface{
    
    JSContext *context =[_wv valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    
    // 注册名为foo的api方法
    context[@"foo"] = ^() {
    	
    	//获取参数
        NSArray *args = [JSContext currentArguments];
        NSString *title = [NSString stringWithFormat:@"%@",[args objectAtIndex:0]];
        //作一些本身的逻辑
        //返回一个值  'foo:'+title
        return [NSString stringWithFormat:@"foo:%@", title];
    };
    

    
}				
			

Html中JS调用原生的代码

//调用方法,用top是确保调用到最顶级,由于iframe要用top才能拿到顶级
window.top.foo('test'); //返回:'foo:test'
			

如上所示,Native中经过引入官方提供的JavaScriptCore库(iOS7中出现的),而后能够将api绑定到JSContext上(而后Html中JS默认经过window.top.***可调用)。有以下特色

  • iOS7才出现这种方式,在这以前,js没法直接调用Native,只能经过JSBridge方式简介调用
  • JS能调用到已经暴露的api,而且能获得相应返回值
  • iOS原生自己是没法被JS调用的,可是经过引入官方提供的第三方"JavaScriptCore",便可开放api给JS调用

原生和H5的另外一种通信方式:JSBridge

实际上,Native与H5通讯,除了前面提到的用基本方法外,还有一种广为流行的方法:JSBridge

什么是JSBridge

JSBridge是广为流行的Hybrid开发中JS和Native一种通讯方式,各大公司的应用中都有用到这种方法

简单的说,JSBridge就是定义Native和JS的通讯,Native只经过一个固定的桥对象调用JS,JS也只经过固定的桥对象调用Native,基本原理是:

H5->经过某种方式触发一个url->Native捕获到url,进行分析->原生作处理->Native调用H5的JSBridge对象传递回调。以下图

上图简单的介绍了下JSBridge的核心原理,具体详细实现请参考后面详解。

为何要用JSBridge

在上文中咱们有提到Native和原生之间的基本通讯,既然Native和原生已经可以实现通讯了,那为何还要这种经过url scheme的JSBridge方式呢,缘由大体以下

  • Android4.2如下,addJavascriptInterface方式有安全漏掉
  • iOS7如下,JS没法调用Native
  • url scheme交互方式是一套现有的成熟方案,能够完美兼容各类版本,不存在上述问题

另外,请注意,能够理解为JSBridge是一种交互理念,而上述的url scheme则是其中的一种实现,因此也就是说,就算后面实现变为了addJavascriptInterface,JavaScriptCore,也同样是JSBridge交互

JSBridge交互的一个很大特色就是便于拓展,并且没有重大的安全性问题,因此也就是为何它广为流行

JSBridge原理以及实现

JSBridge的原理和实现请参考 JSBridge实现原理