前言

欢迎来到 Flutter三方库适配OpenHarmony 系列文章!本系列围绕 flutter_libphonenumber 这个 电话号码处理库 的鸿蒙平台适配,进行全面深入的技术分享。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

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

上一篇我们解析了联合插件的架构设计。本篇将 手把手 讲解鸿蒙平台插件包 flutter_libphonenumber_ohos 的完整创建过程,包括目录结构、pubspec.yaml 配置、ohos/ 原生目录的组织方式、dartPluginClass 注册机制,以及 GeneratedPluginRegistrant 的自动生成原理。

掌握了插件包的创建与注册流程,你就能为任何 Flutter 三方库创建鸿蒙平台实现包。这是鸿蒙适配的 实操核心


一、插件包的完整目录结构

1.1 顶层目录

flutter_libphonenumber_ohos 插件包的完整目录结构如下:

flutter_libphonenumber_ohos/
├── lib/
│   └── flutter_libphonenumber_ohos.dart      # Dart 侧实现
├── ohos/
│   ├── src/main/
│   │   ├── ets/components/plugin/
│   │   │   ├── FlutterLibphonenumberPlugin.ets  # ArkTS 插件入口
│   │   │   └── PhoneNumberUtil.ets              # ArkTS 核心工具类
│   │   └── module.json5                         # 模块配置
│   ├── oh-package.json5                         # 鸿蒙包配置
│   ├── build-profile.json5                      # 构建配置
│   ├── hvigorfile.ts                            # 构建脚本
│   ├── index.ets                                # 包入口文件
│   └── BuildProfile.ets                         # 构建变量
├── example/                                     # 演示工程
│   ├── lib/main.dart
│   └── ohos/                                    # 鸿蒙原生工程
├── pubspec.yaml                                 # Flutter 包配置
└── pubspec_overrides.yaml                       # 本地依赖覆盖

1.2 目录职责划分

目录/文件 层级 职责
lib/ Dart 侧 包含 Dart 平台实现类,通过 MethodChannel 与原生侧通信
ohos/ 原生侧 包含 ArkTS 原生代码和鸿蒙工程配置
ohos/src/main/ets/ 原生侧 ArkTS 源代码目录
ohos/oh-package.json5 原生侧 鸿蒙包的元数据和依赖声明
ohos/module.json5 原生侧 模块类型和设备类型声明
ohos/index.ets 原生侧 包的入口文件,导出插件类
example/ 演示 完整的演示工程,用于测试和展示
pubspec.yaml 配置 Flutter 包的核心配置文件

关键区别:与 Android 插件的 android/ 目录和 iOS 插件的 ios/ 目录类似,鸿蒙插件使用 ohos/ 目录存放原生代码。但鸿蒙使用的是 ArkTS 语言和 HAR(Harmony Archive)模块类型。


二、pubspec.yaml 核心配置

2.1 完整配置文件

pubspec.yaml 是 Flutter 包的核心配置文件,它告诉 Flutter 框架如何识别和加载这个插件:

name: flutter_libphonenumber_ohos
description: OpenHarmony implementation of the flutter_libphonenumber plugin.
repository: https://github.com/bottlepay/flutter_libphonenumber/tree/main/packages/flutter_libphonenumber_ohos
issue_tracker: https://github.com/bottlepay/flutter_libphonenumber/issues
version: 1.0.0

environment:
  sdk: ">=2.19.0 <4.0.0"
  flutter: ">=3.0.0"

flutter:
  plugin:
    implements: flutter_libphonenumber
    platforms:
      ohos:
        package: com.bottlepay.flutter_libphonenumber
        pluginClass: FlutterLibphonenumberPlugin
        dartPluginClass: FlutterLibphonenumberOhos

dependencies:
  flutter:
    sdk: flutter
  flutter_libphonenumber_platform_interface: ^2.1.0

dev_dependencies:
  flutter_test:
    sdk: flutter
  plugin_platform_interface: ^2.0.2

2.2 flutter.plugin 配置详解

flutter.plugin 节点是插件注册的核心,每个字段都有特定含义:

flutter:
  plugin:
    implements: flutter_libphonenumber        # ① 声明实现的插件
    platforms:
      ohos:                                   # ② 目标平台
        package: com.bottlepay.flutter_libphonenumber  # ③ 原生包名
        pluginClass: FlutterLibphonenumberPlugin       # ④ ArkTS 入口类
        dartPluginClass: FlutterLibphonenumberOhos     # ⑤ Dart 入口类

