Flutter 三方库 flutter_web_browser 的鸿蒙适配教程

本文配套仓库:https://atomgit.com/oh-flutter/flutter_web_browser(TAG:0.17.3-ohos-1.0.0-beta.1,分支:feat/ohos_flutter_web_browser_0.17.3)。插件的接口用法、参数说明与业务侧最佳实践,见配套的《给鸿蒙 App 增加打开外部网页能力 —— flutter_web_browser 的鸿蒙使用指南》;本文解决的是另一件事:从上游 GitHub 仓库开始,把 flutter_web_browser 完整适配到 OpenHarmony / HarmonyOS 平台,并在真机上验证。

flutter_web_browser 是 pub.dev 上的一个打开网页的 Flutter 插件(作者 Victor Bonnet,MIT 协议,0.17.3,2018 年首发)。它解决的问题是"应用内打开外部网页不想直接跳走":Android 上基于 Chrome Custom Tabs 提供轻量级的内嵌浏览器标签页,iOS 上基于 SFSafariViewController,调用方只需一行 FlutterWebBrowser.openWebPage(url: ...)。它原本只支持 Android 与 iOS,唯独没有鸿蒙;而鸿蒙 Flutter 应用要打开网页,得自己对接 ArkTS 侧的 startAbility 隐式 Want 拉起系统浏览器。本文完整走一遍社区三方库适配的标准流程:把上游仓库同步到 AtomGit,拉到宿主机,建适配分支,用命令自动补全 ohos 目录,补全 Dart 与 ArkTS 两侧实现,补齐适配说明文件后提交分支与 TAG,最后用仓库自带的 example 在鸿蒙真机上验证。

一、环境搭建

鸿蒙 Flutter 开发环境(ohos 版 SDK、DevEco Studio、签名配置)的完整搭建步骤,官方指南已经写得很细,直接照做即可:

Flutter OHOS 开发环境搭建指南

适配工作比单纯使用多一项要求:终端里 flutter 命令必须指向 ohos 版 SDK,因为后文自动补全 ohos 目录靠的是它提供的 flutter create --platforms ohos 能力。环境装好后用 flutter devices 确认能识别鸿蒙真机。本文实测使用的环境:

版本
Flutter(ohos 版)3.41.10-ohos-1.0.1
编译 SDK6.1.0(23)
实测设备HUAWEI ADA-AL10U 真机(nova 12 Ultra 星耀版,HarmonyOS 6.1.0.135 / API 24)

二、适配过程

2.1 将上游仓库同步到 AtomGit

鸿蒙 Flutter 三方库社区(oh-flutter 组织)托管在 AtomGit,上游项目在 GitHub,适配的第一步是把上游代码完整迁入 AtomGit 上为它新建的目标仓库 oh-flutter/flutter_web_browser。做法是把上游克隆下来,添加 AtomGit 远端后整库推送,保留全部 commit 历史与 TAG,后续上游发新版时也能用同样的方式增量同步:

# 克隆上游仓库,目录名与目标仓库保持一致
git clone https://github.com/victorbonnet/flutter_web_browser.git flutter_web_browser
cd flutter_web_browser

# 关联 AtomGit 目标仓库
git remote add atomgit https://atomgit.com/oh-flutter/flutter_web_browser.git

# 推送全部分支与 TAG
git push atomgit --all
git push atomgit --tags

推送完成后,打开 AtomGit 上目标仓库的页面,能看到与上游一致的提交历史和源码目录:

在这里插入图片描述

图一:同步完成后 AtomGit 目标仓库的代码页

2.2 拉取代码到宿主机

从目标仓库把代码拉到本地,后续所有操作都在这份代码上进行:

git clone https://atomgit.com/oh-flutter/flutter_web_browser.git
cd flutter_web_browser

此时的目录是上游的原始结构。flutter_web_browser 是标准的单包插件,所有平台实现与 Dart 接口都在仓库根目录:

