Android 利用WebViewJavascriptBridge 实现js和java的交互(一)

Android 利用WebViewJavascriptBridge 实现js和java的交互(一)nbsp nbsp nbsp 此文出自 http blog csdn net sk article details skay nbsp 按 Android 开发目前现状来说 开发者大部分时间还是花在 UI 的屏幕适配上 使用原生控件开发成本已不是那么理想 鉴于很多项目和 ios 基于一致的 ui 界面 至使安卓 UI 开发成本花费更大的代价 因此目前结合 Html5 和原生控件是解决 UI 适配的一种很好的

      此文出自:http://blog.csdn.net/sk/article/details/,skay

 按Android 开发目前现状来说,开发者大部分时间还是花在UI的屏幕适配上,使用原生控件开发成本已不是那么理想,鉴于很多项目和ios基于一致的ui界面,至使安卓UI开发成本花费更大的代价,因此目前结合Html5和原生控件是解决UI适配的一种很好的选择,处于APP性能也会用java和native层进行结合。不管是哪种结合,其实原理都差不多,只要按照它的协议来,是很容易的,今天我们仅对于Html和Java层结合,学习下WebViewJavascriptBridge。

已经熟悉了jsbridge的朋友直接移步:

《Android基于JsBridge封装的高效带加载进度的WebView》:http://blog.csdn.net/sk/article/details/

 

一 什么是webViewjavascripBridge?

 WebViewJavascriptBridge是移动UIView和Html交互通信的桥梁,用作者的话来说就是实现java(ios为oc)和js的互相调用的桥梁。替代了WebView的自带的JavascriptInterface的接口,使得我们的开发更加灵活和安全。

 

 二 为什么要用webViewjavascripBridge?

     

  对于安卓开发有一段时间的人来说,知道安卓4.4以前谷歌的webview存在安全漏洞,网站可以通过js注入就可以随便拿到客户端的重要信息,甚至轻而易举的调用本地代码进行流氓行为,谷歌后来发现有此漏洞后,增加了防御措施,如果要是js调用本地代码,开发者必须在代码申明JavascriptInterface,

  列如在4.0之前我们要使得webView加载js只需如下代码:

mWebView.addJavascriptInterface(new JsToJava(), "myjsfunction"); 

 

     4.4之后调用需要在调用方法加入加入@JavascriptInterface注解,如果代码无此申明,那么也就无法使得js生效,也就是说这样就可以避免恶意网页利用js对安卓客户端的窃取和攻击。

        但是即使这样,我们很多时候需要在js记载本地代码的时候,要做一些判断和限制,或者有可能也会做些过滤和对用户友好提示,因此JavascriptInterface也就无法满足我们的需求了,特此有大头鬼就写出了WebViewJavascriptBridge框架。

    

三 怎么使用webViewjavascripBridge

 

   1 将jsBridge.jar引入到我们的工程

          Eclispe

         

           导入jar包, 或者直接copyjar源码, jar可以到gitHub上下载。

 

        Android Studio: 

             

