blog
blog copied to clipboard
Android vs JS通知机制分析【react-native webview等】
前言
最近公司开始上RN android项目,作为一个基本上不写java的纯野生web前端开发, 我还是想来窥探一下react-native/android下对RN项目提供的jar包结构和类方法,以便对项目开发更具有掌控力。
正文
传统JS-Android开发模式【Webview接口】
通过使用android提供的Webview类,即可完成JS和java代码的通信。 基本的使用方式如下:
- 添加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"
/>
- 添加程序清单,增加网络权限
<!-- androidManifest.xml 添加Internet权限-->
<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
- 添加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);
- 添加前端代码
<!-- 调用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>
- 网络请求拦截,最经典的JSBridge实现方案
UIWebView组件【ios】
shouldOverrideUrlLoading((WebView view, WebResourceRequest request))【Android】
RN 安卓的基本类和实现原理
RN的基本实现思路是比较简单的,不同于传统的webview按照jsBridge形式进行native和h5的通信方案, RN的实现方式充分利用了ios/android内置的JS引擎。 一个基本RN的activity依赖这么几个重要的类/库
- 安卓项目运行
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执行原理的讲解