各字段详细说明:

字段 说明
implements flutter_libphonenumber 声明本包是哪个插件的平台实现
platforms.ohos - 声明支持 OpenHarmony 平台
package com.bottlepay.flutter_libphonenumber 原生侧的包标识符
pluginClass FlutterLibphonenumberPlugin ArkTS 侧的插件入口类名
dartPluginClass FlutterLibphonenumberOhos Dart 侧的平台实现类名

2.3 implements 的作用

implements 字段建立了 平台包主包 之间的关联:

flutter_libphonenumber_ohos
    │
    │  implements: flutter_libphonenumber
    │
    ▼
flutter_libphonenumber(主包)
    │
    │  依赖
    │
    ▼
flutter_libphonenumber_platform_interface(接口包)

当 Flutter 框架在鸿蒙平台上运行时,它会:

  1. 扫描所有依赖包的 pubspec.yaml
  2. 找到 implements: flutter_libphonenumberplatforms 包含 ohos 的包
  3. 自动使用该包作为 flutter_libphonenumber 的鸿蒙平台实现

endorsed 机制:如果主包的 pubspec.yaml 中将鸿蒙包列为依赖,则称为 endorsed(背书)。被背书的平台包会自动被引入,开发者无需手动添加依赖。

2.4 dependencies 依赖关系

dependencies:
  flutter:
    sdk: flutter
  flutter_libphonenumber_platform_interface: ^2.1.0

鸿蒙平台包只依赖两个东西:

  1. flutter SDK — Flutter 框架本身
  2. platform_interface — 平台接口包,提供抽象基类和数据模型

注意:平台包 不依赖主包flutter_libphonenumber),只依赖接口包。这是联合插件架构的关键设计——平台包和主包之间没有直接依赖关系。


三、ohos/ 原生目录详解

3.1 oh-package.json5 — 鸿蒙包配置

oh-package.json5 是鸿蒙原生包的元数据文件,类似于 Node.js 的 package.json

{
  "name": "flutter_libphonenumber_ohos",
  "version": "1.0.0",
  "description": "OpenHarmony implementation of flutter_libphonenumber",
  "main": "index.ets",
  "author": "",
  "license": "MIT",
  "dependencies": {
    "@ohos/flutter_ohos": "*"
  },
  "devDependencies": {},
  "peerDependencies": {
    "@ohos/flutter_ohos": "*"
  }
}

关键字段说明:

字段 说明
name flutter_libphonenumber_ohos 包名,与 pubspec.yaml 中的 name 一致
main index.ets 包的入口文件
dependencies @ohos/flutter_ohos: * 依赖 Flutter-OHOS 框架
peerDependencies @ohos/flutter_ohos: * 声明为 peer 依赖,避免版本冲突

3.2 index.ets — 包入口文件

index.etsoh-package.json5main 字段指向的入口文件,它的职责是 导出插件类

import FlutterLibphonenumberPlugin
  from './src/main/ets/components/plugin/FlutterLibphonenumberPlugin';

export default FlutterLibphonenumberPlugin;

这个文件只有两行代码,但它是整个原生侧的 入口点。当 GeneratedPluginRegistrant 通过 import FlutterLibphonenumberPlugin from 'flutter_libphonenumber_ohos' 导入时,实际上就是通过这个 index.ets 找到插件类的。

3.3 module.json5 — 模块配置

{
  "module": {
    "name": "flutter_libphonenumber_ohos",
    "type": "har",
    "deviceTypes": [
      "default",
      "tablet"
    ]
  }
}
字段 说明
name flutter_libphonenumber_ohos 模块名称
type har 模块类型为 HAR(Harmony Archive),即库模块
deviceTypes ["default", "tablet"] 支持的设备类型

HAR vs HAPhar 是库模块(类似 Android 的 AAR),用于被其他模块引用;hap 是应用模块(类似 Android 的 APK),可以独立安装运行。插件包使用 har 类型。

3.4 build-profile.json5 — 构建配置

{
  "apiType": "stageMode",
  "buildOption": {
    "arkOptions": {
      "runtimeOnly": {
        "sources": []
      }
    }
  },
  "buildOptionSet": [
    {
      "name": "release",
      "arkOptions": {
        "obfuscation": {
          "ruleOptions": {
            "enable": false,
            "files": []
          }
        }
      }
    }
  ],
  "targets": [
    {
      "name": "default"
    }
  ]
}

