鸿蒙-flutter-使用FlutterEntry的路由管理和参数传递_中_flutter打开native页面传递参数

前言

前面我们完成了鸿蒙打开flutter指定页面,并且传递参数,接下来我们看一下在flutter侧打开鸿蒙原生页面,并且传递参数应该如何处理。 当然了,我们在前面也提到了,在flutter发起路由的时候,都交给插件来处理。并且我们在上一章中也创建好了flutter插件,并没有使用和原生交互,只是创建了一个flutter路由和页面映射的管理类。

创建插件

这里为了简单,我们在my_flutter_module下新建一个plugins文件,将插件工程放在这个文件夹下。

shell 复制代码
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中添加引用

yaml 复制代码
dependencies:
  flutter_router: 
    path: plugins/flutter_router

flutter打开native

这里需要用到和native通信了。前面也提到过,当flutter发起路由时,先判断目标页面是不是flutter页面,是的话用flutter中的Navigator打开,否则调用channel通知原生打开。

因为打开原生页面有时候也需要传递一些参数,我们在FlutterRouterPlatform中定义这么一个方法:

dart 复制代码
Future<T> open<T extends Object?>(url, {dynamic arguments}) {
  throw UnimplementedError('open() has not been implemented.');
}

然后我们在MethodChannelFlutterRouter中实现这个方法:

dart 复制代码
  @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;
  }

看着代码挺多,实际上只是把urlarguments这两个参数打包到了args里面,通过methodChannel传给原生。

原生侧处理

这里我们可以使用DevEco打开插件目录下的ohos文件夹,把它当作一个鸿蒙工程。或者简单点,直接在当前工程中编辑也行。只是方法提示不太友好,我们可以把ohos工程中的FlutterRouterPlugin文件直接复制到当前鸿蒙工程中,编辑完后再复制回去。 我们看下FlutterRouterPlugin应该如何处理。 考虑到我们是传入的路径,也是打算注册路径和关联页面,但考虑到我们的实际业务情况,就开放了一个处理接口,由native侧设置,当触发打开native页面时,由native来处理

TypeScript 复制代码
import {
  FlutterPlugin,
  FlutterPluginBinding,
  MethodCall,
  MethodCallHandler,
  MethodChannel,
  MethodResult,
} from '@ohos/flutter_ohos';

/** FlutterRouterPlugin **/
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的情况

TypeScript 复制代码
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 "无参数"
    }
  }
}

然后我们在EntryAbilityonCreate方法中设置一下routerPushHandler

TypeScript 复制代码
    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 页面的方法

dart 复制代码
bool hasRouterWidget(String path) {
  final String routerName = _getRouterName(path);
  return _routerMap.containsKey(routerName);
}

然后我们在FlutterRouter写一下对应的打开页面的方法:

dart 复制代码
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,
      ),);
      // return Navigator.of(context).pushNamed(path, arguments: arguments);
    } else {
      // 打开native页面: path已在native端注册
      debugPrint("FlutterRouter#open 打开 native");
      return FlutterRouterPlatform.instance
          .open<T>(path, arguments: arguments)
          .then((value) {
        return value;
      });
    }
  }
}

之后我们在之前使用的LoginPage页面中调用一下这个方法:

dart 复制代码
ElevatedButton(
  onPressed: () {
    //HMRouterAPage
    FlutterRouter().open(context, 'pages/flutter/FromFlutterPage',
        arguments: {
          'name': 'flutter_harmony',
          'age': 3
        });
  },
  child: const Text("FromFlutterPage",
      style: TextStyle(fontSize: 16, color: Color(0xff333333))),
),

看一下效果

总结一下

  1. flutter打开页面时,调用FlutterRouter#open方法,
  2. 在该方法中判断目标页面是 flutter 页面还是 native 页面
  3. 如果是 native 页面,则通过 methodChannel 调用 native 方法
  4. 最终调用的 native 方法由宿主原生工程中设置,由宿主原生工程来打开对应页面
相关推荐
颜颜颜yan_2 小时前
【HarmonyOS5】掌握UIAbility启动模式:Singleton、Specified、Multiton
后端·架构·harmonyos
二蛋和他的大花3 小时前
HarmonyOS运动开发:深度解析文件预览的正确姿势
华为·harmonyos
无知的前端3 小时前
Flutter开发,GetX框架路由相关详细示例
android·flutter·ios
长弓三石4 小时前
鸿蒙网络编程系列53-仓颉版TCP连接超时分析示例
前端·harmonyos
libo_20254 小时前
DevEco Studio测试用例录制功能详解(HarmonyOS 5)
harmonyos
lewis_dys4 小时前
微信内引导用户使用“在浏览器打开”开发参考
harmonyos
zhanshuo5 小时前
告别卡顿!鸿蒙新闻列表流畅滚动优化全攻略
harmonyos
zhanshuo5 小时前
鸿蒙开发者必看!三步搞定动态权限请求,告别用户权限流失
harmonyos
王二蛋与他的张大花5 小时前
HarmonyOS运动开发:深度解析文件预览的正确姿势
harmonyos
TRockBots6 小时前
三、DevEco Studio安装和HelloWorld应用
harmonyos