1. 项目概述:当Flutter遇见OpenHarmony,安全能力如何“跨”过去?

最近在折腾一个挺有意思的活儿:把一个Flutter应用适配到OpenHarmony上,并且要把原有的密码加密能力给集成进去。听起来像是把两个不同“星球”的技术拉到一起开会,一个是从Google来的跨平台UI框架,另一个是咱们国内开源的智能终端操作系统。这活儿干下来,感触最深的就是“跨平台”这三个字,说起来轻巧,做起来全是细节,尤其是在安全这种敏感领域。密码加密,这可不是简单的文本处理,它涉及到密钥管理、算法选型、平台适配,任何一个环节掉链子,都可能让“安全”变成“隐患”。如果你也在做类似的事情,比如想把Flutter应用上架到OpenHarmony的应用市场,或者需要为你的OpenHarmony设备开发一个带安全登录功能的Flutter应用,那这篇从一线踩坑填坑中总结出来的经验,或许能帮你省下不少折腾的时间。

简单来说,这个项目的核心目标就两个:第一,让Flutter应用能在OpenHarmony标准系统上顺畅跑起来;第二,确保应用中的密码等敏感信息,在存储和传输过程中是经过可靠加密的,而不是“裸奔”。这不仅仅是调用一个加密库那么简单,它涉及到从Flutter的Dart层,到与原生平台(这里是OpenHarmony)的通信桥接,再到最终在OpenHarmony的Native层(可能是C/C++或ArkTS)完成实际的加密运算。整个过程,就像是在为两个说不同方言的专家做翻译和协调工作。

2. 整体架构设计与技术选型背后的考量

当我们决定把Flutter应用部署到OpenHarmony,并集成原生密码加密能力时,首先得想清楚整个技术栈怎么搭。这不像在Android或iOS上,有现成且成熟的 flutter 插件生态,很多问题社区都踩过坑了。在OpenHarmony这块新大陆上,我们更多时候得自己当“拓荒者”。

2.1 为什么选择“桥接原生”而非纯Dart实现?

最直接的问题是:加密,到底在哪一层做?一种思路是全部用Dart实现,找一些纯Dart写的加密库。这听起来很“跨平台”,一份代码到处运行。但我实际评估后,很快否定了这个方案,原因有三:

  1. 性能与安全性 :加解密运算,尤其是非对称加密、哈希运算等,是计算密集型操作。纯Dart代码的执行效率,在复杂运算上通常不如利用操作系统底层原生库(如C/C++实现的开源库)来得高效。更重要的是,密码学算法的正确实现非常复杂,细微的错误就会导致严重的安全漏洞。使用经过广泛审计和长时间验证的原生库(如OpenSSL、BoringSSL,或OpenHarmony自身的密码学库),远比使用一个未经大规模实战检验的Dart移植版要可靠得多。

  2. 密钥安全存储 :加密的核心是密钥。密钥本身的安全存储,往往需要依赖操作系统提供的安全环境,比如Android的KeyStore、iOS的Keychain。在OpenHarmony上,同样有类似的 HUKS(Hardware Unified Key Store) 硬件密钥库服务。这是纯Dart环境根本无法触及的领域。我们必须通过平台通道(Platform Channel)调用OpenHarmony的原生API,才能把密钥存到最安全的地方。

  3. 合规与认证 :在一些对安全性要求极高的行业(如金融、政务),使用的加密模块可能需要符合特定的国家标准或行业规范。OpenHarmony作为面向全场景的国产操作系统,其内置的密码学服务很可能已经针对国密算法(如SM2, SM3, SM4)做了深度集成和优化,并满足相关合规要求。直接调用这些服务,是最稳妥的路径。

所以,结论很明确: 加密的核心逻辑必须下沉到OpenHarmony原生侧实现 。Flutter的Dart层只负责业务逻辑的触发(例如,用户点击“登录”时传入密码明文)和结果的接收(拿到加密后的密文或哈希值)。

2.2 通信桥梁:Platform Channel 还是 FFI?

确定了原生实现,下一个问题是怎么通信。Flutter提供了两种主要方式与原生代码交互: Platform Channel FFI(Foreign Function Interface)

  • Platform Channel :这是Flutter官方主推的异步消息传递机制。Dart端发送一个消息(包含方法和参数)到“通道”,原生端监听这个通道,收到消息后执行对应的方法,然后将结果异步返回给Dart端。它的优点是成熟、稳定、文档丰富,适合大多数“请求-响应”式的交互。
  • FFI :允许Dart代码直接调用C语言风格的API(动态库)。这更像是一种“函数直接调用”,延迟更低,适合对性能要求极高的场景。