关键配置:

  • apiType: "stageMode" — 使用 Stage 模型(鸿蒙推荐的应用模型)
  • obfuscation.enable: false — 关闭代码混淆(开发阶段方便调试)
  • targets — 构建目标,默认只有一个 default

3.5 hvigorfile.ts — 构建脚本

export { harTasks } from '@ohos/hvigor-ohos-plugin';

这是鸿蒙的构建脚本文件,导出 harTasks 表示使用 HAR 模块的标准构建任务。类似于 Android 的 build.gradle 中的 apply plugin: 'com.android.library'

3.6 BuildProfile.ets — 构建变量

export const HAR_VERSION = '1.0.0';
export const BUILD_MODE_NAME = 'debug';
export const DEBUG = true;
export const TARGET_NAME = 'default';

export default class BuildProfile {
  static readonly HAR_VERSION = HAR_VERSION;
  static readonly BUILD_MODE_NAME = BUILD_MODE_NAME;
  static readonly DEBUG = DEBUG;
  static readonly TARGET_NAME = TARGET_NAME;
}

这个文件提供了构建时的变量,可以在代码中通过 BuildProfile.DEBUG 判断当前是否为调试模式。


四、Dart 侧实现文件

4.1 flutter_libphonenumber_ohos.dart

Dart 侧只有一个文件,它的职责是:

  1. 定义 FlutterLibphonenumberOhos 类,继承 FlutterLibphonenumberPlatform
  2. 提供 registerWith() 静态方法用于自动注册
  3. 通过 MethodChannel 实现 4 个抽象方法
import 'package:flutter/services.dart';
import 'package:flutter_libphonenumber_platform_interface/flutter_libphonenumber_platform_interface.dart';

// MethodChannel 通道名称,必须与 ArkTS 侧一致
const _channel = MethodChannel('com.bottlepay/flutter_libphonenumber_ohos');

class FlutterLibphonenumberOhos extends FlutterLibphonenumberPlatform {
  /// 注册为默认平台实现(Flutter 框架自动调用)
  static void registerWith() {
    FlutterLibphonenumberPlatform.instance = FlutterLibphonenumberOhos();
  }

  
  Future<Map<String, String>> format(String phone, String region) async {
    return await _channel.invokeMapMethod<String, String>('format', {
      'phone': phone, 'region': region,
    }) ?? <String, String>{};
  }

  
  Future<Map<String, CountryWithPhoneCode>> getAllSupportedRegions() async {
    final result = await _channel
        .invokeMapMethod<String, dynamic>('get_all_supported_regions') ?? {};
    final returnMap = <String, CountryWithPhoneCode>{};
    result.forEach((k, v) => returnMap[k] = CountryWithPhoneCode(
      countryName: v['countryName'] ?? '',
      phoneCode: v['phoneCode'] ?? '',
      countryCode: k,
      // ... 其他 8 个字段
    ));
    return returnMap;
  }

  
  Future<Map<String, dynamic>> parse(String phone, {String? region}) async {
    return await _channel.invokeMapMethod<String, dynamic>('parse', {
      'phone': phone, 'region': region,
    }) ?? <String, dynamic>{};
  }

  
  Future<void> init({
    Map<String, CountryWithPhoneCode> overrides = const {},
  }) async {
    return CountryManager().loadCountries(
      phoneCodesMap: await getAllSupportedRegions(),
      overrides: overrides,
    );
  }
}

4.2 MethodChannel 通道名称的约定

const _channel = MethodChannel('com.bottlepay/flutter_libphonenumber_ohos');

通道名称必须满足以下要求:

  1. 全局唯一 — 不能与其他插件的通道名称冲突
  2. Dart 侧与 ArkTS 侧一致 — 两端使用完全相同的字符串
  3. 命名规范 — 通常使用 com.公司名/插件名 的格式
通道名称定义位置
Dart 侧 flutter_libphonenumber_ohos.dart 中的 _channel 常量
ArkTS 侧 FlutterLibphonenumberPlugin.ets 中的 CHANNEL_NAME 常量
// ArkTS 侧 — 必须与 Dart 侧完全一致
const CHANNEL_NAME: string = 'com.bottlepay/flutter_libphonenumber_ohos';

五、ArkTS 侧插件入口类

