【簡述RN集成到Android原生項目】
【Android項目集成RN系列:RN混淆 / 消息通信 / Gif圖片/ 修改端口號 / 離線包】
【RN使用Android原生控件或自定義組件】
1. Linking 喚起APP.
- 檢查該app能否被喚起,也就是檢查該app是否已安裝成功;
Linking提供了canOpenURL(url: string): Promise<boolean>;這個方法,用來檢測某個url是否可以打開;Linking.canOpenURL('appscheme://').then(canopen => { ... }) - 喚起并傳遞參數(shù)。
使用Linking打開app調(diào)用openURL方法即可:
Linking.openURL('appscheme://apphost/path?params=xxx')
完整調(diào)用方法如下:
備注: Android人員應(yīng)該知道上述打開的路由appscheme://apphost/path?rn=true 哪里來的,非Android應(yīng)該不太清楚,其實這里的路由是我們在Android項目中的AndroidManifest.xml 文件中設(shè)置的,如下:Linking.canOpenURL('appscheme://').then(canopen => { if (canopen) { console.warn('可以打開: appscheme'); Linking.openURL('appscheme://apphost/path?rn=true') } else { console.warn('未安裝: appscheme'); } })<activity android:name=".RNPreloadActivity" android:launchMode="singleTask"> <intent-filter> <data android:host="apphost" android:scheme="appscheme"/> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.BROWSABLE"/> </intent-filter> </activity>
2. APP中喚起RN頁面的Activity,并將路由信息通過linking傳遞到對應(yīng)的js中。
- APP中跳轉(zhuǎn)加載RN的頁面。
Intent intent1 = new Intent(Intent.ACTION_VIEW, Uri.parse("appscheme://apphost/path?params=xxx")); startActivity(intent1); - RN頁面渲染的js文件中如何獲取跳轉(zhuǎn)路由。
Linking.getInitialURL().then((url) => { if (url) { console.warn('捕捉的URL地址為: ' + url); }else{ console.warn('捕獲得的url為空'); } }).catch(err => console.error('錯誤信息為:', err)); - 在js中監(jiān)聽APP的運行狀態(tài)。
監(jiān)聽的字符串以及狀態(tài)如下:AppState.addEventListener('change',(appState)=>{ if(appState=='active'){ Linking.getInitialURL().then(url=>{ console.warn('stateChange url: ' + url); }) } })export type AppStateEvent = "change" | "memoryWarning"; export type AppStateStatus = "active" | "background" | "inactive";
3. Linking在Android中使用Linking.getInitialURL()可能會返回null的問題。
在項目目錄中node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/intent/IntentModule.java查看Linking的源碼發(fā)現(xiàn)getInitialURL()方法如下:
@ReactMethod
public void getInitialURL(Promise promise) {
try {
Activity currentActivity = getCurrentActivity();
String initialURL = null;
if (currentActivity != null) {
Intent intent = currentActivity.getIntent();
String action = intent.getAction();
Uri uri = intent.getData();
if (Intent.ACTION_VIEW.equals(action) && uri != null) {
initialURL = uri.toString();
}
}
promise.resolve(initialURL);
} catch (Exception e) {
promise.reject(new JSApplicationIllegalArgumentException(
"Could not get the initial URL : " + e.getMessage()));
}
}
由上述代碼發(fā)現(xiàn)getInitialURL()方法獲取的即為intent.getData().toString()內(nèi)容,可是使用過程中發(fā)現(xiàn)此處返回可能為null,所以就跟著查看下原因,發(fā)現(xiàn)在React Native中的componentDidMount生命周期方法與Android的Activity還未建立綁定關(guān)系,此時 getCurrentActivity()返回null,所以拿不到對應(yīng)的intent.getData()。
解決方案:
- 方案一:
在RN中對AppState進行監(jiān)聽,當(dāng)處于active狀態(tài)再獲取對應(yīng)的url。onAppStateChange = (nextAppState) => { if (nextAppState === 'active') { Linking.getInitialURL().then(url => { console.warn("onAppStateChange Url:"+url) }) } } componentDidMount = async () => { if (AppState.currentState === 'active') { Linking.getInitialURL().then(url => { console.warn("AppState.currentState Url:"+url) }) } AppState.addEventListener('change', this.onAppStateChange); } - 方案二:
在Android中對應(yīng)的Activity和NativeModule中修改。
在NativeModule中添加如下方法:public static ArrayBlockingQueue<String> myBlockingQueue = new ArrayBlockingQueue<String>(1);//臨時和RN交互的數(shù)據(jù) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getIntent() != null && getIntent().getData() != null){ myBlockingQueue.clear(); myBlockingQueue.add(getIntent().getData().toString()); } }@ReactMethod public void getInitialURL(Promise promise) { try { String initialURL = RNPreloadActivity.myBlockingQueue.take(); if (promise != null){ promise.resolve(initialURL); } } catch (InterruptedException e) { if (promise != null){ promise.reject(new JSApplicationIllegalArgumentException( "Could not get the initial URL : " + e.getMessage())); } } }