flutter_web_browser/
├── android/                # Android 平台实现(Chrome Custom Tabs)
├── ios/                    # iOS 平台实现(SFSafariViewController)
├── lib/
│   └── flutter_web_browser.dart   # Dart 接口:FlutterWebBrowser 类与两个 Options 类
├── example/                # 上游自带示例工程
├── CHANGELOG.md
├── LICENSE                 # MIT
├── README.md
└── pubspec.yaml

注意看:目录里有 android/ios/,没有 ohos/,pubspec 的插件注册节点里也只有 android 与 ios 两个平台——这就是适配要补的部分。

在这里插入图片描述

图二:clone 完成后的仓库原始目录

2.3 创建适配分支并补全 ohos 目录结构

先建适配分支。社区约定分支名为 feat/ohos_<库名>_<版本号>,版本号取自上游 pubspec 里的 version: 0.17.3

git checkout -b feat/ohos_flutter_web_browser_0.17.3

接下来一条命令补全 ohos 目录。flutter create --platforms ohos . 是 ohos 版 Flutter SDK 提供的能力:读取当前目录 pubspec 的包名与插件声明,自动生成鸿蒙平台目录并追加注册节点:

flutter create --platforms ohos .

命令执行后,仓库里多出一个 ohos/ 目录,pubspec.yaml 也被自动改了两处。生成的目录结构如下:

ohos/
├── src/main/ets/components/plugin/
│   └── FlutterWebBrowserPlugin.ets   # 插件模板:ArkTS 实现入口,此刻是空的
├── src/main/module.json5             # 模块配置
├── index.ets                         # 插件导出入口
├── oh-package.json5                  # 包描述:name / version / main / 对 flutter.har 的依赖
└── build-profile.json5               # 构建配置

各文件的职责:index.ets 把插件类导出给引擎侧;oh-package.json5 声明这是一个依赖 @ohos/flutter_ohos(引擎 HAR 包)的 ArkTS 包;module.json5 是模块清单;FlutterWebBrowserPlugin.ets 是 flutter create 生成的插件模板,只有空壳生命周期方法,真正要写的代码全在这个文件里,2.4 节补全它。pubspec.yaml 自动追加的注册节点:

flutter:
  plugin:
    platforms:
      android:
        package: dev.vbonnet.flutterwebbrowser
        pluginClass: FlutterWebBrowserPlugin
      ios:
        pluginClass: FlutterWebBrowserPlugin
      ohos:                                 # 新增
        package: com.example.flutter_web_browser
        pluginClass: FlutterWebBrowserPlugin

flutter create 还会把 Dart SDK 约束放宽一档(上游 >=2.12.0 <3.0.0,生成后为 >=2.12.0 <4.0.0),以兼容当前 ohos 版 SDK 的 Dart 版本。

在这里插入图片描述

图三:命令输出与生成的 ohos 目录

2.4 在插件文件中补全 ohos 实现

先看改动全景。整个适配在插件侧只改了一个 Dart 文件、一个 pubspec 注册节点,外加新增的 ohos 目录:

文件改动内容
lib/flutter_web_browser.dart加法新增 kIsWeb 导入、_isOhos 判断、openWebPage 的鸿蒙分支
pubspec.yaml加法ohos 注册节点与 SDK 约束放宽(2.3 已完成)
ohos/新增ArkTS 插件实现(2.3 生成模板,本节补全)
说明文件四份新增2.5 节补全

原有 Android 与 iOS 的实现一行未动——所有平台分支都是"只加不改",这是鸿蒙适配对上游与使用方的双向承诺。

Dart 侧改动集中在 lib/flutter_web_browser.dartFlutterWebBrowser 类里,一共三处:

import 'package:flutter/foundation.dart' show kIsWeb;

/// Whether the current platform is OpenHarmony.
static bool get _isOhos => !kIsWeb && Platform.operatingSystem == 'ohos';