5.1 FlutterLibphonenumberPlugin.ets 完整结构

ArkTS 侧的插件入口类实现了两个接口:FlutterPluginMethodCallHandler

import {
  FlutterPlugin,
  FlutterPluginBinding,
  MethodCall,
  MethodCallHandler,
  MethodChannel,
  MethodResult
} from '@ohos/flutter_ohos';
import { PhoneNumberUtil, RegionInfo, PhoneNumber } from './PhoneNumberUtil';

const TAG: string = 'FlutterLibphonenumberPlugin';
const CHANNEL_NAME: string = 'com.bottlepay/flutter_libphonenumber_ohos';

export default class FlutterLibphonenumberPlugin
  implements FlutterPlugin, MethodCallHandler {

  private channel: MethodChannel | null = null;
  private phoneUtil: PhoneNumberUtil = PhoneNumberUtil.getInstance();

  getUniqueClassName(): string {
    return TAG;
  }

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

  onDetachedFromEngine(binding: FlutterPluginBinding): void {
    if (this.channel !== null) {
      this.channel.setMethodCallHandler(null);
      this.channel = null;
    }
  }

  onMethodCall(call: MethodCall, result: MethodResult): void {
    if (call.method === 'format') {
      this.handleFormat(call, result);
    } else if (call.method === 'parse') {
      this.handleParse(call, result);
    } else if (call.method === 'get_all_supported_regions') {
      this.handleGetAllSupportedRegions(result);
    } else {
      result.notImplemented();
    }
  }
}

5.2 FlutterPlugin 接口

FlutterPlugin 接口定义了插件的 生命周期方法

方法 调用时机 职责
getUniqueClassName() 注册时 返回唯一标识符,用于插件去重
onAttachedToEngine() 引擎绑定时 创建 MethodChannel,设置消息处理器
onDetachedFromEngine() 引擎解绑时 清理 MethodChannel,释放资源

5.3 MethodCallHandler 接口

MethodCallHandler 接口只有一个方法 onMethodCall,负责接收和分发 Dart 侧的调用:

onMethodCall(call: MethodCall, result: MethodResult): void {
  // call.method — 方法名(如 'format'、'parse')
  // call.argument('key') — 获取参数
  // result.success(data) — 返回成功结果
  // result.error(code, msg, detail) — 返回错误
  // result.notImplemented() — 方法未实现
}

5.4 三个方法的分发

插件入口类支持三个 MethodChannel 方法:

方法名 处理函数 功能
format handleFormat() 格式化电话号码
parse handleParse() 解析电话号码
get_all_supported_regions handleGetAllSupportedRegions() 获取所有支持的国家/地区

设计原则:插件入口类只负责 消息分发,具体的业务逻辑委托给 PhoneNumberUtil 工具类。这种分离使得代码职责清晰,便于维护。


六、dartPluginClass 自动注册机制

6.1 注册流程概述

Flutter 框架通过 dartPluginClass 实现了 零配置 的平台注册。整个流程无需开发者手动干预:

  1. Flutter 构建工具扫描所有依赖包的 pubspec.yaml
  2. 找到声明了 dartPluginClass 的包
  3. 在编译时自动生成注册代码
  4. 应用启动时自动调用 registerWith() 方法

6.2 registerWith() 的实现

class FlutterLibphonenumberOhos extends FlutterLibphonenumberPlatform {
  static void registerWith() {
    FlutterLibphonenumberPlatform.instance = FlutterLibphonenumberOhos();
  }
}

这个方法做了三件事:

  1. 创建实例FlutterLibphonenumberOhos() 调用构造函数
  2. Token 验证instance setter 内部调用 PlatformInterface.verifyToken()
  3. 替换默认实现 — 将 _instanceMethodChannelFlutterLibphonenumber 替换为鸿蒙实现

6.3 注册前后的实例变化

注册前:
  FlutterLibphonenumberPlatform.instance
    → MethodChannelFlutterLibphonenumber(默认实现)
    → 通道名:com.bottlepay/flutter_libphonenumber

注册后:
  FlutterLibphonenumberPlatform.instance
    → FlutterLibphonenumberOhos(鸿蒙实现)
    → 通道名:com.bottlepay/flutter_libphonenumber_ohos

关键:注册后,所有通过 FlutterLibphonenumberPlatform.instance 发起的调用都会路由到鸿蒙实现,使用鸿蒙专属的 MethodChannel 通道。


