blog icon indicating copy to clipboard operation
blog copied to clipboard

Android vs JS通知机制分析【react-native webview等】

Open slashhuang opened this issue 7 years ago • 0 comments

前言

最近公司开始上RN android项目,作为一个基本上不写java的纯野生web前端开发, 我还是想来窥探一下react-native/android下对RN项目提供的jar包结构和类方法,以便对项目开发更具有掌控力。

正文

传统JS-Android开发模式【Webview接口】

通过使用android提供的Webview类,即可完成JS和java代码的通信。 基本的使用方式如下:

  1. 添加webview页面
    <!--  res/layout/下的文件  -->
    <WebView  xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/webview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
    />
  1. 添加程序清单,增加网络权限
    <!--  androidManifest.xml 添加Internet权限-->
    <?xml version="1.0" encoding="utf-8"?>
        <manifest ... >
        <uses-permission android:name="android.permission.INTERNET" />
    </manifest>
  1. 添加webview接口
    /**添加Webview**/

    WebView myWebView = (WebView) findViewById(R.id.webview);
    myWebView.loadUrl("http://www.example.com");

    /*添加java接口*/
    public class WebAppInterface {
        Context mContext;
        /** 设置context */
        WebAppInterface(Context c) {
            mContext = c;
        }
        /**点击跳出toast*/
        @JavascriptInterface
        public void showToast(String toast) {
            Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
        }
    }

    /*添加JS调用java的接口描述,webview可以调用window['android']来触发native代码*/
    myWebView.addJavascriptInterface(new WebAppInterface(this), "android");

    /*添加Java直接调用JS的接口*/
    myWebView.evaluateJavascript("getGreetings()", new ValueCallback<String>(){
        @Override
        public void onReceiveValue(String value) {
           println(value);
        }});
    });
    /* 启用JS */
    myWebView.getSettings().setJavaScriptEnabled(true);
  1. 添加前端代码
    <!--   调用Android代码   -->
    <input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />
    <script type="text/javascript">
        function showAndroidToast(toast) {
            window.android.showToast(toast);
        }
        function getGreetings() {
            return 1;
        }
    </script>
  1. 网络请求拦截,最经典的JSBridge实现方案
    UIWebView组件【ios】
    shouldOverrideUrlLoading((WebView view, WebResourceRequest request))【Android】

RN 安卓的基本类和实现原理

RN的基本实现思路是比较简单的,不同于传统的webview按照jsBridge形式进行native和h5的通信方案, RN的实现方式充分利用了ios/android内置的JS引擎。 一个基本RN的activity依赖这么几个重要的类/库

  1. 安卓项目运行

RN的实现原理【创建原生模块为例】

原生模块 extends ReactContextBaseJavaModule

    public class ToastModule extends ReactContextBaseJavaModule {

      private static final String DURATION_SHORT_KEY = "SHORT";
      private static final String DURATION_LONG_KEY = "LONG";

      public ToastModule(ReactApplicationContext reactContext) {
        super(reactContext);
      }
      /*派生类实现getName方法*/
      @Override
      public String getName() {
        return "ToastAndroid";
      }
      /*一个可选的方法getContants返回了需要导出给JavaScript使用的常量*/
      @Override
      public Map<String, Object> getConstants() {
        final Map<String, Object> constants = new HashMap<>();
        constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
        constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);
        return constants;
      }
      /*要导出一个方法给JavaScript使用,Java方法需要使用注解@ReactMethod*/
      @ReactMethod
      public void show(String message, int duration) {
        Toast.makeText(getReactApplicationContext(), message, duration).show();
      }
      /*提供给JS进行回调*/
      @ReactMethod
      public void measureLayout(
          int tag,
          int ancestorTag,
          Callback errorCallback,
          Callback successCallback) {
        try {
          measureLayout(tag, ancestorTag, mMeasureBuffer);
          float relativeX = PixelUtil.toDIPFromPixel(mMeasureBuffer[0]);
          float relativeY = PixelUtil.toDIPFromPixel(mMeasureBuffer[1]);
          float width = PixelUtil.toDIPFromPixel(mMeasureBuffer[2]);
          float height = PixelUtil.toDIPFromPixel(mMeasureBuffer[3]);
          successCallback.invoke(relativeX, relativeY, width, height);
        } catch (IllegalViewOperationException e) {
          errorCallback.invoke(e.getMessage());
        }
      }
    }
      /*注册模块*/
      class AnExampleReactPackage implements ReactPackage {
          @Override
          public List<Class<? extends JavaScriptModule>> createJSModules() {
            return Collections.emptyList();
          }

          @Override
          public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
            return Collections.emptyList();
          }

          @Override
          public List<NativeModule> createNativeModules(
                                      ReactApplicationContext reactContext) {
            List<NativeModule> modules = new ArrayList<>();

            modules.add(new ToastModule(reactContext));

            return modules;
          }
    }
    /*将注册模块的列表添加进MainApplication.java*/
    protected List<ReactPackage> getPackages() {
        return Arrays.<ReactPackage>asList(
                new MainReactPackage(),
                new AnExampleReactPackage()); // <-- 添加这一行,类名替换成你的Package类的名字.
    }

参考资料

安卓webview实现原理 react-native架构初探 react-native 安卓模块 facebook关于react-native执行原理的讲解

slashhuang avatar Dec 07 '16 09:12 slashhuang