repositories { // ... maven { url "https://jitpack.io" } } dependencies { compile 'com.github.lzyzsd:jsbridge:1.0.4' }

 

     2 WebView包需使用以上包的webView

 

              Layout中使用第三方webView

       EG:

             

 
   
   
    
    
    
    
    
  

  3 Java代码

      1 activity

public class MainActivity extends Activity implements OnClickListener { private final String TAG = "MainActivity"; BridgeWebView webView; Button button; int RESULT_CODE = 0; ValueCallback 
  
    mUploadMessage; static class Location { String address; } static class User { String name; Location location; String testStr; } @Override protected void onCreate(Bundle savedInstanceState) { 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(new DefaultHandler()); webView.setWebChromeClient(new WebChromeClient() { @SuppressWarnings("unused") public void openFileChooser(ValueCallback 
   
     uploadMsg, String AcceptType, String capture) { this.openFileChooser(uploadMsg); } @SuppressWarnings("unused") public void openFileChooser(ValueCallback 
    
      uploadMsg, String AcceptType) { this.openFileChooser(uploadMsg); } public void openFileChooser(ValueCallback 
     
       uploadMsg) { mUploadMessage = uploadMsg; pickFile(); } }); //加载本地网页 //webView.loadUrl("file:///android_asset/demo.html"); //加载服务器网页 webView.loadUrl("https://www.baidu.com"); //必须和js同名函数,注册具体执行函数,类似java实现类。 webView.registerHandler("submitFromWeb", new BridgeHandler() { @Override public void handler(String data, CallBackFunction function) { String str ="这是html返回给java的数据:" + data; // 例如你可以对原始数据进行处理 makeText(MainActivity.this, str, LENGTH_SHORT).show(); Log.i(TAG, "handler = submitFromWeb, data from web = " + data); function.onCallBack( str + ",Java经过处理后截取了一部分:"+ str.substring(0,5)); } }); //模拟用户获取本地位置 User user = new User(); Location location = new Location(); location.address = "上海"; user.location = location; user.name = "Bruce"; webView.callHandler("functionInJs", new Gson().toJson(user), new CallBackFunction() { @Override public void onCallBack(String data) { makeText(MainActivity.this, "网页在获取你的位置", LENGTH_SHORT).show(); } }); webView.send("hello"); } public void pickFile() { Intent chooserIntent = new Intent(Intent.ACTION_GET_CONTENT); chooserIntent.setType("image/*"); startActivityForResult(chooserIntent, RESULT_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { if (requestCode == RESULT_CODE) { if (null == mUploadMessage){ return; } Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData(); mUploadMessage.onReceiveValue(result); mUploadMessage = null; } } @Override public void onClick(View v) { if (button.equals(v)) { webView.callHandler("functionInJs", "data from Java", new CallBackFunction() { @Override public void onCallBack(String data) { // TODO Auto-generated method stub Log.i(TAG, "reponse data from js " + data); } }); } } } 
      
     
    
  

2 自定webVIewClient

 

class MyWebViewClient extends BridgeWebViewClient{ public MyWebViewClient(BridgeWebView webView) { super(webView); } }

 

   将自定义webViewClient设置到webview上    

 mWebView.setWebViewClient(new MyWebViewClient(mWebView));

      

      通过实例化webView,用法和安卓原生的view没多大区别,设置WebChromClient, 设置加载的html(同样支持网络和本地文件),接着我们需要给web注册和html端约定好的js方法名。代码列举的submitFromweb和js的执行的方法名一致,玩过NDK的JNI调用的朋友也知道必须和c代码之间有个约定,其实js桥和jni有点类似,

 

通过注册handler来实现回调,Java代码中通过js返回的数据,进行处理后在调用function.onCallback返回给js.这里不做过多解释

 

//必须和js函数同名,注册具体执行回调函数,类似java实现类。
		webView.registerHandler("submitFromWeb", new BridgeHandler() {

			@Override
			public void handler(String data, CallBackFunction function) {

				String str ="这是html返回给java的数据:" + data;
				// 例如你可以对原始数据进行处理
				makeText(MainActivity.this, str, LENGTH_SHORT).show();

				Log.i(TAG, "handler = submitFromWeb, data from web = " + data);
                function.onCallBack( str + ",Java经过处理后截取了一部分:"+ str.substring(0,5));
			}

		});

      

 webView.callHandler("functionInJs", new Gson().toJson(user), new CallBackFunction() { @Override public void onCallBack(String data) { makeText(MainActivity.this, "网页在获取你的位置", LENGTH_SHORT).show(); } });

 

  3 Html和js实现

         html代码如下,效果图

 

 

    Android 利用WebViewJavascriptBridge 实现js和java的交互(一)

 
   
    js调用java  
   

 

  js代码

 

    

 

 

      这段代码不难理解,我们对上面的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", new BridgeHandler() {

			@Override
			public void handler(String data, CallBackFunction function) {

				String str ="这是html返回给java的数据:" + data;
				// 例如你可以对原始数据进行处理
				makeText(MainActivity.this, str, LENGTH_SHORT).show();

				Log.i(TAG, "handler = submitFromWeb, data from web = " + 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('JS got a message', message); var data = { 'Javascript Responds': 'Wee!' }; console.log('JS responding with', data); responseCallback(data); }); bridge.registerHandler("functionInJs", function(data, responseCallback) { document.getElementById("show").innerHTML = ("data from Java: = " + data); var responseData = "Javascript Says Right back aka!"; responseCallback(responseData); }); })

 

 

四 总结

     

通过以上的API介绍,代码示例,不难发现此框架的优雅和简便,对js和java双方来说,如果Html中的js需要调用java代码,而java代码没做任何实现,那么js中方法也是无效的,反之java代码注册的函数,没在js里去回调实现,那么Java层也是无法获取js中数据的,由此可见,此通信是双方支持的,必须由双方来约定,这样就避免了Android之前存在的js注入漏洞,也很大的提高了安全性,也可以保证我们的网页数据不被第三方的APP获取,具体来讲,列如我们的项目某一个web的h5界面,被系统浏览器或者其他第三方App的恶意加载,那么它的java代码想调用你的js函数,实现需要你的H5的Js先注册,不然跟本无法调用你的h5信息。这样保证了这个html数据的安全性,,第三方的浏览器可以加载预览你的网页,但是第三方java无法和你的的h5中的js交互通信的。同样加载我们自己的APP加载第三方的网页时候,我们可以对第三方网页进行一些行为的过滤,方便保护我们手机的安全,列如第三方可以获取本机地址时我们可以提示用户授权。虽然H5并不属于插件的一种,但是借助h5我可以方便的去更新一些运营活动,和某些需要经常需要更换UI的业务功能的地方,以上只JSBridge的使用姿势,,以后再给大家解剖下JsBridge的内部实现。

 

jsbridage的封装请参考:

项目实例:https://github.com/Tamicer/JsBridge_Android

 

更多文章请关注本人微信公众号:请扫原文地址的左侧二维码

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/226641.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月16日 下午10:27
下一篇 2026年3月16日 下午10:28


相关推荐

  • html中颜色的编码,css颜色编码对照表[通俗易懂]

    html中颜色的编码,css颜色编码对照表[通俗易懂]css颜色编码对照表2018-09-14颜色名十六进制值RGB值PearlyGates#FFFFF2#fffff2PaleOlive#FBF5E6#fbf5e6white#FFFFFF#ffffffFrostedLime#F6F9ED#f6f9edWhiteOrchid#FDFDF0#fdfdf0GreenVeil#EEF3E2#eef3e2GrayClif…

    2022年5月17日
    62
  • CSS3选择器详解

    CSS3选择器详解一、CSS3选择器分类1.基本选择器2.层次选择器3.伪类选择器1)动态伪类选择器2)目标伪类选择器3)语言伪类选择器4)UI元素状态伪类选择器5)结构伪类选择器6)否定伪类选择器4.伪元素5.属性选择器二、基本选择器语法这里着重说一下群组选择器(selector1,selector2,…,selec

    2022年7月27日
    7
  • 适配器模式详解

    适配器模式详解适配器模式,显而易见,灵感来源于笔记本电脑一类的适配器 模式动机 在软件开发中采用类似于电源适配器的设计和编码技巧被称为适配器模式。 通常情况下,客户端可以通过目标类的接口访问它所提供的服务。有时,现有的类可以满足客户类的功能需要,但是它所提供的接口不一定是客户类所期望的,这可能是因为现有类中方法名与目标类中定义的方法名不一致等原因所导致的。 在这…

    2022年7月25日
    10
  • 剑指Offer面试题:1.实现单例模式建议收藏

    一题目:实现单例模式Singleton只能生成一个实例的类是实现了Singleton(单例)模式的类型。由于设计模式在面向对象程序设计中起着举足轻重的作用,在面试过程中很多公司都喜欢问一些与设计模

    2021年12月19日
    45
  • 「月花上千,钱包被掏空」第一批「养虾人」开始疯狂卸载,「拆虾」服务已爆单

    「月花上千,钱包被掏空」第一批「养虾人」开始疯狂卸载,「拆虾」服务已爆单

    2026年3月14日
    2
  • handlerInvocation的invoke方法

    handlerInvocation的invoke方法java.lang.reflect.Proxy类的newProxyInstance(),是用于创建动态代理类和实例的静态方法.返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。java.lang.reflect.InvocationHandler接口中的invoke(),在代理实例上处理方法调用并返回结果。当与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法…

    2022年5月12日
    51

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号