有的時候我們使用React Native無法滿足一些使用特定場景,這個時候就需要使用原生的Android方法乐设,比如一些耗時的寫操作讼庇,操作數(shù)據(jù)庫或者多線程操作等。
React Native可以直接調(diào)用系統(tǒng)的API(java方法),實現(xiàn)JavaScript與java語言的通訊近尚,如果React Native中沒有滿足我們需求的Api,可以封裝原生的方法提供JavaScript調(diào)用蠕啄。
JavaScript和java通信是通過bridge
實現(xiàn)的,在java層和JavaScript層的bridge分別存有相同的一份模塊配置表戈锻。Java與JavaScript相互通信時介汹,通過bridge里的配置表將所調(diào)用模塊方式轉(zhuǎn)為{moduleID,methodID,args}
的形式傳遞給處理層,處理層通過bridge里的配置表找到對應(yīng)的方法執(zhí)行舶沛,如果有callback嘹承,則回傳給調(diào)用層,如果沒有執(zhí)行就結(jié)束。
我們通過JavaScript調(diào)用Toast的例子來看下如庭,JavaScript如何調(diào)用Java代碼的叹卷。
新建一個項目:
react-native init RNAndroid
在android的項目目錄下面新建一個類RNToastModule,此類需要繼承ReactContextBaseJavaModule
撼港。
ReactContextBaseJavaModule
ReactContextBaseJavaModule
是一個抽象類,是用來被JavaScript調(diào)用對象的父類骤竹,我們需要Override一些ReactContextBaseJavaModule
的方法帝牡。
首先要Override getName()
方法:
@Override
public String getName() {
return "RNToastAndroid";
}
這個方法的返回值就是JavaScript中調(diào)用的名稱,比如我們命名為RNToastAndroid,在JavaScript中可以這樣調(diào)用:
var {NativeModules}=require('react-native');
var rnToastAndroid = NativeModules.RNToastAndroid;
然后我們可以選擇性的覆蓋getConstants()
方法:
這個方法的用在JavaScript和Java直接定義公用常量的蒙揣,它使用key-value的方式保存靶溜。
在Java中定義兩個變量:
private static final String DURAION_SHORT_KEY = "SHORT";
private static final String DURAION_LONG_KEY = "LONG";
在getConstants()
中給兩個字符串賦值:
@Override
public Map<String, Object> getConstants() {
final Map<String, Object> constants = new HashMap<>();
constants.put(DURAION_SHORT_KEY, Toast.LENGTH_SHORT);
constants.put(DURAION_LONG_KEY, Toast.LENGTH_LONG);
return constants;
}
我們把Toast的兩個常量放在了 constants
中。
在JavaScript可以這樣調(diào)用:
rnToastAndroid.show('Hello Toast of native', rnToastAndroid.SHORT);
最后我們定義一個React調(diào)用的方法:
@ReactMethod
public void show(String message, int duration) {
Toast.makeText(getReactApplicationContext(), message, duration).show();
}
這個使用了annotation
定義的方式必須加上@ReactMethod
懒震。
這里的參數(shù)只能React Navive定義的參數(shù)罩息。
ReactMethod的對應(yīng)參數(shù)
@ReactMethod
中傳的參數(shù)必須是JavaScript和Java對應(yīng)的。
Boolean -> Bool
Integer -> Number
Double -> Number
Float -> Number
String -> String
Callback -> function
ReadableMap -> Object
ReadableArray -> Array
注冊ReactPackage
新建一個RNJavaReactPackage類个扰,繼承ReactPackage瓷炮。
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new RNToastModule(reactContext));
return modules;
}
@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return new ArrayList<>();
}
RNJavaReactPackage創(chuàng)建了一個NativeModule的List。把RNToastModule的實例都添加進去提供給JavaScript層調(diào)用递宅。
添加ReactPackage
在android/app/src/main/java/com/your-app-name/
中有個MainActivity.java其中的getPackages()
方法用來返回用來的ReactPackage包,添加定義好的RNJavaReactPackage的實例
以上內(nèi)容已經(jīng)在0.31.0
中更新娘香。
新版本使用ReactNativeHost
替換ReactInstanceManager
,ReactNativeHost是設(shè)置Android相關(guān)配置的類。
需要在Application
中實例化办龄。
首先實現(xiàn)新建一個ReactNativeHost
的實例并添加RNJavaReactPackage的實例:
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
protected boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new RNJavaReactPackage()
);
}
};
實現(xiàn)ReactApplication
:
public class MainApplication extends Application implements ReactApplication {
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
}
JavaScript中調(diào)用
在JavaScript顯示Toast:
'use strict';
var {NativeModules}=require('react-native');
var rnToastAndroid = NativeModules.RNToastAndroid;
rnToastAndroid.show('Hello Toast of native', rnToastAndroid.SHORT);
這樣就完成了從JavaScript中直接調(diào)用了Java中定義的方法烘绽。
代碼地址:https://github.com/jjz/react-native/tree/master/RNAndroid