在这个密码加密项目中,我选择了 Platform Channel 。原因如下:

  • 开发复杂度 :FFI需要你手动管理C数据结构和内存,在Dart和C之间进行类型转换,调试起来更复杂。而Platform Channel使用标准的消息编解码(如JSON),上手更快。
  • 安全性 :异步的Channel机制天然避免了在Dart侧长时间阻塞UI线程,而加密运算可能在原生侧耗时,异步处理更合理。
  • 生态兼容 :OpenHarmony的应用开发,目前主推ArkTS/JS。通过Platform Channel,我们可以用ArkTS来编写原生侧的加密模块,与OpenHarmony的API结合更顺畅。虽然FFI理论上也能调用C库,但中间还需要一层Native API(NAPI)的封装,链路更长。

因此,我们的架构就清晰了: Flutter (Dart) <--(Platform Channel)--> OpenHarmony (ArkTS/JS) <--> OpenHarmony 密码学服务 (HUKS等)

2.3 加密方案选型:对称、非对称还是哈希?

这不是一个二选一的问题,而是一个组合拳。根据密码使用的不同场景,我们需要不同的加密策略:

  1. 本地存储密码的哈希(Hash) :这是最基本的原则。用户的密码 绝对不应该 以明文形式存储在本地数据库或文件中。正确的做法是存储密码的哈希值(例如使用SHA-256或SM3)。当用户登录时,将输入的密码再次进行哈希运算,与存储的哈希值比对。为了抵御彩虹表攻击,必须 加盐(Salt) 。这个盐值应该是每个用户独立、随机生成的,并和哈希值一起存储。

    注意 :哈希是单向的,无法解密。这用于验证密码正确性,而不是用于“解密”出原始密码。

  2. 网络传输加密(非对称/对称结合) :如果密码需要发送到服务器,必须使用HTTPS(TLS)来保证传输通道的安全。在客户端,我们通常不直接加密密码本身,而是依赖TLS。但在一些特殊协议中,可能会用到非对称加密(如RSA或SM2)来加密一个临时生成的对称密钥(会话密钥)。

  3. 本地敏感配置加密(对称加密) :应用内一些其他的敏感配置信息(如API Token的加密存储),可以使用对称加密算法(如AES或SM4)。这里的关键是 密钥从哪里来 ?绝不能硬编码在代码里。最佳实践是,密钥本身由用户密码派生的密钥加密后存储,或者直接使用系统密钥库(HUKS)来生成和保管加密密钥。

在我们的集成项目中,重点会放在 场景1(密码哈希) 场景3(利用HUKS进行密钥管理) 上,因为这是移动端应用最普遍、最核心的安全需求。

3. 实操步骤:搭建Flutter-OpenHarmony加密桥梁

理论说完了,我们动手搭起来。这里我会假设你已经有一个基本的Flutter项目,并且OpenHarmony的开发环境(DevEco Studio)也已经就绪。

3.1 第一步:创建Flutter插件模块

我们不直接把原生代码写在主工程里,而是创建一个Flutter插件(Plugin),这样加密能力可以独立维护和复用。

# 在项目根目录外,创建插件
flutter create --template=plugin --platforms=android,ios,ohos maaath_password_encryption
cd maaath_password_encryption

这个命令会创建一个插件工程结构,其中 lib/ 下是Dart代码, android/ ios/ 和** ohos/ ** 分别是各平台的原生实现目录。OpenHarmony(ohos)平台的支持需要特定版本的Flutter SDK和模板,确保你的Flutter环境已支持OpenHarmony。

3.2 第二步:实现Dart层接口(Channel调用方)

lib/ 目录下,我们定义插件的对外接口。首先编辑 lib/maaath_password_encryption.dart

import 'dart:async';
import 'package:flutter/services.dart';

class MaaathPasswordEncryption {
  // 单例模式,方便全局调用
  static final MaaathPasswordEncryption _instance = MaaathPasswordEncryption._internal();
  factory MaaathPasswordEncryption() => _instance;
  MaaathPasswordEncryption._internal();

  // 定义与原生端通信的Channel,名称必须唯一,两端保持一致
  static const MethodChannel _channel = MethodChannel('maaath_password_encryption');