七、GeneratedPluginRegistrant 自动生成

7.1 ArkTS 侧的自动注册

Flutter-OHOS 构建工具会在 example 工程中自动生成 GeneratedPluginRegistrant.ets

import { FlutterEngine, Log } from '@ohos/flutter_ohos';
import FlutterLibphonenumberPlugin from 'flutter_libphonenumber_ohos';

const TAG = "GeneratedPluginRegistrant";

export class GeneratedPluginRegistrant {
  static registerWith(flutterEngine: FlutterEngine) {
    try {
      flutterEngine.getPlugins()?.add(
        new FlutterLibphonenumberPlugin()
      );
    } catch (e) {
      Log.e(TAG,
        "Tried to register plugins with FlutterEngine ("
        + flutterEngine + ") failed.");
      Log.e(TAG, "Received exception while registering", e);
    }
  }
}

7.2 自动生成的触发条件

条件 说明
pubspec.yaml 中声明了 pluginClass 告诉构建工具 ArkTS 侧有插件类需要注册
依赖链中包含该插件包 example 工程直接或间接依赖了插件包
运行 flutter pub get 触发依赖解析和代码生成

7.3 注册链路完整时序

应用启动
    │
    ├── ArkTS 侧注册(原生侧)
    │   ├── 1. FlutterEngine 创建
    │   ├── 2. GeneratedPluginRegistrant.registerWith(engine)
    │   ├── 3. new FlutterLibphonenumberPlugin()
    │   ├── 4. engine.getPlugins().add(plugin)
    │   ├── 5. plugin.onAttachedToEngine(binding)
    │   └── 6. MethodChannel 创建,setMethodCallHandler(this)
    │
    ├── Dart 侧注册(框架侧)
    │   ├── 7. Flutter 框架扫描 dartPluginClass
    │   ├── 8. 调用 FlutterLibphonenumberOhos.registerWith()
    │   └── 9. FlutterLibphonenumberPlatform.instance = 鸿蒙实例
    │
    └── 注册完成
        ├── Dart 侧:instance 指向 FlutterLibphonenumberOhos
        └── ArkTS 侧:MethodChannel 已就绪,等待消息

双端注册:鸿蒙插件需要在 两端 分别注册——ArkTS 侧注册插件到 FlutterEngine(处理原生消息),Dart 侧注册平台实例(路由 API 调用)。两端通过 MethodChannel 通道名称关联。


八、与 Android/iOS 插件创建的对比

8.1 目录结构对比

对比项 Android iOS 鸿蒙(OHOS)
原生目录 android/ ios/ ohos/
源码目录 src/main/kotlin/ Classes/ src/main/ets/
包配置 build.gradle .podspec oh-package.json5
模块配置 AndroidManifest.xml Info.plist module.json5
构建脚本 build.gradle Podfile hvigorfile.ts
入口文件 无(Gradle 自动扫描) 无(podspec 指定) index.ets
实现语言 Kotlin/Java Swift/ObjC ArkTS

8.2 插件接口对比

// Android (Kotlin)
class FlutterLibphonenumberPlugin : FlutterPlugin, MethodCallHandler {
  override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) { }
  override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { }
  override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { }
}

// iOS (Swift)
public class SwiftFlutterLibphonenumberIosPlugin: NSObject, FlutterPlugin {
  public static func register(with registrar: FlutterPluginRegistrar) { }
  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { }
}

// OHOS (ArkTS)
export default class FlutterLibphonenumberPlugin
  implements FlutterPlugin, MethodCallHandler {
  onAttachedToEngine(binding: FlutterPluginBinding): void { }
  onMethodCall(call: MethodCall, result: MethodResult): void { }
  onDetachedFromEngine(binding: FlutterPluginBinding): void { }
}

8.3 关键差异总结

特性 Android iOS OHOS
插件注册方式 GeneratedPluginRegistrant.java GeneratedPluginRegistrant.m GeneratedPluginRegistrant.ets
构建系统 Gradle CocoaPods Hvigor
模块类型 AAR Framework HAR
依赖管理 Maven/Gradle CocoaPods/SPM OHPM
最低 API minSdkVersion iOS Deployment Target compatibleSdkVersion

九、example 工程的鸿蒙配置

9.1 example/ohos/ 目录结构

演示工程的鸿蒙原生部分位于 example/ohos/ 目录:

