react-native中安卓webview和js层通讯

前言:

学习rn已经有大半年了,目前的项目是采用rn的,在项目中曾遇到webview中调用postMessage,而后在浏览器和真机中查看,发如今浏览器中会报错,后者不会报错,而后以为很奇怪,所以就去粗略的研究了一下rn中webview的实现。因为webview涉及不少东西,因此这一篇写介绍一下安卓的webview,下篇再继续介绍ios的webview。javascript

介绍:

webview主要是用来进行页面请求,页面加载,页面渲染,页面交互等处理,而安卓对于webview是没有区分UIWebview和WKWebview,而是直接采用webkit内核的wkwebview。html

webview的工具类:

  • websetting:

做用:主要使用来设置和管理webview;java

获取WebSettings实例:android

// 添加访问网络权限(AndroidManifest.xml)  
<uses-permission android:name="android.permission.INTERNET" />
// 建立webview实例 
Webview webview = new WebView(this); 
// 建立webSettings实例 
WebSettings websettings = webview.getSettings();

WebSettings经常使用方法:
image.pngios

  • webviewclient:

做用:处理各类通知 & 请求事件;web

  1. shouldOverrideUrlLoading:该方法主要是在请求url的时候触发该事件,该事件会根据返回值来决定是否拦截url请求;若是返回true则会不让webview处理该url,而是交给系统来自行处理该url的请求,若是返回的是false,则会不作拦截,直接由webview来处理加载url。
  2. onPageStarted:页面资源开始加载,此时能够作一个loading操做。
  3. onPageFinished:页面资源加载结束时触发,此时能够关闭loading操做。
  4. onLoadResource:页面请求或者加载资源时出错会触发。
  • webChromeClient:

做用:辅助 WebView 处理 Javascript 的对话框,网站图标,网站标题等等。chrome

  1. onProgressChanged(WebView view, int newProgress):获取网页的加载进度而且展现出来。
  2. onReceivedTitle(WebView view, String title):获取网页的title。
  3. onJsAlert,onJsConfirm,onJsPrompt:支持js的警告窗,确认窗和输入窗。

js与原生webview的交互:

  • 安卓调用js代码:

1)webview的loadUrl:该方法能够在webview中执行本地资源的加载,远程资源的加载以及js代码的执行。浏览器

调用形式:
webview.loadUrl(远程url);
webview.loadUrl(本地文件);
webview.loadUrl('javascript:js代码'):该形式必须在在onPageFinished以后才能调用,由于要等到资源加载完毕后,才能执行js代码。其中若是要调用html文件内的代码,只能时js代码嵌入到html的script标签之中。安全

// html
<html>
 ...
 <script>
   function toCall() { ... }
 </script>
 ...
 </html>
 
 // webview
 shouldOverrideUrlLoading(Webview webview, String url) { 
        webview.loadUrl(url); 
 }
 onPageFinished(Webview webview) { 
       webview.loadUrl("javascript: tocall()") 
       webview.loadUrl("javascript:console.log('asdf')")
 }

优势:简单;
缺点:对于原生要采用js代码的结果时就会很麻烦,并且效率低,还有调用它来执行js代码会刷新页面;
使用场景:不须要获取返回值且性能要求不高;网络

2)webview的evaluateJavascript:能够直接调用js代码,而且能直接获取js代码中的返回值;

webview.evaluateJavascript("avascript:callJS()", new ValueCallback() {
    @Override 
    public void onReceiveValue(String value) { 
    //此处为 js 返回的结果 
    } 
})

优势:调用简单,且效率高,并且能获取js层的执行结果;
缺点:必需要在安卓4.4以后才能用;
使用场景:在安卓4.4条件下优先使用;

  • js唤起安卓端代码:

1)webview的addJavascriptInterface:主要时将java类的对象和js对象进行映射,从而实现js调用java层代码;

调用形式:webview.addJavascriptInterface(java对象,js对象)

step1:制定特定的java类:

