在混合工程中,flutter和原生之间的页面栈如何管理呢,由于我们采用的是hybrid_stack_manager,这里简单分析下整个流程
一、原生跳Flutter
1、使用
原生
HashMap<String,Object> m = new HashMap<>();
m.put("flutter", true);
HashMap<String,Object> p = new HashMap<>();
p.put("title", "测试");
XURLRouter.sharedInstance().openUrlWithQueryAndParams("hrd://test", m, p);
Flutter
Router.sharedInstance().routerWidgetHandler =
({RouterOption routeOption, Key key}) {
print(routeOption.url);
print(routeOption.query);
print(routeOption.params);
switch (routeOption.url) {
case "hrd://test":
return MaterialApp(...);
}
return null;
};
2、源码
XURLRouter是个单例,先看openUrlWithQueryAndParams方法
public boolean openUrlWithQueryAndParams(String url, HashMap<String, Object> query, HashMap<String, Object> params){
Uri tmpUri = Uri.parse(url);
if(!kOpenUrlPrefix.equals(tmpUri.getScheme()))
return false;
//会走这个if
if(query!=null && query.containsKey("flutter") && (Boolean) query.get("flutter")){
//这里可以看到原生跳flutter页面,其实是跳转到FlutterWrapperActivity,而且会把query、params两个HashMap带过去
Intent intent = new Intent(mAppContext,FlutterWrapperActivity.class);
intent.setData(Uri.parse(url));
intent.setAction(Intent.ACTION_VIEW);
intent.putExtra("query", query);
intent.putExtra("params", params);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mAppContext.startActivity(intent);
return true;
}
...
return false;
}
再看FlutterWrapperActivity的onCreate方法
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.flutter_layout);
checkIfAddFlutterView();
fakeSnapImgView = (ImageView) findViewById(R.id.flutter_snap_imageview);
fakeSnapImgView.setVisibility(View.GONE);
//Process Intent Extra
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
Uri uri = intent.getData();
//会走这个if
if (uri != null) {
//把获取到的url、query、params传到HybridStackManager
HybridStackManager.sharedInstance().openUrlFromFlutter(uri.toString(), (HashMap) intent.getSerializableExtra("query"), (HashMap) intent.getSerializableExtra("params"));
} else if (bundle != null) {
HybridStackManager.sharedInstance().openUrlFromFlutter(intent.getStringExtra("url"), (HashMap) intent.getSerializableExtra("query"), (HashMap) intent.getSerializableExtra("params"));
}
...
}
HybridStackManager是个单例,然后我们看openUrlFromFlutter方法
public void openUrlFromFlutter(String url, HashMap query, HashMap params) {
//从这里我们看到参数是通过methodChannel传递给Flutter的,而assembleChanArgs方法会把url、query、parmas组装成一个新的HashMap
HybridStackManager.sharedInstance().methodChannel.invokeMethod("openURLFromFlutter", assembleChanArgs(url, query, params));
}
接下来我们Flutter中的openURLFromFlutter方法,在Flutter端我们会先调用Router.sharedInstance(),该方法会调到setupMethodChannel方法,方法里边会设置MethodChannel的回调setMethodCallHandler
void setupMethodChannel(){
HybridStackManagerPlugin.hybridStackManagerPlugin
.setMethodCallHandler((MethodCall methodCall)async{
String method = methodCall.method;
//这里我们看到了openURLFromFlutter方法,即原生会调到
if (method == "openURLFromFlutter") {
//获取组装后的Map
Map args = methodCall.arguments;
if (args != null) {
bool animated = (args["animated"] == 1);
//参数传到pushPageWithOptionsFromFlutter方法
Router.sharedInstance().pushPageWithOptionsFromFlutter(
routeOption: new RouterOption(
url: args["url"],
query: args["query"],
params: args["params"]),
animated: animated ?? false);
}
} else if (method == "popToRoot") {
Router.sharedInstance().popToRoot();
} else if (method == "popToRouteNamed") {
Router.sharedInstance().popToRouteNamed(methodCall.arguments);
} else if (method == "popRouteNamed") {
Router.sharedInstance().popRouteNamed(methodCall.arguments);
}
else if(method == "fetchSnapshot"){
...
}
});
}
我们看Router的pushPageWithOptionsFromFlutter方法
pushPageWithOptionsFromFlutter({RouterOption routeOption, bool animated}) {
//这个pageFromOption方法肯关键,它会返回一个Widget接下来会详细看这个方法
Widget page =
Router.sharedInstance().pageFromOption(routeOption: routeOption);
if (page != null) {
//会走这个if
GlobalKey boundaryKey = new GlobalKey();
//XMaterialPageRoute是MaterialPageRoute的子类
XMaterialPageRoute pageRoute = new XMaterialPageRoute(
settings: new RouteSettings(name: routeOption.userInfo),
animated: animated,
boundaryKey: boundaryKey,
builder: (BuildContext context) {
return new RepaintBoundary(key:boundaryKey,child: page);
});
//前边我们知道原生跳转flutter其实是跳转了一个FlutterWrapperActivity,然后把参数通过methodChannel传递给flutter,这里可以看出flutter这一端的页面栈其实也是通过Navigator管理的
Navigator.of(globalKeyForRouter.currentContext).push(pageRoute);
HybridStackManagerPlugin.hybridStackManagerPlugin
.updateCurFlutterRoute(routeOption.userInfo);
} else {
HybridStackManagerPlugin.hybridStackManagerPlugin.openUrlFromNative(
url: routeOption.url,
query: routeOption.query,
params: routeOption.params);
}
NavigatorState navState = Navigator.of(globalKeyForRouter.currentContext);
List<Route<dynamic>> navHistory = navState.history;
}
接下来我们看Router的pageFromOption方法,先回忆下我们之前会给routerWidgetHandler赋值
//给routerWidgetHandler赋值
Router.sharedInstance().routerWidgetHandler =
({RouterOption routeOption, Key key}) {
print(routeOption.url);
print(routeOption.query);
print(routeOption.params);
switch (routeOption.url) {
case "hrd://test":
//返回一个Widget
return MaterialApp(...);
}
return null;
};
typedef Widget FlutterWidgetHandler({RouterOption routeOption, Key key});
//会给routerWidgetHandler赋值
FlutterWidgetHandler routerWidgetHandler;
pageFromOption({RouterOption routeOption, Key key}) {
try {
currentPageUrl = routeOption.url + "?" + converUrl(routeOption.query);
} catch (e) {}
routeOption.userInfo = Utils.generateUniquePageName(routeOption.url);
if (routerWidgetHandler != null)
//回调routerWidgetHandler方法并且返回Widget
return routerWidgetHandler(routeOption: routeOption, key: key);
}
3、总结
- 原生跳转flutter其实是跳转到FlutterWrapperActivity
- 在FlutterWrapperActivity中参数会通过MethodChannel传递给flutter
- 在flutter这一端的页面栈其实也是通过Navigator管理的
二、Flutter跳原生
1、使用
Flutter
HybridStackManagerPlugin.hybridStackManagerPlugin
.openUrlFromNative(
url: "hrd://test",
query: {"title": "测试"});
原生
XURLRouter.sharedInstance().setNativeRouterHandler((url, query, params) -> {
switch (url) {
case "hrd://test":
return TestActivity.class;
}
return null;
});
2、源码
先看HybridStackManagerPlugin的openUrlFromNative方法
openUrlFromNative({String url, Map query, Map params, bool animated}) {
//会通过MethodChannel把参数传给原生
_channel.invokeMethod("openUrlFromNative", {
"url": url ?? "",
"query": (query ?? {}),
"params": (params ?? {}),
"animated": animated ?? true
});
}
接着看原生中的openUrlFromNative
@Override
public void onMethodCall(MethodCall call, Result result) {
if (call.method.equals("openUrlFromNative")) {
if (curFlutterActivity != null && curFlutterActivity.isActive()) {
HashMap openUrlInfo = (HashMap)call.arguments;
String url = (String)openUrlInfo.get("url");
HashMap query = (HashMap)openUrlInfo.get("query");
HashMap params = (HashMap)openUrlInfo.get("params");
//将获取的参数组装成字符串
String concatUrl = concatUrl(url, query, params);
//调用FlutterWrapperActivity的openUrl方法
curFlutterActivity.openUrl(concatUrl, params);
}
result.success("OK");
} else if (call.method.equals("getMainEntryParams")) {
...
}
}
我们看FlutterWrapperActivity的openUrl方法
public void openUrl(String url, HashMap params) {
HybridStackManager.sharedInstance().curFlutterActivity = null;
if (url.contains("flutter=true")) {
//flutter跳flutter需要设置flutter为true
Intent intent = new Intent(FlutterWrapperActivity.this, FlutterWrapperActivity.class);
intent.setAction(Intent.ACTION_RUN);
intent.setData(Uri.parse(url));
intent.putExtra("params", params);
this.innerStartActivity(intent, true);
} else {
//会走这里
Uri tmpUri = Uri.parse(url);
String tmpUrl = String.format("%s://%s", tmpUri.getScheme(), tmpUri.getHost());
HashMap query = new HashMap();
for (String key : tmpUri.getQueryParameterNames()) {
query.put(key, tmpUri.getQueryParameter(key));
}
//调XURLRouter的openUrlWithQueryAndParams方法
XURLRouter.sharedInstance().openUrlWithQueryAndParams(tmpUrl, query, null);
saveFinishSnapshot(false);
}
}
public boolean openUrlWithQueryAndParams(String url, HashMap<String, Object> query, HashMap<String, Object> params){
Uri tmpUri = Uri.parse(url);
if(!kOpenUrlPrefix.equals(tmpUri.getScheme()))
return false;
if(query!=null && query.containsKey("flutter") && (Boolean) query.get("flutter")){
//原生调会走这里,需要设置flutter为true
Intent intent = new Intent(mAppContext,FlutterWrapperActivity.class);
intent.setData(Uri.parse(url));
intent.setAction(Intent.ACTION_VIEW);
intent.putExtra("query", query);
intent.putExtra("params", params);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mAppContext.startActivity(intent);
return true;
}
if(mNativeRouterHandler!=null) {
//这里会回调XURLRouterHandler的openUrlWithQueryAndParams方法并获取到一个Class,最后通过startActivity进行页面跳转
Class activityCls = mNativeRouterHandler.openUrlWithQueryAndParams(url, query, params);
Intent intent = new Intent(mAppContext,activityCls);
intent.setData(Uri.parse(url));
intent.setAction(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (query != null) {
for (String key : query.keySet()) {
intent.putExtra(key, String.valueOf(query.get(key)));
}
}
if (params != null) {
for (String key : params.keySet()) {
intent.putExtra(key, String.valueOf(params.get(key)));
}
}
mAppContext.startActivity(intent);
}
return false;
}
我们在使用的时候会给上边的mNativeRouterHandler赋值
public void setNativeRouterHandler(XURLRouterHandler handler){
mNativeRouterHandler = handler;
}
XURLRouter.sharedInstance().setNativeRouterHandler((url, query, params) -> {
switch (url) {
case "hrd://test":
return TestActivity.class;
}
return null;
});
3、总结
- flutter跳原生其实是通过MethodChannel传值给原生
- 原生这边接收到参数后会返回一个Class
- 最终也是通过startActivity实现页面跳转
网友评论