转自:http://blog.youkuaiyun.com/sk719887916/article/details/47189607
按安卓开发目前现状来说,开发者大部分时间还是花在UI的屏幕适配上,使用原生控件开发成本已不是那么理想,鉴于很多项目和iOS基于一致的ui界面,至使安卓UI开发成本花费更大的代价,因此目前结合Html5和原生控件是解决UI适配的一种很好的选择,处于APP性能也会用Java和native层进行结合。不管是哪种结合,其实原理都差不多,只要按照它的协议来,是很容易的,今天我们仅对于Html和Java层结合,学习下一个新的开源项目--WebViewJavascriptBridge。
一 什么是webViewjavascripBridge?
WebViewJavascriptBridge是移动UIView和Html交互通信的桥梁,用作者的话来说就是实现java(ios为oc)和js的互相调用的桥梁。替代了WebView的自带的JavascriptInterface的接口,使得我们的开发更加灵活和安全。
二 为什么要用webViewjavascripBridge?
- mWebView.addJavascriptInterface(newJsToJava(),"myjsfunction");
4.4之后调用需要在调用方法加入加入@JavascriptInterface注解,如果代码无此申明,那么也就无法使得js生效,也就是说这样就可以避免恶意网页利用js对安卓客户端的窃取和攻击。
但是即使这样,我们很多时候需要在js记载本地代码的时候,要做一些判断和限制,或者有可能也会做些过滤和对用户友好提示,因此JavascriptInterface也就无法满足我们的需求了,特此有大神就写出了WebViewJavascriptBridge框架。
三 怎么使用webViewjavascripBridge
1 将jsBridge.jar引入到我们的工程
2 WebView包需使用以上包的webView
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <!--button演示Java调用web-->
- <Button
- android:id="@+id/button"
- android:layout_width="match_parent"
- android:text="@string/button_name"
- android:layout_height="48dp"
- />
- <!--webview演示web调用Java-->
- <com.github.lzyzsd.jsbridge.BridgeWebView
- android:id="@+id/webView"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- </com.github.lzyzsd.jsbridge.BridgeWebView>
- </LinearLayout>
3 Java代码
- publicclassMainActivityextendsActivityimplementsOnClickListener{
- privatefinalStringTAG="MainActivity";
- BridgeWebViewwebView;
- Buttonbutton;
- intRESULT_CODE=0;
- ValueCallback<Uri>mUploadMessage;
- staticclassLocation{
- Stringaddress;
- }
- staticclassUser{
- Stringname;
- Locationlocation;
- StringtestStr;
- }
- @Override
- protectedvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- webView=(BridgeWebView)findViewById(R.id.webView);
- button=(Button)findViewById(R.id.button);
- button.setOnClickListener(this);
- webView.setDefaultHandler(newDefaultHandler());
- webView.setWebChromeClient(newWebChromeClient(){
- @SuppressWarnings("unused")
- publicvoidopenFileChooser(ValueCallback<Uri>uploadMsg,StringAcceptType,Stringcapture){
- this.openFileChooser(uploadMsg);
- }
- @SuppressWarnings("unused")
- publicvoidopenFileChooser(ValueCallback<Uri>uploadMsg,StringAcceptType){
- this.openFileChooser(uploadMsg);
- }
- publicvoidopenFileChooser(ValueCallback<Uri>uploadMsg){
- mUploadMessage=uploadMsg;
- pickFile();
- }
- });
- //加载本地网页
- //webView.loadUrl("file:///android_asset/demo.html");
- //加载服务器网页
- webView.loadUrl("https://www.baidu.com");
- //必须和js同名函数,注册具体执行函数,类似java实现类。
- webView.registerHandler("submitFromWeb",newBridgeHandler(){
- @Override
- publicvoidhandler(Stringdata,CallBackFunctionfunction){
- Stringstr="这是html返回给java的数据:"+data;
- //例如你可以对原始数据进行处理
- makeText(MainActivity.this,str,LENGTH_SHORT).show();
- Log.i(TAG,"handler=submitFromWeb,datafromweb="+data);
- function.onCallBack(str+",Java经过处理后截取了一部分:"+str.substring(0,5));
- }
- });
- //模拟用户获取本地位置
- Useruser=newUser();
- Locationlocation=newLocation();
- location.address="上海";
- user.location=location;
- user.name="Bruce";
- webView.callHandler("functionInJs",newGson().toJson(user),newCallBackFunction(){
- @Override
- publicvoidonCallBack(Stringdata){
- makeText(MainActivity.this,"网页在获取你的位置",LENGTH_SHORT).show();
- }
- });
- webView.send("hello");
- }
- publicvoidpickFile(){
- IntentchooserIntent=newIntent(Intent.ACTION_GET_CONTENT);
- chooserIntent.setType("image/*");
- startActivityForResult(chooserIntent,RESULT_CODE);
- }
- @Override
- protectedvoidonActivityResult(intrequestCode,intresultCode,Intentintent){
- if(requestCode==RESULT_CODE){
- if(null==mUploadMessage){
- return;
- }
- Uriresult=intent==null||resultCode!=RESULT_OK?null:intent.getData();
- mUploadMessage.onReceiveValue(result);
- mUploadMessage=null;
- }
- }
- @Override
- publicvoidonClick(Viewv){
- if(button.equals(v)){
- webView.callHandler("functionInJs","datafromJava",newCallBackFunction(){
- @Override
- publicvoidonCallBack(Stringdata){
- //TODOAuto-generatedmethodstub
- Log.i(TAG,"reponsedatafromjs"+data);
- }
- });
- }
- }
- }
- //必须和js同名函数,注册具体执行函数,类似java实现类。
- webView.registerHandler("submitFromWeb",newBridgeHandler(){
- @Override
- publicvoidhandler(Stringdata,CallBackFunctionfunction){
- Stringstr="这是html返回给java的数据:"+data;
- //例如你可以对原始数据进行处理
- makeText(MainActivity.this,str,LENGTH_SHORT).show();
- Log.i(TAG,"handler=submitFromWeb,datafromweb="+data);
- function.onCallBack(str+",Java经过处理后截取了一部分:"+str.substring(0,5));
- }
- });
如果是webview刚开始就执行一段Java代码 ,可以通过webView.CallHandler()来实现 。当然我们注册的方法也要和js里面的方法名一致。
- webView.callHandler("functionInJs",newGson().toJson(user),newCallBackFunction(){
- @Override
- publicvoidonCallBack(Stringdata){
- makeText(MainActivity.this,"网页在获取你的位置",LENGTH_SHORT).show();
- }
- });
3 Html和js实现
html代码如下,效果图
- <html>
- <head>
- <metacontent="text/html;charset=utf-8"http-equiv="content-type">
- <title>
- js调用java
- </title>
- </head>
- <body>
- <p>
- <xmpid="show">
- </xmp>
- </p>
- <p>
- <xmpid="init">
- </xmp>
- </p>
- <p>
- <inputtype="text"id="text1"value="用户名(username)"/>
- </p>
- <p>
- <inputtype="text"id="text2"value="password"/>
- </p>
- <p>
- <inputtype="button"id="enter"value="发消息给Native"onclick="testClick();"
- />
- </p>
- <p>
- <inputtype="button"id="enter1"value="调用Native方法"onclick="testClick1();"
- />
- </p>
- <p>
- <inputtype="button"id="enter2"value="显示html"onclick="testDiv();"/>
- </p>
- <p>
- <inputtype="file"value="打开文件"/>
- </p>
- </body>
- </html>
js代码
- <script>
- functiontestDiv(){
- document.getElementById("show").innerHTML=document.getElementsByTagName("html")[0].innerHTML;
- }
- functiontestClick(){
- varstr1=document.getElementById("text1").value;
- varstr2=document.getElementById("text2").value;
- //发送消息给java代码
- vardata="name="+str1+",pass="+str2;
- window.WebViewJavascriptBridge.send(
- data
- ,function(responseData){
- document.getElementById("show").innerHTML="repsonseDatafromjava,data="+responseData
- }
- );
- }
- functiontestClick1(){
- varstr1=document.getElementById("text1").value;
- varstr2=document.getElementById("text2").value;
- //调用本地java方法
- window.WebViewJavascriptBridge.callHandler(
- 'submitFromWeb'
- ,{'param':str1}
- ,function(responseData){
- document.getElementById("show").innerHTML="sendgetresponseDatafromjava,data="+responseData
- }
- );
- }
- functionbridgeLog(logContent){
- document.getElementById("show").innerHTML=logContent;
- }//注册事件监听
- functionconnectWebViewJavascriptBridge(callback){
- if(window.WebViewJavascriptBridge){
- callback(WebViewJavascriptBridge)
- }else{
- document.addEventListener(
- 'WebViewJavascriptBridgeReady'
- ,function(){
- callback(WebViewJavascriptBridge)
- },
- false
- );
- }
- }
- //注册回调函数,初始化函数
- connectWebViewJavascriptBridge(function(bridge){
- bridge.init(function(message,responseCallback){
- console.log('JSgotamessage',message);
- vardata={
- 'JavascriptResponds':'Wee!'
- };
- console.log('JSrespondingwith',data);
- responseCallback(data);
- });
- bridge.registerHandler("functionInJs",function(data,responseCallback){
- document.getElementById("show").innerHTML=("datafromJava:="+data);
- varresponseData="JavascriptSaysRightbackaka!";
- responseCallback(responseData);
- });
- })
- </script>
这段代码不难理解,我们对上面的id为enter的Button注册了一个点击事件,点击后执行以下testClick()方法,依次类推,其他Button注册事件相同,
当点击“发消息给Native”的按钮时,Js通过webWiew的jsBridage.send()发送一条数据给java层(密码和用户名),同时在此用function()来执行应java层回调函数的。此demo中是把java返回的数据插入到"show"的div里面去。
testClick1():此方法中调用callHandler来调用Java代码的submitFromweb同名函数,可以结合上面的Activty的代码理解下,此函数调用我们已在java注册实现好的
- //必须和js同名函数,注册具体执行函数,类似java实现类。
- webView.registerHandler("submitFromWeb",newBridgeHandler(){
- @Override
- publicvoidhandler(Stringdata,CallBackFunctionfunction){
- Stringstr="这是html返回给java的数据:"+data;
- //例如你可以对原始数据进行处理
- makeText(MainActivity.this,str,LENGTH_SHORT).show();
- Log.i(TAG,"handler=submitFromWeb,datafromweb="+data);
- function.onCallBack(str+",Java经过处理后截取了一部分:"+str.substring(0,5));
- }
- });
java注册Js函数如上面列子 ,那么在js中注册方法来注册呢,
在js中我们同样可以直接注册一个回调函数,通过bridge.registerHandler()来注册,接着调用responseCallback(responseData)来返回数据给java代码的同名函数。f
也可以直接调用init()来指定网页首次加载上面注册java代码。
- connectWebViewJavascriptBridge(function(bridge){
- bridge.init(function(message,responseCallback){
- console.log('JSgotamessage',message);
- vardata={
- 'JavascriptResponds':'Wee!'
- };
- console.log('JSrespondingwith',data);
- responseCallback(data);
- });
- bridge.registerHandler("functionInJs",function(data,responseCallback){
- document.getElementById("show").innerHTML=("datafromJava:="+data);
- varresponseData="JavascriptSaysRightbackaka!";
- responseCallback(responseData);
- });
- })