  // 1. 哈希密码(加盐)
  // 参数:password - 明文密码
  // 返回:一个Map,包含 'hash' (Base64编码的哈希值) 和 'salt' (Base64编码的盐值)
  // 注意:首次调用时生成新盐,验证时需传入之前存储的盐
  Future<Map<String, String>> hashPassword(String password, {String? existingSalt}) async {
    try {
      final Map<String, dynamic> arguments = {'password': password};
      if (existingSalt != null) {
        arguments['salt'] = existingSalt;
      }
      final Map<dynamic, dynamic> result = await _channel.invokeMethod('hashPassword', arguments);
      // 将动态类型转换为明确的String类型返回
      return {
        'hash': result['hash'] as String,
        'salt': result['salt'] as String,
      };
    } on PlatformException catch (e) {
      print("调用哈希方法失败: ${e.message}");
      rethrow; // 或者返回一个包含错误信息的Map,由业务层处理
    }
  }

  // 2. 使用系统密钥库加密一段数据
  Future<String> encryptWithKeyStore(String plaintext, String keyAlias) async {
    try {
      final String result = await _channel.invokeMethod('encryptWithKeyStore', {
        'plaintext': plaintext,
        'keyAlias': keyAlias,
      });
      return result; // 返回Base64编码的密文
    } on PlatformException catch (e) {
      print("加密失败: ${e.message}");
      rethrow;
    }
  }

  // 3. 使用系统密钥库解密
  Future<String> decryptWithKeyStore(String ciphertext, String keyAlias) async {
    try {
      final String result = await _channel.invokeMethod('decryptWithKeyStore', {
        'ciphertext': ciphertext,
        'keyAlias': keyAlias,
      });
      return result; // 返回解密后的明文
    } on PlatformException catch (e) {
      print("解密失败: ${e.message}");
      rethrow;
    }
  }
}

Dart层的代码相对清晰,主要就是定义 MethodChannel 和几个异步方法,它们负责将调用“打包”成消息发送给原生端。

3.3 第三步:实现OpenHarmony原生层(ArkTS)

这是最关键的一步。我们进入 ohos/ 目录。OpenHarmony插件的原生代码主要放在 ohos/src/main/ets/ 下。

首先,我们需要修改 ohos/src/main/ets/MaaathPasswordEncryption.ts (或.js),这是Channel的接收和处理方:

import crypto from '@ohos.security.crypto';
import util from '@ohos.util';
import huks from '@ohos.security.huks';

// 1. 定义Flutter Plugin的入口类,实现Channel方法分发
export class MaaathPasswordEncryption {
  private methodChannel: any;

  constructor() {
    // 注意:这里的Channel名称必须与Dart端完全一致
    this.methodChannel = new MethodChannel('maaath_password_encryption');
    this._registerMethods();
  }

  private _registerMethods(): void {
    this.methodChannel.onMethodCall = (method: string, args: Record<string, any>, callback: Function) => {
      switch (method) {
        case 'hashPassword':
          this._handleHashPassword(args, callback);
          break;
        case 'encryptWithKeyStore':
          this._handleEncryptWithKeyStore(args, callback);
          break;
        case 'decryptWithKeyStore':
          this._handleDecryptWithKeyStore(args, callback);
          break;
        default:
          callback(null, `未实现的方法: ${method}`);
      }
    };
  }

  // 2. 处理密码哈希
  private async _handleHashPassword(args: Record<string, any>, callback: Function): Promise<void> {
    const password: string = args.password;
    let saltBase64: string | undefined = args.salt;

    let salt: Uint8Array;
    if (saltBase64) {
      // 如果传入了盐,则使用传入的盐(验证场景)
      salt = this._base64ToUint8Array(saltBase64);
    } else {
      // 否则生成新的随机盐(注册场景)
      salt = crypto.createRandomBytes(32); // 生成32字节随机盐
    }

    // 将密码字符串转换为Uint8Array
    const passwordBytes = new util.TextEncoder().encode(password);

    // 拼接盐和密码(常见做法:salt + password)
    const dataToHash = new Uint8Array(salt.length + passwordBytes.length);
    dataToHash.set(salt, 0);
    dataToHash.set(passwordBytes, salt.length);

    // 使用SM3算法进行哈希(OpenHarmony内置支持国密)
    const hashResult = await crypto.hash(crypto.Hash.SM3, dataToHash.buffer);

    // 将结果转换为Base64字符串返回
    const hashBase64 = this._arrayBufferToBase64(hashResult);
    const saltBase64Result = this._arrayBufferToBase64(salt.buffer);

    callback(null, {
      hash: hashBase64,
      salt: saltBase64Result
    });
  }