example/ohos/
├── AppScope/
│   └── app.json5                    # 应用级配置
├── entry/
│   ├── src/main/ets/
│   │   ├── entryability/            # 应用入口
│   │   └── plugins/
│   │       └── GeneratedPluginRegistrant.ets  # 自动生成
│   ├── oh-package.json5             # entry 模块配置
│   └── build-profile.json5          # entry 构建配置
├── oh-package.json5                 # 工程级配置
├── build-profile.json5              # 工程级构建配置
├── hvigorfile.ts                    # 工程级构建脚本
└── hvigor/
    └── hvigor-config.json5          # Hvigor 配置

9.2 example 工程的 build-profile.json5

{
  "app": {
    "products": [
      {
        "name": "default",
        "signingConfig": "default",
        "compatibleSdkVersion": "5.1.0(18)",
        "runtimeOS": "HarmonyOS"
      }
    ]
  },
  "modules": [
    {
      "name": "entry",
      "srcPath": "./entry"
    }
  ]
}

关键配置:

  • compatibleSdkVersion: "5.1.0(18)" — 最低兼容的 SDK 版本
  • runtimeOS: "HarmonyOS" — 运行时操作系统
  • modules — 声明工程包含的模块

9.3 插件包的引用方式

在鸿蒙工程中,插件包通过 符号链接(symlink) 的方式被引用。Flutter-OHOS 构建工具会自动在 entry/oh_modules/ 目录下创建指向插件包 ohos/ 目录的符号链接:

entry/oh_modules/
└── flutter_libphonenumber_ohos/  →  ../../ohos/  (symlink)

注意:不要手动复制插件包的 ohos/ 目录到 example 工程中,Flutter-OHOS 构建工具会自动管理符号链接。


十、从零创建鸿蒙平台包的步骤

10.1 完整创建流程

如果你要为其他 Flutter 插件创建鸿蒙平台实现,可以按以下步骤操作:

  1. 创建包目录
mkdir -p my_plugin_ohos/lib
mkdir -p my_plugin_ohos/ohos/src/main/ets/components/plugin
  1. 创建 pubspec.yaml
name: my_plugin_ohos
version: 1.0.0

environment:
  sdk: ">=2.19.0 <4.0.0"
  flutter: ">=3.0.0"

flutter:
  plugin:
    implements: my_plugin
    platforms:
      ohos:
        package: com.example.my_plugin
        pluginClass: MyPluginPlugin
        dartPluginClass: MyPluginOhos

dependencies:
  flutter:
    sdk: flutter
  my_plugin_platform_interface: ^1.0.0
  1. 创建 Dart 侧实现
// lib/my_plugin_ohos.dart
import 'package:flutter/services.dart';
import 'package:my_plugin_platform_interface/my_plugin_platform_interface.dart';

const _channel = MethodChannel('com.example/my_plugin_ohos');

class MyPluginOhos extends MyPluginPlatform {
  static void registerWith() {
    MyPluginPlatform.instance = MyPluginOhos();
  }

  // 实现抽象方法...
}
  1. 创建 ohos/oh-package.json5
{
  "name": "my_plugin_ohos",
  "version": "1.0.0",
  "main": "index.ets",
  "dependencies": {
    "@ohos/flutter_ohos": "*"
  }
}
  1. 创建 ohos/index.ets
import MyPluginPlugin
  from './src/main/ets/components/plugin/MyPluginPlugin';
export default MyPluginPlugin;
  1. 创建 ArkTS 插件类
import {
  FlutterPlugin, FlutterPluginBinding,
  MethodCall, MethodCallHandler,
  MethodChannel, MethodResult
} from '@ohos/flutter_ohos';

export default class MyPluginPlugin
  implements FlutterPlugin, MethodCallHandler {

  private channel: MethodChannel | null = null;

  getUniqueClassName(): string { return 'MyPluginPlugin'; }

  onAttachedToEngine(binding: FlutterPluginBinding): void {
    this.channel = new MethodChannel(
      binding.getBinaryMessenger(), 'com.example/my_plugin_ohos'
    );
    this.channel.setMethodCallHandler(this);
  }

  onDetachedFromEngine(binding: FlutterPluginBinding): void {
    this.channel?.setMethodCallHandler(null);
    this.channel = null;
  }

  onMethodCall(call: MethodCall, result: MethodResult): void {
    // 处理方法调用
    result.notImplemented();
  }
}
  1. 创建 ohos/module.json5
{
  "module": {
    "name": "my_plugin_ohos",
    "type": "har",
    "deviceTypes": ["default", "tablet"]
  }
}

