鸿蒙-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 方法由宿主原生工程中设置,由宿主原生工程来打开对应页面
相关推荐
江上清风山间明月6 小时前
Flutter AlwaysScrollableScrollPhysics详解
flutter·滚动·scrollable·scrollphysics
小小小小小星6 小时前
鸿蒙开发核心功能模块全解析:从架构到实战应用
harmonyos
奶糖不太甜7 小时前
鸿蒙开发问题之纯血鸿蒙自启动步骤详解
harmonyos
普罗米拉稀7 小时前
Flutter 复用艺术:Mixin 与 Abstract 的架构哲学与线性化解密
flutter·ios·面试
yangshuo128111 小时前
AI编程工具对决:Kilo vs Augment 开发Flutter俄罗斯方块游戏实战对比
flutter·游戏·ai编程
xq952711 小时前
鸿蒙next 获取versionCode和versionName
harmonyos
鸿蒙小白龙12 小时前
openharmony之恢复出厂设置需求总结
harmonyos·鸿蒙·鸿蒙系统
深海的鲸同学 luvi13 小时前
【HarmonyOS】H5 实现在浏览器中正常跳转 AppLinking 至应用
华为·harmonyos
tangweiguo0305198714 小时前
Flutter 自定义 Switch 切换组件完全指南
flutter
zhanshuo1 天前
HarmonyOS 实战:学会在鸿蒙中使用第三方 JavaScript 库(附完整 Demo)
harmonyos