static Future<void> openWebPage({
  required String url,
  CustomTabsOptions customTabsOptions = const CustomTabsOptions(),
  SafariViewControllerOptions safariVCOptions =
      const SafariViewControllerOptions(),
}) {
  // On OpenHarmony the page is opened with the system browser, so the
  // Custom Tabs / SFSafariViewController options are not applicable.
  if (_isOhos) {
    return _channel.invokeMethod('openWebPage', {'url': url});
  }

  // ……以下为上游原有的 android_options / ios_options 组装逻辑,未动
}

三个决策值得展开。第一,为什么用 Platform.operatingSystem == 'ohos' 判断:Flutter 鸿蒙 SDK 在鸿蒙设备上运行时,operatingSystem 返回 'ohos',此时上游代码里的 Platform.isAndroidPlatform.isIOS 都是 false。前置的 !kIsWeb 是硬约束——Web 平台没有 dart:ioPlatform 一访问就抛异常,必须先短路。第二,为什么新增独立分支而不是复用 Android 分支:上游会把 Custom Tabs 的配色、分享等选项组装进 android_options / ios_options 一并传给通道,而鸿蒙 native 侧只解析 url;走独立分支让通道消息只带 url,native 侧解析逻辑保持最简,代码意图也明确——鸿蒙系统浏览器不支持这些定制。第三,返回值语义:上游 Android 在 launchUrl 成功后 result.success(null),返回 Future<void>;鸿蒙分支的 invokeMethod 成功时同样以 null 完成 Future,调用方在各平台拿到的语义一致。

ArkTS 侧是本次适配的主体,补全 ohos/src/main/ets/components/plugin/FlutterWebBrowserPlugin.ets,实现 FlutterPluginMethodCallHandlerAbilityAware 三个接口。第一段是生命周期与通道注册:

export default class FlutterWebBrowserPlugin implements FlutterPlugin, MethodCallHandler, AbilityAware {
  private static readonly CHANNEL_NAME: string = 'flutter_web_browser';
  private channel: MethodChannel | null = null;
  private ability: UIAbility | null = null;

  onAttachedToEngine(binding: FlutterPluginBinding): void {
    this.channel = new MethodChannel(
      binding.getBinaryMessenger(),
      FlutterWebBrowserPlugin.CHANNEL_NAME,
      StandardMethodCodec.INSTANCE
    );
    this.channel.setMethodCallHandler(this);
  }

  // AbilityAware:持有 UIAbility,后续 startAbility 要用它的 context
  onAttachedToAbility(binding: AbilityPluginBinding): void {
    this.ability = binding.getAbility();
  }

  onMethodCall(call: MethodCall, result: MethodResult): void {
    try {
      switch (call.method) {
        case 'openWebPage': {
          this.openWebPage(call, result);
          break;
        }
        case 'warmup': {
          // 打开系统浏览器无需预热,与上游 iOS 实现一致恒返回 true
          result.success(true);
          break;
        }
        default: {
          result.notImplemented();
          break;
        }
      }
    } catch (err) {
      result.error('no_activity', 'Failed to handle method call', null);
    }
  }
}

通道名沿用上游约定俗成的 flutter_web_browseronAttachedToEngine 只负责注册通道,真正干活的 UIAbilityonAttachedToAbility 里拿到——鸿蒙侧拉起浏览器必须用 UIAbilityContext,这个 context 只能从 Ability 生命周期来,两个生命周期缺一不可。

第二段是 openWebPage 的参数校验与 want 组装:

private openWebPage(call: MethodCall, result: MethodResult): void {
  const url: string | undefined = call.argument('url');
  if (url == undefined || url.length === 0) {
    result.error('invalid_url', 'openWebPage requires a non-empty "url" string argument', null);
    return;
  }
  if (this.ability == null) {
    // 错误码与上游 Android 实现(MethodCallHandlerImpl)保持一致
    result.error('no_activity', 'Plugin is only available within an activity context', null);
    return;
  }
  const context = this.ability.context as common.UIAbilityContext;
  // MethodResult 只允许回复一次;startAbility 的 Promise 回调与同步异常
  // 可能先后触发,用标志位保证只回复一次
  let replied: boolean = false;
  const replyOnce = (): void => {
    if (!replied) {
      replied = true;
      result.success(null);
    }
  };
  const replyError = (message: string, details: string): void => {
    if (!replied) {
      replied = true;
      // 错误码与上游 Android 的 no_activity 语义对齐:无法打开网页
      result.error('no_activity', message, details);
    }
  };
  try {
    // 官方推荐拉起浏览器方式:viewData action + browsable entity
    const want: Want = {
      action: 'ohos.want.action.viewData',
      entities: ['entity.system.browsable'],
      uri: url
    };
    context.startAbility(want).then((): void => {
      // 对齐上游 Android:launchUrl 成功后 result.success(null)
      replyOnce();
    }).catch((err: BusinessError): void => {
      replyError(`Failed to open ${url}: ${err.message}`, `${err.code}`);
    });
  } catch (err) {
    replyError(`Failed to open ${url}`, '');
  }
}

这段里两个点最值得说。其一,want 的组装方式:action: 'ohos.want.action.viewData'entities: ['entity.system.browsable']uri,是鸿蒙官方推荐的"拉起浏览器打开网页"隐式 Want 写法——系统按 entity 筛出所有声明了可浏览能力的应用,默认浏览器排在最前。URL 原样透传,不做任何加工。其二,replyOnce 标志位:startAbility 返回 Promise,thencatch 是异步回调路径,外层 try/catch 是同步异常路径,两条路径可能先后触发;而 MethodResult 只允许回复一次,重复回复会直接导致引擎断言崩溃。标志位把所有回复路径互斥成"第一次生效、其余丢弃",这是 ArkTS 侧拉起系统能力的插件通用套路。

错误码与上游 Android 实现对齐:url 为空报 invalid_url,插件未挂接到 UIAbility 或拉起失败报 no_activity——业务代码的 onError 判断在各平台写法一致。

warmup 一行 result.success(true) 是刻意为之:上游 iOS 的 warmup 用于预热 SFSafariViewController 服务,Android 实现为恒 true 的空操作;鸿蒙拉起系统浏览器同样无需预热,恒 true 让"调用 warmup 后再 openWebPage"的既有代码模式在鸿蒙上原样成立。closeevents 上游仅 iOS 实现,Dart 侧本就有 Platform.isIOS 守卫,鸿蒙上根本不会发起这两个调用,native 侧 default 分支的 notImplemented 只是防御性兜底。

2.5 补全适配说明文件并提交分支

插件实现完成后,在仓库根目录补齐四份适配说明文件:

README.OpenSource            # 开源说明(Name / License / Version Number / Owner / Upstream URL)
README.OpenHarmony_CN.md     # 中文使用说明:简介、下载安装、约束与限制、使用示例、接口说明、新增特性、遗留问题等
README.OpenHarmony.md        # 英文使用说明
CHANGELOG.OpenHarmony.md     # 鸿蒙适配变更记录与验证环境

README.OpenSource 是社区合规检查的第一站,实际内容:

[
  {
    "Name": "flutter_web_browser",
    "License": "MIT License",
    "License File": "LICENSE",
    "Version Number": "0.17.3",
    "Owner": "qiaomu8559968@126.com",
    "Upstream URL": "https://github.com/victorbonnet/flutter_web_browser",
    "Description": "A Flutter plugin to open a web page with Chrome Custom Tabs (Android) & SFSafariViewController (iOS). This repository adds OpenHarmony platform support on top of the original library."
  }
]

CHANGELOG.OpenHarmony.md 记录这个 TAG 相对上游的变化与验证环境:

## 0.17.3-ohos-1.0.0-beta.1

* Adapted flutter_web_browser 0.17.3 for the OpenHarmony platform: `openWebPage` now opens
  the URL in the system browser via `startAbility` (`ohos.want.action.viewData` action +
  `entity.system.browsable` entity), `warmup` returns `true` as a no-op, and `close`/`events`
  remain iOS-only per the upstream Dart guards.