10.2 创建检查清单

完成创建后,逐项检查以下要素:

  1. pubspec.yamlimplements 指向正确的主包名
  2. dartPluginClass 类名与 Dart 文件中的类名一致
  3. pluginClass 类名与 ArkTS 文件中的类名一致
  4. MethodChannel 通道名称在 Dart 和 ArkTS 两端完全一致
  5. oh-package.json5main 指向 index.ets
  6. index.ets 正确导出了插件类
  7. module.json5typehar
  8. Dart 类正确继承了 PlatformInterface 的子类

十一、常见问题与排查

11.1 MethodChannel 通道名称不匹配

症状:调用 API 时无响应或抛出 MissingPluginException

排查

// Dart 侧
const _channel = MethodChannel('com.bottlepay/flutter_libphonenumber_ohos');
// ArkTS 侧 — 必须完全一致
const CHANNEL_NAME: string = 'com.bottlepay/flutter_libphonenumber_ohos';

提示:通道名称是 大小写敏感 的,一个字符的差异都会导致通信失败。

11.2 registerWith() 未被调用

症状FlutterLibphonenumberPlatform.instance 仍然是默认的 MethodChannelFlutterLibphonenumber

排查

  1. 检查 pubspec.yamldartPluginClass 是否正确
  2. 检查 registerWith() 是否为 static void 方法
  3. 运行 flutter clean 后重新构建

11.3 GeneratedPluginRegistrant 未包含插件

症状:ArkTS 侧的 GeneratedPluginRegistrant.ets 中没有导入插件

排查

  1. 检查 pubspec.yamlpluginClass 是否正确
  2. 检查 oh-package.json5name 是否与包名一致
  3. 运行 flutter pub get 重新生成

11.4 HAR 模块编译失败

症状:DevEco Studio 报告编译错误

排查

  1. 检查 @ohos/flutter_ohos 依赖是否正确声明
  2. 检查 module.json5type 是否为 har
  3. 检查 ArkTS 代码是否有语法错误

十二、本文涉及的文件清单

文件 路径 作用
pubspec.yaml flutter_libphonenumber_ohos/pubspec.yaml Flutter 包配置
Dart 实现 lib/flutter_libphonenumber_ohos.dart Dart 侧平台实现
包入口 ohos/index.ets 鸿蒙包入口文件
包配置 ohos/oh-package.json5 鸿蒙包元数据
模块配置 ohos/src/main/module.json5 模块类型声明
构建配置 ohos/build-profile.json5 构建选项
构建脚本 ohos/hvigorfile.ts HAR 构建任务
构建变量 ohos/BuildProfile.ets 编译时变量
插件入口 ohos/src/main/ets/.../FlutterLibphonenumberPlugin.ets ArkTS 插件类
核心工具 ohos/src/main/ets/.../PhoneNumberUtil.ets 格式化/解析逻辑
自动注册 example/ohos/.../GeneratedPluginRegistrant.ets 自动生成的注册代码

总结

本文详细讲解了鸿蒙平台插件包 flutter_libphonenumber_ohos 的完整创建过程。关键要点回顾:

  1. 插件包由 Dart 侧lib/)和 原生侧ohos/)两部分组成,通过 MethodChannel 通信
  2. pubspec.yaml 中的 flutter.plugin 配置是注册的核心,dartPluginClass 实现 Dart 侧自动注册,pluginClass 实现 ArkTS 侧自动注册
  3. ohos/ 目录使用 HAR 模块 类型,包含 oh-package.json5module.json5index.ets 等配置文件
  4. GeneratedPluginRegistrant.ets 由 Flutter-OHOS 构建工具 自动生成,无需手动编写
  5. 注册是 双端 的——Dart 侧通过 registerWith() 注册平台实例,ArkTS 侧通过 GeneratedPluginRegistrant 注册插件到 FlutterEngine
  6. 掌握了这套创建流程,你可以为 任何 Flutter 插件 创建鸿蒙平台实现包

下一篇我们将深入 init() 初始化流程,看看国家数据是如何从 ArkTS 侧加载到 Dart 侧的 CountryManager 中的。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

Logo

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

更多推荐