前言
前面我们完成了鸿蒙打开flutter指定页面,并且传递参数,接下来我们看一下在flutter侧打开鸿蒙原生页面,并且传递参数应该如何处理。
当然了,我们在前面也提到了,在flutter发起路由的时候,都交给插件来处理。并且我们在上一章中也创建好了flutter插件,并没有使用和原生交互,只是创建了一个flutter路由和页面映射的管理类。
创建插件
这里为了简单,我们在my_flutter_module
下新建一个plugins
文件,将插件工程放在这个文件夹下。
1 2
| cd my_flutter_module/plugins/ flutter create --org com.huangyuanlove.flutter_router --template=plugin --platforms=ohos flutter_router
|
这里我们演示鸿蒙项目下的插件,就没有支持 Android 和 iOS。
在 my_flutter_module中引用这个插件,在pubspec.yaml
中添加引用
1 2 3
| dependencies: flutter_router: path: plugins/flutter_router
|
flutter打开native
这里需要用到和native通信了。前面也提到过,当flutter发起路由时,先判断目标页面是不是flutter页面,是的话用flutter中的Navigator打开,否则调用channel通知原生打开。
因为打开原生页面有时候也需要传递一些参数,我们在FlutterRouterPlatform
中定义这么一个方法:
1 2 3 4
| Future<T> open<T extends Object?>(url, {dynamic arguments}) { throw UnimplementedError('open() has not been implemented.'); }
|
然后我们在MethodChannelFlutterRouter
中实现这个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @override Future<T> open<T extends Object?>(url, {dynamic arguments}) async { var args = {}; args['path'] = url;
if (arguments != null) { args['arguments'] = arguments; } debugPrint("-----------open---start--------"); debugPrint("path $url"); debugPrint("arguments $arguments"); debugPrint("-----------open----end-------");
final result = await methodChannel.invokeMethod('open', args); return result; }
|
看着代码挺多,实际上只是把url
和arguments
这两个参数打包到了args
里面,通过methodChannel
传给原生。
原生侧处理
这里我们可以使用DevEco打开插件目录下的ohos文件夹,把它当作一个鸿蒙工程。或者简单点,直接在当前工程中编辑也行。只是方法提示不太友好,我们可以把ohos工程中的FlutterRouterPlugin
文件直接复制到当前鸿蒙工程中,编辑完后再复制回去。
我们看下FlutterRouterPlugin
应该如何处理。
考虑到我们是传入的路径,也是打算注册路径和关联页面,但考虑到我们的实际业务情况,就开放了一个处理接口,由native侧设置,当触发打开native页面时,由native来处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| import { FlutterPlugin, FlutterPluginBinding, MethodCall, MethodCallHandler, MethodChannel, MethodResult, } from '@ohos/flutter_ohos';
export default class FlutterRouterPlugin implements FlutterPlugin, MethodCallHandler { private channel: MethodChannel | null = null; static routerPushHandler: (path: string, args: Record<string, Object> | undefined,result:MethodResult) => boolean = (path, args,result) => { return false };
static setRouterPushHandler(handler: (path: string, args: Record<string, Object> | undefined,result:MethodResult) => boolean) { FlutterRouterPlugin.routerPushHandler = handler }
constructor() { }
getUniqueClassName(): string { return "FlutterRouterPlugin" }
onAttachedToEngine(binding: FlutterPluginBinding): void { this.channel = new MethodChannel(binding.getBinaryMessenger(), "flutter_router"); this.channel.setMethodCallHandler(this) }
onDetachedFromEngine(binding: FlutterPluginBinding): void { if (this.channel != null) { this.channel.setMethodCallHandler(null) } }
onMethodCall(call: MethodCall, result: MethodResult): void { if (call.method == "getPlatformVersion") { result.success("OpenHarmony ^ ^ ") } else if (call.method == 'open') { let path: string = call.argument('path') let args: Record<string, Object> | undefined = call.argument('arguments') console.error("-------onMethodCall----open---start--------") console.error(`path ${path}`) console.error(`arguments ${args}`) console.error("------onMethodCall-----open----end-------") FlutterRouterPlugin.routerPushHandler(path, args,result)
} else { result.notImplemented() } } }
|
我们再写一个鸿蒙页面,用来测试flutter打开native的情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| import { HMRouter, HMRouterMgr } from "@hadss/hmrouter"; import { ActionBar } from "../../comm/ActionBar"; import { UIUtils } from "@kit.ArkUI";
@HMRouter({ pageUrl: 'pages/flutter/FromFlutterPage' }) @Component export struct FromFlutterPage { @State routerParam: Map<string, Object> | undefined = undefined
aboutToAppear(): void { this.routerParam = HMRouterMgr.getCurrentParam() as Map<string, Object> }
build() { Column() { ActionBar({ title: "从 flutter 打开的页面",onClickBack:(_)=>{HMRouterMgr.pop()} })
Text('获取到的路由参数') Text(this.routerParamsToStr())
} }
routerParamsToStr(): string { if (this.routerParam) { let result = ''
let tmp:Map<string,Object> = UIUtils.getTarget<Map<string,Object>>(this.routerParam); tmp.forEach((value,key)=>{ result += `${key} : ${value} \n` })
return result
} else { return "无参数" } } }
|
然后我们在EntryAbility
的onCreate
方法中设置一下routerPushHandler
1 2 3 4 5 6 7 8
| FlutterRouterPlugin.setRouterPushHandler((path:string,args:Record<string,Object>|undefined,result: MethodResult)=>{ console.error(`rouerHandler:path=> ${path} ,args=>${args}`) if(path =='pages/flutter/FromFlutterPage'){ HMRouterMgr.push({pageUrl:'pages/flutter/FromFlutterPage',param:args}) return true } return false; });
|
这里我们判断了path的值和跳转对应的页面。
flutter侧调用
我们调用的方法都写在了FlutterRouter
中,并且也是在这里判断是打开 flutter 页面还是打开native 页面
我们在RouterManager
中添加一个判断是否为 flutter 页面的方法
1 2 3 4
| bool hasRouterWidget(String path) { final String routerName = _getRouterName(path); return _routerMap.containsKey(routerName); }
|
然后我们在FlutterRouter
写一下对应的打开页面的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
import 'package:flutter/material.dart'; import 'package:flutter_router/router_manager.dart';
import 'flutter_router_platform_interface.dart';
class FlutterRouter { Future<String?> getPlatformVersion() { return FlutterRouterPlatform.instance.getPlatformVersion(); } Future<T?> open<T extends Object?>(context, path, {Object? arguments}) async { final bool useFlutterPage = RouterManager.instance.hasRouterWidget(path); if(useFlutterPage){ debugPrint("FlutterRouter#open 打开 flutter"); Widget target = RouterManager.instance.getRouterWidget(path,params: arguments); return Navigator.of(context).push(MaterialPageRoute( builder: (context) => target, ),); } else { debugPrint("FlutterRouter#open 打开 native"); return FlutterRouterPlatform.instance .open<T>(path, arguments: arguments) .then((value) { return value; }); } } }
|
之后我们在之前使用的LoginPage
页面中调用一下这个方法:
1 2 3 4 5 6 7 8 9 10 11 12
| ElevatedButton( onPressed: () { FlutterRouter().open(context, 'pages/flutter/FromFlutterPage', arguments: { 'name': 'flutter_harmony', 'age': 3 }); }, child: const Text("FromFlutterPage", style: TextStyle(fontSize: 16, color: Color(0xff333333))), ),
|
看一下效果

总结一下
- flutter打开页面时,调用
FlutterRouter#open
方法,
- 在该方法中判断目标页面是 flutter 页面还是 native 页面
- 如果是 native 页面,则通过 methodChannel 调用 native 方法
- 最终调用的 native 方法由宿主原生工程中设置,由宿主原生工程来打开对应页面