* Requires the ohos-flavored Flutter SDK (verified with 3.41.10-ohos-1.0.1).

README.OpenHarmony_CN.md 里的"遗留问题"一节值得认真写:UI 定制参数在鸿蒙系统浏览器上不生效、拉起的是完整浏览器窗口而非应用内轻量视图、close/events 保持与 Android 一致的行为——这三条是使用方一定会遇到的行为差异,提前写清楚能省掉大量 Issue 往返。最后提交代码并打 TAG:

# 插件侧适配改动(ohos 目录、Dart 鸿蒙分支、pubspec 注册节点与四份说明文件)
git add ohos lib/flutter_web_browser.dart pubspec.yaml \
  README.OpenSource README.OpenHarmony_CN.md README.OpenHarmony.md CHANGELOG.OpenHarmony.md
git commit -m "feat: adapt flutter_web_browser for the OpenHarmony platform"

# example 的适配改动单独提交
git add example
git commit -m "feat: rework example app as a dedicated flutter_web_browser demo"

# TAG 命名规则:原库版本-ohos-版本号-beta.x
git tag 0.17.3-ohos-1.0.0-beta.1

# 推送分支与 TAG 到 AtomGit
git push atomgit feat/ohos_flutter_web_browser_0.17.3
git push atomgit 0.17.3-ohos-1.0.0-beta.1

TAG 是后续使用方以 git 依赖引入时的版本锚点,TAG 名、README 与 CHANGELOG 三处保持一致,推完 TAG 适配的代码部分就完成了。

在这里插入图片描述
在这里插入图片描述

图四:适配分支与 TAG 推送到 AtomGit

三、在 Demo 中验证适配效果

3.1 使用仓库自带的 example

上游 example 位于仓库根的 example/,本就覆盖了插件全部能力:预热浏览器、直接打开网页、打开网页 5 秒后关闭,以及 Android 与 iOS 各自的定制参数演示段。适配期间为 example 补了两件事:其一,在 example 下执行 flutter create --platforms ohos 生成鸿蒙宿主工程;其二,main.dart 增加鸿蒙演示分支——新增一个"Open Flutter website (options ignored on OHOS)"按钮验证定制参数被忽略的场景,并用 _supportsBuiltInBrowser 守卫把 Custom Tabs 相关的演示逻辑限定在 Android 与 iOS:

/// Chrome Custom Tabs / SFSafariViewController only exist on Android & iOS.
/// On OpenHarmony the page always opens with the system browser and the
/// events stream is not available.
bool get _supportsBuiltInBrowser => Platform.isAndroid || Platform.isIOS;

// 界面底部按平台渲染 ohos 演示段
if (Platform.operatingSystem == 'ohos') ...[
  Text('test OpenHarmony'),
  ElevatedButton(
    onPressed: () {
      // On OpenHarmony the page always opens with the system
      // browser, so the Custom Tabs options are ignored.
      FlutterWebBrowser.openWebPage(
        url: "https://flutter.io/",
        customTabsOptions: CustomTabsOptions(
          colorScheme: CustomTabsColorScheme.dark,
          showTitle: true,
          urlBarHidingEnabled: true,
        ),
      );
    },
    child: Text('Open Flutter website (options ignored on OHOS)'),
  ),
],

进入 example 目录构建 hap:

cd example
flutter pub get
flutter build hap --debug

构建产物在 build/ohos/hap/entry-default-signed.hap。安装需要签名:用 DevEco Studio 打开 example 的 ohos 工程,在 File > Project Structure > Signing Configs 里勾选 Automatically generate signature 配置调试签名,签名信息由工具自动注入 build-profile.json5。装到设备并启动:

hdc install -r build/ohos/hap/entry-default-signed.hap
hdc shell aa start -b com.example.demo -a EntryAbility

启动后主界面顶部显示 “Running on ohos”,下方依次是预热按钮、两个打开网页按钮与 ohos 演示段:

在这里插入图片描述

图五:example 启动后的主界面(HUAWEI ADA-AL10U 真机)

3.2 自建工程时以 AtomGit 链接方式引入

不用 example、在自己的工程里验证的话,按 git 依赖方式引入即可,url、ref 两项直接用本文开头的仓库地址与 TAG。完整的引入步骤、参数说明与业务实战,见姊妹篇《flutter_web_browser 的鸿蒙使用指南》第四章,此处不展开。TAG 与框架版本的对应关系:

Flutter 框架版本TAG 名称分支名
3.41.100.17.3-ohos-1.0.0-beta.1feat/ohos_flutter_web_browser_0.17.3

兼容性说明:stable 引擎(3.41.10-ohos-1.0.1)配编译 SDK 6.1.0(23) 在 HarmonyOS 6.1 真机实测通过;canary 引擎(3.44 canary)的 ArkTS 层要求 API 26,宿主工程的 compatibleSdkVersion 需改回 "26.0.0" 才能构建。

3.3 调用接口并观察真机运行效果

example 里最核心的调用只有一行:

await FlutterWebBrowser.openWebPage(url: "https://flutter.io/");

点击"Open Flutter website",系统浏览器被拉起,地址栏载入 flutter.io:

在这里插入图片描述

图六:点击按钮后系统默认浏览器被拉起

页面随后重定向到 flutter.dev 并完整渲染,"Build for any screen"标题可见——从 Dart 一行调用到网页呈现的全链路打通:

在这里插入图片描述

图七:flutter.dev 在系统浏览器中渲染完成

点击"Warmup browser website"验证预热接口:应用界面无任何变化、无崩溃,warmup() 的 Future 以 true 正常完成。这正是预期的语义——鸿蒙拉起系统浏览器无需预热,恒 true 让"先预热再打开"的既有代码模式原样成立:

在这里插入图片描述

图八:点击预热按钮后应用前台无变化

ohos 演示段的按钮验证定制参数场景:调用时传入 CustomTabsOptions(colorScheme: dark, showTitle: true, urlBarHidingEnabled: true),浏览器正常拉起、参数不产生任何 UI 效果、也不报错——鸿蒙系统浏览器的外观不可由调用方定制,参数被静默忽略属于设计内行为。

closeevents 在真机上无需验证:上游仅 iOS 实现,Dart 侧 Platform.isIOS 守卫保证鸿蒙上调用是空操作与空流,example 也用 _supportsBuiltInBrowser 把事件订阅限定在了 iOS。

到这里适配完成度就有了实测背书:openWebPage 全链路可用,拉起、加载、重定向一路正常,成功时 Future 正常完成、失败抛 no_activity 的 PlatformException,语义与上游 Android 一致;warmup 语义正确;close / events 保持与 Android 相同的空操作与空流;唯一的受限点是 UI 定制参数不生效,这是系统浏览器形态决定的,已如实记入 README 遗留问题。

四、常见问题

4.1 适配过程中的问题

Q1:flutter create --platforms ohos . 该在哪些目录执行?

flutter_web_browser 是单包插件,与联邦插件不同,只需要执行两次:插件根目录一次(生成插件的 ohos/ 适配层与 pubspec 注册节点),example/ 下一次(生成示例工程的鸿蒙宿主,供 flutter build hap 构建)。两次产物角色不同,都不能省。

Q2:compatibleSdkVersion 怎么填?

带括号的旧版格式与数值都要和目标设备对上。本文用 "6.1.0(23)":API 23 对应 ROM 6.1.0,不高于实测真机的 API 24,安装正常。若填得比设备 API 高(比如模拟器用的 "26.0.0"),真机安装会报"此应用暂不支持在当前设备安装";反过来用 canary 引擎构建时 ArkTS 层要求 API 26,又要改回 "26.0.0"。原则:stable 引擎配真机取设备 API 之下的最近版本,canary 引擎取 26。

Q3:ArkTS 侧 result.success 被调用两次导致崩溃?