  // 3. 处理使用HUKS加密
  private async _handleEncryptWithKeyStore(args: Record<string, any>, callback: Function): Promise<void> {
    const plaintext: string = args.plaintext;
    const keyAlias: string = args.keyAlias;

    // 这里简化流程,实际需要:
    // a. 检查密钥是否存在,不存在则生成(需用户认证)
    // b. 使用HUKS进行加密操作
    // 以下为示例伪代码逻辑
    try {
      // 假设我们已经有一个初始化好的HUKS密钥
      const cipherText = await this._huksEncrypt(keyAlias, plaintext);
      callback(null, cipherText);
    } catch (error) {
      callback(`加密错误: ${error.message}`, null);
    }
  }

  // 4. 处理使用HUKS解密
  private async _handleDecryptWithKeyStore(args: Record<string, any>, callback: Function): Promise<void> {
    const ciphertext: string = args.ciphertext;
    const keyAlias: string = args.keyAlias;
    try {
      const plainText = await this._huksDecrypt(keyAlias, ciphertext);
      callback(null, plainText);
    } catch (error) {
      callback(`解密错误: ${error.message}`, null);
    }
  }

  // -------------------- 工具函数 --------------------
  private _arrayBufferToBase64(buffer: ArrayBuffer): string {
    // OpenHarmony util.base64Encode 用法
    const uint8Array = new Uint8Array(buffer);
    return util.base64Encode(uint8Array);
  }

  private _base64ToUint8Array(base64: string): Uint8Array {
    return util.base64Decode(base64);
  }

  // -------------------- HUKS相关函数(示例框架)--------------------
  private async _huksEncrypt(keyAlias: string, data: string): Promise<string> {
    // 1. 构建加密参数
    const properties: huks.HuksOptions = {
      properties: [
        { tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_AES },
        { tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 },
        { tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT },
        { tag: huks.HuksTag.HUKS_TAG_PADDING, value: huks.HuksKeyPadding.HUKS_PADDING_PKCS7 },
        { tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, value: huks.HuksCipherMode.HUKS_MODE_GCM }, // 使用GCM等认证模式更安全
        { tag: huks.HuksTag.HUKS_TAG_DIGEST, value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 },
      ]
    };

    // 2. 初始化(Init)
    const handle = await huks.init(keyAlias, properties);
    
    // 3. 更新(Update)和结束(Finish)加密过程,处理数据
    // ... 此处省略具体的分段加密逻辑,需将data转换为Uint8Array进行处理
    // 4. 最终返回Base64编码的密文和可能的认证标签(GCM模式)
    return 'encryptedBase64String';
  }

  private async _huksDecrypt(keyAlias: string, cipherTextBase64: string): Promise<string> {
    // 解密流程与加密对称,参数中的 PURPOSE 改为 HUKS_KEY_PURPOSE_DECRYPT
    // ...
    return 'decryptedPlainText';
  }
}

// 5. 插件注册
export default class MaaathPasswordEncryptionPlugin {
  static register(): void {
    new MaaathPasswordEncryption();
  }
}

上面的ArkTS代码是一个高度简化的示例,重点展示了Channel通信、使用 @ohos.security.crypto 进行哈希、以及调用HUKS的框架。真实的HUKS操作涉及密钥生命周期管理(生成、导入、使用、删除)、分段加解密等复杂步骤,需要仔细阅读OpenHarmony的官方安全文档。

3.4 第四步:在Flutter主工程中集成插件

回到你的Flutter主项目,在 pubspec.yaml 中通过路径依赖引入我们刚写的插件:

dependencies:
  flutter:
    sdk: flutter
  maaath_password_encryption:
    path: ../path/to/maaath_password_encryption # 指向插件目录

然后执行 flutter pub get 。之后,你就可以在Dart代码中像下面这样使用了:

import 'package:maaath_password_encryption/maaath_password_encryption.dart';

// 用户注册时,哈希并存储密码
Future<void> registerUser(String username, String password) async {
  final crypto = MaaathPasswordEncryption();
  final result = await crypto.hashPassword(password);
  // result['hash'] 和 result['salt'] 需要安全地存储到本地数据库或服务器
  await _saveToLocalDB(username, result['hash'], result['salt']);
  print('密码哈希完成,盐值: ${result['salt']}');
}

