React Native Linking與 Android原生頁面路由跳轉(zhuǎn)問題

【簡述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)用方法如下:
      Linking.canOpenURL('appscheme://').then(canopen => {
        if (canopen) {
           console.warn('可以打開: appscheme');
           Linking.openURL('appscheme://apphost/path?rn=true')
        } else {
           console.warn('未安裝: appscheme');
        }
      })
    
    備注: Android人員應(yīng)該知道上述打開的路由appscheme://apphost/path?rn=true 哪里來的,非Android應(yīng)該不太清楚,其實這里的路由是我們在Android項目中的AndroidManifest.xml 文件中設(shè)置的,如下:
    <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)。
         AppState.addEventListener('change',(appState)=>{
              if(appState=='active'){
                  Linking.getInitialURL().then(url=>{
                      console.warn('stateChange url: ' + url);    
                  })
              }
            })
    
    監(jiān)聽的字符串以及狀態(tài)如下:
    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()。

解決方案:

  1. 方案一:
    在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);
     }
    
  2. 方案二:
    在Android中對應(yīng)的Activity和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());
           }
       }
    
    在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()));
                }
            }
        }
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容