混合开发的优势:

使用H5实现的功能能够在不升级App的情况下动态更新,而且可以在Android或iOS的App上同时运行,节约了成本,提高了开发效率。
原理:其实就是Java代码和JavaScript之间的调用。

H5调原生方式:

第一种

1.首先对WebView进行初始化

WebSettings settings = webview.getSettings();
settings.setJavaScriptEnabled(true); //允许在WebView中使用js

2.创建一个类JavaScriptMetod,专门用来给js提供可调用的方法

3.创建该类的构造方法,提供两个参数,WebView对象和上下文对象

private Context mContext; 
 private WebView mWebView; 
 public JavaScriptMethod(Context context, WebView webView) { 
 mContext = context; 
 mWebView = webView; 
 }

4.创建一个字符串常量,作为android与js通信的接口,即字符串映射对象

public static final String JAVAINTERFACE = “javaInterface”;

5.接下来就是创建给js调用的方法,方法的参数接收一个json字符串(注意:在Android4.2之后,为了提高代码安全性,方法必须使用注解@JavascriptInterface,否则无法调用)

@JavascriptInterface 
 //andorid4.2(包括android4.2)以上,如果不写该注解,js无法调用android方法 
 public void showToast(String json){ 
 Toast.makeText(context, json, Toast.LENGTH_SHORT).show(); 
 }

6.在WebView初始化代码中执行如下代码,

//创建上面创建类的对象 
 JavaScriptMetod m = new JavaScriptMetod(this, webview); 
 //其实就是告诉js,我提供给哪个对象给你调用,这样js就可以调用对象里面的方法 
 //第二个参数就是该类中的字符串常量 
 webview.addJavascriptInterface(m, JavaScriptMetod.javaInterface);

现在,在js中就可以调用JavaScriptMetod中的方法了,调用方式如下

//参数一般为json格式 
 var json = {“name”:”javascript”}; 
 //javaInterface是上面所说的字符串映射对象 
 window.javaInterface.showToast(JSON.stringify(json));

网络上介绍js与android原生交互的文章里,大部分都是上面这种方式,但是这种方式并不适用于ios,也就是说,window.javaInterface.showToast(JSON.stringify(json))这样的js代码并不适用于ios,如果用以上的方法,就得分别为android和ios各写一套js代码。这样很显然是不太合理的,所以在实际开发中,一般都使用接下来的第二种方法。

第二种

这种方法实现的思想是js发出一个url请求,并将所需的参数添加到该url中。android端通过webView.setWebViewClient()拦截url,解析url中携带的参数,并根据参数信息进行相应的操作。

1.与方法一相同,首先都需要对webview进行初始化

WebSettings settings = webview.getSettings();
settings.setJavaScriptEnabled(true); //允许在WebView中使用js

2.首先看js中的代码是怎么写的,

$(“#showtoast”).click(function () { 
 var json = {“data”: “I am a toast”}; 
 window.location.href=”protocol://android?code=toast&data=”+JSON.stringify(json); 
 });$("#call").click(function () {
    var json = {"data": "10086"};
   window.location.href="protocol://android?code=call&data="+JSON.stringify(json);
});

这里定义两个点击事件,分别控制android显示吐司和打电话的操作。其中,protocol://android为自定义的H5与android间的通信协议,与http请求进行区分。code规定了要进行的操作,data为传输的数据。

2.android中的代码

webView.setWebViewClient(new WebViewClient() { 
 @Override 
 public boolean shouldOverrideUrlLoading(WebView view, String url) { 
 /** 
 * 通过判断拦截到的url是否含有pre,来辨别是http请求还是调用android方法的请求 
 */ 
 String pre = “protocol://android”; 
 if (!url.contains(pre)) { 
 //该url是http请求,用webview加载url 
 return false; 
 } 
 //该url是调用android方法的请求,通过解析url中的参数来执行相应方法 
 Map

原生调H5方式:

  1. 首先是JS的一段代码:
1. function javaCallJs(arg){ 
 document.getElementById(“content”).innerHTML = 
 (“欢迎:”+arg ); 
 }
  1. 然后是在java中调用JS中的方法
webView.loadUrl(“javascript:javaCallJs(“+”’”+name+”’”+”)”);

  1. 以上代码就是调用了JS中一个叫javaCallJs(arg)的方法,并传入了一个name参数。(具体效果下面有展示)

#
#
其他一些常见问题:

  1. WebViewClient.onPageFinished()。
    你永远无法确定当WebView调用这个方法的时候,网页内容是否真的加载完毕了。当前正在加载的网页产生跳转的时候这个方法可能会被多次调用,StackOverflow上有比较具体的解释(How to listen for a Webview finishing loading a URL in Android?), 但其中列举的解决方法并不完美。所以当你的WebView需要加载各种各样的网页并且需要在页面加载完成时采取一些操作的话,可能WebChromeClient.onProgressChanged()比WebViewClient.onPageFinished()都要靠谱一些。
  2. WebView后台耗电问题。
    当你的程序调用了WebView加载网页,WebView会自己开启一些线程(?),如果你没有正确地将WebView销毁的话,这些残余的线程(?)会一直在后台运行,由此导致你的应用程序耗电量居高不下。对此我采用的处理方式比较偷懒,简单又粗暴(不建议),即在Activity.onDestroy()中直接调用System.exit(0),使得应用程序完全被移出虚拟机,这样就不会有任何问题了。
  3. 切换WebView闪屏问题。
    如果你需要在同一个ViewGroup中来回切换不同的WebView(包含了不同的网页内容)的话,你就会发现闪屏是不可避免的。这应该是Android硬件加速的Bug,如果关闭硬件加速这种情况会好很多,但无法获得很好的浏览体验,你会感觉网页滑动的时候一卡一卡的,不跟手。
  4. 在某些手机上,Webview有视频时,activity销毁后,视频资源没有被销毁,甚至还能听到在后台播放。即便是像刚才那样各种销毁webview也无济于事,解决办法:在onDestory之前修改url为空地址。

5.WebView硬件加速导致页面渲染闪烁问题
关于Android硬件加速 开始于Android 3.0 (API level 11),开启硬件加速后,WebView渲染页面更加快速,拖动也更加顺滑。但有个副作用就是容易会出现页面加载白块同时界面闪烁现象。解决这个问题的方法是设置WebView暂时关闭硬件加速 代码如下:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 
 webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null); 
 }