// 用户登录时,验证密码
Future<bool> verifyPassword(String username, String inputPassword) async {
  // 1. 从本地取出之前存储的哈希值和盐值
  final (storedHash, storedSalt) = await _getFromLocalDB(username);
  // 2. 使用存储的盐值对输入密码进行哈希
  final crypto = MaaathPasswordEncryption();
  final result = await crypto.hashPassword(inputPassword, existingSalt: storedSalt);
  // 3. 比较新生成的哈希值与存储的哈希值是否一致
  return result['hash'] == storedHash;
}

4. 核心难点解析与避坑指南

集成过程看似步骤明确,但实际开发中会遇到不少“坑”。下面是我总结的几个关键难点和解决方案。

4.1 难点一:Flutter与OpenHarmony版本兼容性问题

这是最大的“玄学”问题。Flutter对OpenHarmony的支持仍在快速演进中,不同版本的Flutter SDK可能对应不同的OpenHarmony API版本和模板。

  • 问题表现 flutter create --template=plugin --platforms=ohos 命令执行失败,或者生成的 ohos 目录结构不对,缺少关键文件。
  • 排查与解决
    1. 确认Flutter渠道和版本 :使用 flutter doctor -v 查看你的Flutter版本。目前对OpenHarmony支持较好的通常是Flutter的特定版本或Master渠道。你需要查阅Flutter官方或OpenHarmony社区的最新文档,确认兼容矩阵。
    2. 检查OpenHarmony SDK路径 :确保DevEco Studio中安装的OpenHarmony SDK路径被正确配置。有时需要在 ohos 目录下的 build.gradle ohos 插件配置文件中手动指定SDK路径。
    3. 使用FVM管理多版本Flutter :强烈推荐使用 fvm (Flutter Version Management)来管理多个Flutter版本。你可以为OpenHarmony项目单独配置一个兼容的Flutter版本,而不会影响其他项目。
      # 安装fvm
      dart pub global activate fvm
      # 为项目指定一个Flutter版本(例如某个支持OH的commit)
      fvm use <version_or_channel>
      

4.2 难点二:Platform Channel 数据类型映射

Dart和ArkTS/JS之间的数据类型并非一一对应,错误的类型会导致通信失败。

  • 常见错误 :Dart端发送了一个 int ,原生端期望的是 string ,或者Map/List的结构不一致。
  • 最佳实践
    1. 使用简单、明确的数据结构 :尽量使用 String , int , bool , List<dynamic> , Map<String, dynamic> 这些基本类型。复杂对象先序列化为JSON字符串再传递。
    2. 在两端定义协议文档 :哪怕只是注释,也要明确每个方法的参数名、类型、返回值结构。例如:
      // Dart端协议
      // 方法名: 'hashPassword'
      // 参数: {'password': String, 'salt': String?} // salt可选
      // 返回: {'hash': String, 'salt': String}
      
    3. 做好错误处理 :如前面Dart代码所示,一定要用 try-catch 包裹 invokeMethod 调用,并处理 PlatformException 。原生端回调时,第一个参数是错误信息(成功时为 null ),第二个参数是结果,这个约定不能错。

4.3 难点三:OpenHarmony HUKS API的复杂性

HUKS功能强大,但API调用链较长,涉及异步操作和大量的参数配置,容易出错。

  • 关键步骤 :一次完整的HUKS加密通常包括 generateKey (或 importKey ) -> init -> update (可能多次)-> finish 。解密同理。
  • 避坑技巧
    1. 仔细阅读官方示例 :OpenHarmony的 @ohos.security.huks 文档会提供关键示例代码。先从示例代码跑通最简单的流程开始。
    2. 关注 HuksTag :密钥属性(算法、长度、用途、填充模式等)都通过 HuksTag 来设置。一个常见的错误是 PURPOSE 没配对,比如生成密钥时设置了 ENCRYPT ,解密时却用同一个别名去 INIT ,会失败。用于解密的密钥其 PURPOSE 必须包含 DECRYPT
    3. 处理异步与Promise :HUKS的API返回的是Promise,务必使用 async/await .then().catch() 正确处理异步和错误。
    4. 密钥别名(KeyAlias)管理 :密钥别名是访问密钥的句柄。要设计好别名的命名规则,防止冲突。应用卸载后,密钥库中对应的密钥是否清除,也取决于生成时的参数。

