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:有更好的办法请评论区留言,不胜感激
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章