startAbility 返回 Promise,then / catch 异步回调与外层同步 catch 可能先后触发,而 MethodResult 只允许回复一次。参照 2.4 的实现,用 replied 标志位包裹所有回复路径(replyOnce / replyError),第一次结果生效后其余丢弃。

Q4:构建出的 hap 装不上?

hap 必须签名才能安装。用 DevEco Studio 打开工程配置调试签名即可;注意调试签名 profile 与 bundleName 绑定,若借用其他工程的签名材料,需将 AppScope/app.json5 的 bundleName 改成与 profile 一致(本文 example 为 com.example.demo)。签名信息由工具自动注入 build-profile.json5,这部分改动不必提交入库。

4.2 使用过程中的问题

Q1:为什么打开的是完整浏览器窗口,而不是应用内的轻量标签页?

Chrome Custom Tabs 是 Android 独有的系统能力(宿主应用内嵌一个可定制的浏览器标签页),鸿蒙侧没有对应物,插件通过隐式 Want 拉起的是系统默认浏览器的完整窗口。这是平台形态差异,不是适配缺陷;如果业务必须应用内浏览,鸿蒙侧应改用 Web 组件类方案。

Q2:从网页按返回键,为什么回到了浏览器首页而不是我的应用?

实测发现从拉起的网页按返回,落在华为浏览器自己的首页而非发起调用的应用——浏览器把返回键当作自身页面导航历史处理了。发起调用的应用并没有被销毁,从任务中心切回或重新调起即可。这不影响 openWebPage 的返回值语义(Future 在拉起成功时就已完成)。

Q3:打开 flutter.dev 出现"疑似诈骗"红色横幅?

华为浏览器的防诈骗系统会按站点标记风险提示,flutter.dev 被标记时页面顶部会出现红色横幅,重试也依然存在。这是设备系统对特定站点的行为,与插件无关——换成自家业务 URL 不会出现。适配验证时若选 flutter.io / flutter.dev 这类测试站点遇到横幅,属正常现象。

Q4:customTabsOptions 传了没效果?

设计如此。鸿蒙系统浏览器的外观不可由调用方定制,所有 UI 定制参数被静默忽略(不报错、不崩溃),仅 url 生效。跨平台代码不需要为鸿蒙删掉参数——上游接口签名原样可用,这也是"一套代码跑多端"的前提。

Q5:openWebPage() 正常返回就代表用户看完网页了吗?

正常返回只代表"系统浏览器拉起成功",用户何时关闭、有没有看,鸿蒙侧没有任何回调能感知——events 事件流仅上游 iOS 支持。需要感知关闭行为的业务,在鸿蒙侧应改用 Web 组件内嵌方案或自行设计流程。

五、结语

回顾整条适配链路:上游仓库同步进 AtomGit 保住历史;flutter create --platforms ohos . 一条命令补全目录与注册节点;改动只落在 Dart 侧的一个平台判断分支与 ArkTS 侧的一个插件文件里,startAbility 隐式 Want 加上 replyOnce 互斥,就把上游 openWebPage / warmup 的语义完整搬到了鸿蒙;四份说明文件交代清楚适配行为与遗留差异,分支与 TAG 按社区规范提交发布。原库的接口签名与异常语义原封未动,这正是"只做加法"的适配给使用方的承诺。

使用中发现问题,欢迎到 flutter_web_browser 鸿蒙仓库提 Issue(鸿蒙适配层,标题建议 [Bug] 一句话现象,附上复现步骤、期望与实际结果、设备与系统版本、Flutter 鸿蒙 SDK 版本及日志截图),插件上游行为的问题到原库 GitHub 仓库反馈,修复代码欢迎发 PR。接口的完整用法、参数表与业务侧最佳实践,见姊妹篇《flutter_web_browser 的鸿蒙使用指南》。

六、相关链接

欢迎加入 CPF-Flutter 鸿蒙社区,社区入口、环境搭建指南和本文相关链接统一放在这里:

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