4.4 难点四:调试与日志输出

跨层调试比较麻烦,你需要清楚问题出在Dart层、Channel通信层还是原生层。

  • 分层调试法
    1. Dart层 :使用 print debugPrint ,在Flutter DevTools的Console里查看。
    2. Channel通信层 :在原生端(ArkTS)的方法入口处打印接收到的参数,确认数据是否正确送达。同样,在回调前打印要返回的数据。
    3. 原生层 :OpenHarmony应用可以使用 hilog 命令输出日志到控制台。在ArkTS中可以使用 console.log() Logger 模块。
      import hilog from '@ohos.hilog';
      hilog.info(0x0000, 'MyTag', '加密方法被调用,参数: %{public}s', JSON.stringify(args));
      
    4. 使用DevEco Studio的调试器 :可以给ArkTS代码打断点,这是最有效的调试原生逻辑的方法。

5. 进阶思考与性能优化

当基础功能跑通后,我们可以考虑一些更深入的问题来提升安全性、用户体验和性能。

5.1 密钥管理策略:存哪?怎么存?

  • 场景一:用户密码派生的密钥 。可以使用PBKDF2、Scrypt等算法,将用户密码和固定的应用唯一盐(App Salt)进行多次哈希迭代,生成一个加密密钥。这个密钥用于加密本地其他敏感数据。 切记 :这个派生过程应该在原生侧完成,避免密码在Channel中频繁传递。
  • 场景二:设备绑定的密钥 。使用HUKS生成一个设备硬件绑定的密钥(设置 HUKS_TAG_ATTESTATION_ID 等标签)。即使应用数据被完整拷贝到另一台设备,也无法解密。适合加密高敏感数据。
  • 密钥轮换 :对于长期存储的数据,应考虑定期轮换加密密钥。新数据用新密钥加密,旧数据在访问时解密后用新密钥重新加密。

5.2 国密算法(SM2/SM3/SM4)的优先使用

在OpenHarmony环境下,应优先考虑使用国密算法。如上文代码所示, @ohos.security.crypto 直接支持SM3哈希。对于SM2/SM4,HUKS也提供了支持。在生成密钥或指定算法时,使用 HUKS_ALG_SM2 HUKS_ALG_SM4 等对应的枚举值即可。这不仅更符合国内一些项目的合规要求,其性能在OpenHarmony系统上也通常有更好的优化。

5.3 异步操作与UI响应

加密哈希和HUKS操作都可能耗时,尤其是在低端设备上。务必确保这些操作在非UI线程执行。

  • 在Dart端 ,我们的 MethodChannel.invokeMethod 本身就是异步的(返回 Future ),这很好。但要避免在 compute 或Isolate中再进行密集的Dart运算,应把计算压力完全交给原生侧。
  • 在原生ArkTS侧 ,HUKS的API是异步的。但要小心,如果你的加密操作是在UI线程触发的,并且回调后需要更新Flutter UI,你需要确保回调能正确返回到Flutter的UI线程。Platform Channel的回调机制通常已经处理了这一点。

5.4 插件化与生态建设

我们是以插件形式开发加密模块的。一个好的插件还应该包括:

  • 完善的文档 :README文件,说明安装、配置、API和常见问题。
  • 单元测试 :为Dart接口和主要的原生功能编写测试用例。
  • 示例应用 :一个完整的、可运行的示例应用,展示插件的典型用法。
  • 发布到Pub.dev :如果希望共享给社区,可以发布到Flutter的包仓库。需要注意的是,由于包含原生代码,发布时需要为每个平台(android, ios, ohos)打包相应的产物。

最后,集成过程中如果遇到 waiting for another flutter command to release the startup lock 这类问题,通常是因为Flutter进程被意外锁住,去 flutter sdk 目录下的 bin/cache 里删除 .lockfile 文件即可。而 flutter pub get 卡在 resolving dependencies ,多半是网络问题,可以检查是否配置了国内镜像,或者尝试切换网络环境。

整个集成过程,就像是在Flutter的便捷与OpenHarmony的底层能力之间架起一座坚固且安全的桥梁。每踩过一个坑,对两个系统的理解就加深一层。当你看到Flutter界面上的一个按钮点击,能安全地触发OpenHarmony硬件密钥库里的加密操作时,那种成就感,就是跨平台开发最大的乐趣所在。

更多推荐