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

前言

在数据传输、加密解密、文件读写等底层操作中,二进制数据的转换是家常便饭。Flutter (Dart) 核心库虽然内置了 dart:convert (JSON/UTF8),但在处理十六进制 (Hex) 字符串、非常规 Base64 变体或其他编码时略显力不从心。

convert 是 Dart 官方维护的一个增强转换库,它提供了大量实用的 Codec, Converter, Sink 实现,填补了标准库在常见编码格式上的空白,尤其在处理自定义协议报文时极为便利。

一、概念介绍/原理解析

1.1 核心概念

  • Codec (编解码器): 包含 EncoderDecoder,如 hex 对象即为一个 Codec。
  • Converter (转换器): 单向转换,如 hex.decoder 将字符串转为字节列表。
  • Sink (数据槽):用于流式处理数据,适合大文件或网络流。

'48656c6c6f' (十六进制字符串)

hex.decode

72, 101, 108, 108, 111

hex.encode

1.2 进阶概念

该库遵循 dart:convert 的设计模式,这意味着它可以无缝集成到 Stream.transform 管道中。

二、核心 API/组件详解

2.1 基础用法

处理 Hex 字符串。

import 'package:convert/convert.dart';

void main() {
  // 1. Hex 编码 (Bytes -> String)
  var bytes = [0x48, 0x65, 0x6c, 0x6c, 0x6f]; // "Hello"
  var hexString = hex.encode(bytes);
  print(hexString); // "48656c6c6f"
  
  // 2. Hex 解码 (String -> Bytes)
  var decoded = hex.decode('48656c6c6f');
  print(decoded); // [72, 101, 108, 108, 111]
}

在这里插入图片描述

2.2 流式转换 (Stream)

处理大文件或网络流时,使用 transform 更加高效。

import 'dart:async';
import 'package:convert/convert.dart';

void processStream() {
  // 模拟一个不断产生 Hex 字符串的流
  var stream = Stream.fromIterable(['48', '65', '6c', '6c', '6f']);
  
  // 转换为字节流
  stream.transform(hex.decoder).listen((byte) {
    print('收到字节: $byte');
  });
}

在这里插入图片描述

2.3 AccumulatorSink

累积数据直到处理这一块的全部内容。这在处理分块传输(Chunked Transfer)时很有用。

var sink = AccumulatorSink<String>();
sink.add('Part 1');
sink.add('Part 2');
sink.close();
print(sink.events); // ["Part 1", "Part 2"]

三、常见应用场景

3.1 场景 1:蓝牙/串口通信

低功耗蓝牙 (BLE) 设备传输的数通常是十六进制字节流,App 端需将其转为可读字符串或对象。

void onBleDataReceived(List<int> data) {
  // 假设前 2 字节是标志位
  String hexStr = hex.encode(data);
  print('Received raw hex: $hexStr');
}

3.2 场景 2:加密密钥存储

AES/RSA 密钥通常以 Hex 或 Base64 形式存储在本地文件或数据库中。

void saveKey(List<int> keyBytes) async {
  // 转为 Hex 字符串存储,通过 secure_storage
  final keyHex = hex.encode(keyBytes);
  await storage.write(key: 'aes_key', value: keyHex);
}

3.3 场景 3:自定义协议解析

解析 Socket 接收到的定长包头(如前 4 字节为长度,后续为 JSON 体)。

void parsePacket(List<int> packet) {
  // 取前4字节的 Hex
  String lenHex = hex.encode(packet.sublist(0, 4));
  int len = int.parse(lenHex, radix: 16);
  // ...
}

四、OpenHarmony 平台适配

4.1 纯算法库

convert 是纯 Dart 逻辑,无任何平台相关代码,在 OpenHarmony 上直接可用,无需配置。

4.2 性能优化

对于极大量数据的转换(如图片 Hex 转码),建议放入 compute (Isolate) 中执行,以免阻塞 UI 线程。

五、完整示例代码

本示例构建一个简单的 Hex 转换工具,用户输入字符串(如 “Hello”)或 Hex(如 “4865…”),实时显示另一种格式。

import 'dart:convert';
import 'package:convert/convert.dart'; // 是的,这里与 dart:convert 不冲突但需注意命名
import 'package:flutter/material.dart';

void main() {
  runApp(const MaterialApp(home: ConverterPage()));
}

class ConverterPage extends StatefulWidget {
  const ConverterPage({super.key});

  
  State<ConverterPage> createState() => _ConverterPageState();
}

class _ConverterPageState extends State<ConverterPage> {
  final _textController = TextEditingController();
  final _hexController = TextEditingController();
  String _error = '';

  void _onTextChanged(String text) {
    try {
      // String -> UTF8 Bytes -> Hex String
      var bytes = utf8.encode(text);
      var hexStr = hex.encode(bytes);
      
      _hexController.value = TextEditingValue(
        text: hexStr,
        selection: TextSelection.collapsed(offset: hexStr.length),
      );
      setState(() => _error = '');
    } catch (e) {
      // 一般不会错
    }
  }

  void _onHexChanged(String text) {
    try {
      // 移除可能存在的空格
      var cleanHex = text.replaceAll(' ', '');
      // Hex String -> Bytes -> UTF8 String
      var bytes = hex.decode(cleanHex);
      var str = utf8.decode(bytes);
      
      _textController.value = TextEditingValue(
        text: str,
        selection: TextSelection.collapsed(offset: str.length),
      );
      setState(() => _error = '');
    } catch (e) {
      setState(() => _error = '无效的 Hex 格式');
    }
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Hex 转换工具')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
              controller: _textController,
              decoration: const InputDecoration(
                labelText: '普通文本 (UTF-8)',
                border: OutlineInputBorder(),
              ),
              onChanged: _onTextChanged,
            ),
            const SizedBox(height: 20),
            const Icon(Icons.swap_vert, size: 32, color: Colors.blue),
            const SizedBox(height: 20),
            TextField(
              controller: _hexController,
              decoration: InputDecoration(
                labelText: '十六进制 (Hex)',
                border: const OutlineInputBorder(),
                errorText: _error.isNotEmpty ? _error : null,
              ),
              onChanged: _onHexChanged,
              keyboardType: TextInputType.text, // Hex contains a-f
            ),
          ],
        ),
      ),
    );
  }
}

在这里插入图片描述

六、总结

convert 库极其轻量,却解决了 Dart 标准库在这方面的缺失。

最佳实践

  1. 异常捕获:Hex 解码极易出错(比如长度是奇数),务必 try-catch
  2. 区分大小写:通常 Hex 库能处理大小写,但规范输出时建议统一(如大写)。
  3. 流处理:处理文件流时优先使用 Stream.transform(hex.decoder),而非一次性读取内存。
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