H5 跳轉Flutter APP問題:在Flutter中解決H5能夠打開APP並接收H5傳遞的參數

最近遇到了這個問題,其實這個問題在源生開發中算是一個很常見的問題。有很多場景都需要通過其他APP或者H5來打開APP並且有時候會攜帶參數。

所以在這裏我說一下我的做法(大神勿噴,有更好的辦法請評論區留言,不勝感激)。

我的思路就是:1.APP接收第三方平臺的請求方式與源生處理方式不變,然後存儲好請求的參數;2.利用平臺提供的Flutter與源生交互的通道MethodChannel(android)以及FlutterMethodChannel(iOS),在雙端分別創建一個可以訪問到存儲的請求數據的通道,通過判斷存儲的數據,來響應第三方平臺的請求。

Android端

1.首先在AndroidManifest.xml中修改入口Activity的配置:

            android:name=".MainActivity"
            android:launchMode="singleTask"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:exported="true"
            android:windowSoftInputMode="adjustResize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
                
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.BROWSABLE"/>
                <data android:scheme="scheme" android:host="host" android:pathPrefix="/path"/>
            </intent-filter>
        </activity>

其中 android:launchMode=“singleTask” android:exported=“true” 是新增的
以及

                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.BROWSABLE"/>
                <data android:scheme="scheme" android:host="host" android:pathPrefix="/path"/>

2.在MainActivity中接收並保存第三方傳遞過來的參數信息:

  private void getOpenData(){
    try {
      Uri uri = getIntent().getData();
      if (uri==null){
        return;
      }
      String query = uri.getQuery();
      String openpage = uri.getQueryParameter("openpage");
      String data = uri.getQueryParameter("data");
      Log.d("scheme-", "openpage: " + openpage + ", data: " + data + ", query: " + query);
      JSONObject jsonObject=new JSONObject();
      jsonObject.put("openpage",openpage);
      jsonObject.put("data",data);
      CampusBarApplication.schemeInfo=jsonObject;
    } catch (Exception e) {
      Log.e("scheme-", e.getMessage(), e);
    }
  }

我這裏用了一個靜態變量保存 CampusBarApplication.schemeInfo=jsonObject; 用數據庫、SP,文件等都可以,這裏爲了方便就用了個靜態變量。

3.定義一個Flutter與源生交互的通道:
什麼是通道?https://book.flutterchina.club/chapter12/platform-channel.html

 private void initOpenPage() {
//    new MethodChannel()
    new MethodChannel(getFlutterView(), openpage_chanel).setMethodCallHandler(
            (methodCall, result) -> {
              if (methodCall.method.equals(checkOpenPage)) {
                Map<String,String> map=new HashMap<>();
                if (CampusBarApplication.schemeInfo==null){
                  map.put("code","201");
                }else {
                  map.put("code","200");
                  map.put("openpage",CampusBarApplication.schemeInfo.getString("openpage"));
                  map.put("data",CampusBarApplication.schemeInfo.getString("data"));
                  CampusBarApplication.schemeInfo=null;//記得在每次相應完清空保存的數據
                }
                result.success(map);
              }
            }
    );

  }

4.在flutter代碼使用:

  var  platform = MethodChannel(NetUrlConstant.OPENPAGE_CHANEL);
  platform.invokeMethod(NetUrlConstant.CHECK_OPEN_PAGE).then((onValue){
    if(onValue["code"]=="200"){
      println(onValue["data"]+"aassddffgg-----------------------------");
	//TODO
    }else if(onValue["code"]=="201"){
    }

   
  });

這樣就可以在flutter響應到第三方的請求。

iOS端

1.首先開始跟源生開發一樣去配置URL Scheme 或者使用universal link,我在這就不講怎麼配置了。
2.在AppDelegate.m中接收並保存第三方傳遞過來的參數信息:

- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options
{
 
      NSLog(@"URL scheme:%@", [url scheme]);
      NSLog(@"URL query: %@", [url query]);
      
      NSMutableDictionary * dic=[NSMutableDictionary dictionary];
      
      [dic setObject:[url scheme] forKey:@"openpage"];
      [dic setObject:[url query] forKey:@"data"];
      NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
      
      [userDefaults setObject:dic forKey:@"openinfo"];
      
      //這裏建議同步存儲到磁盤中,但是不是必須的
      [userDefaults synchronize];
  
    return YES;
}

3.在AppDelegate.m 中同樣是定義一個通道:

    FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
    
     FlutterMethodChannel* channel = [FlutterMethodChannel
                                             methodChannelWithName:@"openpage_chanel"
                                             binaryMessenger:controller];

     [channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
       // TODO
          if ([@"checkOpenPage" isEqualToString:call.method]) {
           
            
              
              NSUserDefaults *userDefaultes = [NSUserDefaults standardUserDefaults];
              //讀取字典類型NSDictionary類型的數據
              NSMutableDictionary *dic = [userDefaultes dictionaryForKey:@"openinfo"];
              
              if (dic) {
                  [dic setObject:@"200" forKey:@"code"];
                  //記得清除保存的信息
                  
              }else{
                  dic=[NSMutableDictionary dictionary];
                    [dic setObject:@"201" forKey:@"code"];
                    
              }
            result(dic);
         }
         
     }];

注意:Android跟iOS要協商好,將通道返回的信息格式保持一致,這樣在Flutter就不用判斷平臺,用一套代碼就可以完成雙端的操作。

PS:有更好的辦法請評論區留言,不勝感激
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章