public class ToJs { 
    // 定义JS须要调用的方法 
    // 被JS调用的方法必须加入@JavascriptInterface注解 
    @JavascriptInterface 
    void executeJs() { 
    ..... 
    } 
}

step2:进行映射

// 设置与Js交互的权限 
webSettings.setJavaScriptEnabled(true); 
mWebView.addJavascriptInterface(new ToJs(), "test");

step3:在js层调用

window.test.executeJs();

缺点:存在安全性问题,由于能够经过test来获取整一个java类的全部方法,可能会获取系统或者用户等敏感信息。

2)WebViewClient的shouldOverrideUrlLoading:主要是对url请求进行拦截操做,对url的协议格式schema,协议名authority进行判断,若是符合则调用对应的方法而且返回true,容许url拦截,不然返回false,不支持url拦截。

协议形式:schema://authority?param1=xxx&param2=xxx

// java 
 websetting.setJavascriptEnabled(true);
 webview.setWebViewClient(new WebViewClient() {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
       Uri uri = Uri.parse(url);
       String schema = uri.getSchema();
       String authority = uri.getAuthority();
       Set collection = uri.getQueryParameterNames();
       if (schema.equal('js') && authority.equal('webview')) {
          ...
          webview.loadUrl('javascript: c"(" + result + ")')
          return false
      }
   }
   return true;
 })
 
 // js 
  function b() { 
     window.location = 'js://webview?a=1&b=2'; 
  } 
  function c(data) {} 
  b()

优势:不存在安全漏洞;
缺点:很难在js端获取安卓端方法调用后的返回值;只能经过loadUrl方式将结果返回给js端;
使用场景:不须要返回值的时候;

3)WebChromeClient的onJsAlert()、onJsConfirm()、onJsPrompt():
原理:就是js层调用了alert,confirm,prompt时,webview能够经过设置webchromeclient来拦截弹窗的默认行为,从而对传过来的参数进行处理,通常传过来的参数是协议的格式传过来,主要是为了约束。

区别:

alert ---》没有返回值;
comfirm ---》只返回true或者false;
prompt ----》输入框输入什么,可返回什么,所以能够拦截它,而后改变返回的值;

image.png

image.png

优势:能获取webview的返回值;
缺点:就是比较麻烦;
(吐槽一下segmengfault这里的富文本框,贴代码特别不方便。)

js与RN的交互:

上面说了这么多,主要是为了给rn中webview和js层通讯而作的一个铺垫,接下来就介绍本文的主题。
在rn中,对于视图组件在安卓中是会受到ViewManager控制;在rn中webview管理器的结构以下:

image.png

其中:
ReactWebViewClient:实现了WebviewClient,而且重写了几个重要的生命钩子;
ReactWebView:实现了webview,它根据rn的特色重写了不少方法,而且在setWebViewClient中将ReactWebviewClient注入进来。
ReactWebviewBridge:提供给js层调用。

当设置webview的source的时候,就会触发setSource方法,此时的处理逻是:
image.png
由此处能够看出当对于html或者uri会有不同的处理,但最后仍是经过webview.loadUrl来加载资源。

对于原生调用js代码,rn会多一层封装,将loadUrl和evaluteJavascript封装在一块儿evaluateJavascriptWithFallback;

image.png

通讯原理图(有些复杂,ios的不会这么复杂):

image.png
image.png
image.png

(因为流程图比较大且复杂,因此分开三段展现)

关键步骤:
step1:js层调用webview层方法:
image.png

image.png

image.png

image.png

step2:rn层与rn-js层通讯:
image.png

step3:rn-js层与rn层通讯:
image.png

step4:rn层调用js方法:
image.png

总结:其实rn-js与html层通讯,能够拆分红rn-js层和rn原生层通讯+webview和js层的通讯;

参考文章:
安卓webview
最全面总结 Android WebView与 JS 的交互方式
Android WebView 全面干货指南
你不知道的 Android WebView 使用漏洞

相关文章
相关标签/搜索