【简述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 => { ... })
- 唤起并传递参数。
使用Linking打开app调用openURL方法即可:
Linking.openURL('appscheme://apphost/path?params=xxx')
完整调用方法如下:Linking.canOpenURL('appscheme://').then(canopen => { if (canopen) { console.warn('可以打开: appscheme'); Linking.openURL('appscheme://apphost/path?rn=true') } else { console.warn('未安装: appscheme'); } })
备注: Android人员应该知道上述打开的路由appscheme://apphost/path?rn=true 哪里来的,非Android应该不太清楚,其实这里的路由是我们在Android项目中的AndroidManifest.xml 文件中设置的,如下:
<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传递到对应的js中。
- APP中跳转加载RN的页面。
Intent intent1 = new Intent(Intent.ACTION_VIEW, Uri.parse("appscheme://apphost/path?params=xxx")); startActivity(intent1);
- RN页面渲染的js文件中如何获取跳转路由。
Linking.getInitialURL().then((url) => { if (url) { console.warn('捕捉的URL地址为: ' + url); }else{ console.warn('捕获得的url为空'); } }).catch(err => console.error('错误信息为:', err));
- 在js中监听APP的运行状态。
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的源码发现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()));
}
}
由上述代码发现getInitialURL()
方法获取的即为intent.getData().toString()内容,可是使用过程中发现此处返回可能为null,所以就跟着查看下原因,发现在React Native中的componentDidMount
生命周期方法与Android的Activity还未建立绑定关系,此时 getCurrentActivity()
返回null,所以拿不到对应的intent.getData()。
解决方案:
- 方案一:
在RN中对AppState进行监听,当处于active
状态再获取对应的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中对应的Activity和NativeModule中修改。public static ArrayBlockingQueue<String> myBlockingQueue = new ArrayBlockingQueue<String>(1);//临时和RN交互的数据 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getIntent() != null && getIntent().getData() != null){ myBlockingQueue.clear(); myBlockingQueue.add(getIntent().getData().toString()); } }
在NativeModule中添加如下方法:
@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())); } } }