最近遇到了這個問題,其實這個問題在源生開發中算是一個很常見的問題。有很多場景都需要通過其他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就不用判斷平臺,用一套代碼就可以完成雙端的操作。