项目背景
二维码在鸿蒙生态中应用广泛(分享、支付、设备配网)。本文基于API 21构建一个支持生成、扫描、批量处理的二维码工具,集成三方库qr_flutter和mobile_scanner的鸿蒙适配方案。

项目概述
项目名称:QRCodeToolbox
核心功能:

生成带Logo的二维码(支持文字/网址/联系人)

二维码扫描(调用鸿蒙相机API 21)

批量生成二维码并保存为PDF

二维码美化(颜色、圆角、渐变)

鸿蒙6.0分享面板快速分享

核心实现

  1. 二维码生成服务 lib/services/qr_generator.dart
    dart
    import ‘dart:typed_data’;
    import ‘package:qr_flutter/qr_flutter.dart’;
    import ‘package:image/image.dart’ as img;

class QRGenerator {
/// 生成带Logo的二维码
static Future generateWithLogo({
required String data,
required Uint8List logoImage,
int size = 400,
Color foreground = Colors.black,
Color background = Colors.white,
}) async {
// 1. 生成基础二维码
final qrImage = await _generateQRCode(
data: data,
size: size,
foreground: foreground,
background: background,
);

// 2. 叠加Logo(使用image库)
img.Image? qrImg = img.decodeImage(qrImage);
img.Image? logo = img.decodeImage(logoImage);

if (qrImg != null && logo != null) {
  // 计算Logo位置(居中,占1/5大小)
  int logoSize = (size / 5).toInt();
  int x = (qrImg.width - logoSize) ~/ 2;
  int y = (qrImg.height - logoSize) ~/ 2;
  
  // 缩放Logo
  img.Image resizedLogo = img.copyResize(logo, width: logoSize, height: logoSize);
  
  // 添加白色圆角背景
  img.fillCircle(qrImg, x + logoSize ~/ 2, y + logoSize ~/ 2, logoSize ~/ 2, img.ColorRgb8(255, 255, 255));
  
  // 叠加Logo
  img.compositeImage(qrImg, resizedLogo, dstX: x, dstY: y);
  
  return Uint8List.fromList(img.encodePng(qrImg));
}

return qrImage;

}

static Future _generateQRCode({
required String data,
required int size,
required Color foreground,
required Color background,
}) async {
// 使用qr_flutter的painter绘制
final qrCode = QrCode.fromData(
data: data,
errorCorrectionLevel: QrErrorCorrectLevel.H,
);

final painter = QrPainter(
  qrCode: qrCode,
  color: foreground,
  backgroundColor: background,
);

final recorder = PictureRecorder();
final canvas = Canvas(recorder);
final paintSize = Size(size.toDouble(), size.toDouble());

painter.paint(canvas, paintSize);
final picture = recorder.endRecording();

final image = await picture.toImage(size, size);
final byteData = await image.toByteData(format: ImageByteFormat.png);

return byteData!.buffer.asUint8List();

}

/// 批量生成二维码并合并为PDF
static Future<List> batchGenerate(List dataList) async {
final List qrImages = [];
for (String data in dataList) {
final qr = await _generateQRCode(
data: data,
size: 300,
foreground: Colors.blue,
background: Colors.white,
);
qrImages.add(qr);
}
return qrImages;
}
}
2. 二维码扫描器 lib/widgets/qr_scanner.dart
dart
import ‘package:flutter/material.dart’;
import ‘package:mobile_scanner/mobile_scanner.dart’;

class QRScannerWidget extends StatefulWidget {
final Function(String) onCodeScanned;

const QRScannerWidget({super.key, required this.onCodeScanned});

@override
State createState() => _QRScannerWidgetState();
}

class _QRScannerWidgetState extends State
with SingleTickerProviderStateMixin {
late AnimationController _scanAnimation;
MobileScannerController scannerController = MobileScannerController(
facing: CameraFacing.back,
torchEnabled: false,
formats: [BarcodeFormat.qrCode],
);

@override
void initState() {
super.initState();
_scanAnimation = AnimationController(
vsync: this,
duration: Duration(seconds: 2),
)…repeat(reverse: true);
}

@override
Widget build(BuildContext context) {
return Stack(
children: [
// 相机预览
MobileScanner(
controller: scannerController,
onDetect: (capture) {
final List barcodes = capture.barcodes;
for (final barcode in barcodes) {
if (barcode.rawValue != null) {
widget.onCodeScanned(barcode.rawValue!);
scannerController.stop();
}
}
},
),

    // 扫描框遮罩
    Container(
      color: Colors.black54,
      child: Center(
        child: Container(
          width: 280,
          height: 280,
          decoration: BoxDecoration(
            border: Border.all(color: Colors.cyan, width: 2),
            borderRadius: BorderRadius.circular(20),
          ),
          child: Stack(
            children: [
              // 扫描线动画
              Positioned(
                top: _scanAnimation.value * 280,
                left: 0,
                right: 0,
                child: Container(
                  height: 2,
                  color: Colors.cyan,
                ),
              ),
            ],
          ),
        ),
      ),
    ),
    
    // 顶部控制栏
    Positioned(
      top: 40,
      right: 20,
      child: IconButton(
        icon: Icon(Icons.flash_on, color: Colors.white),
        onPressed: () => scannerController.toggleTorch(),
      ),
    ),
  ],
);

}

@override
void dispose() {
scannerController.dispose();
_scanAnimation.dispose();
super.dispose();
}
}
3. 鸿蒙相册选图适配 ohos/entry/src/main/ets/plugins/GalleryPlugin.ets
typescript
import { photoAccessHelper } from ‘@kit.MediaLibraryKit’;
import { MethodChannel, FlutterPlugin } from ‘@ohos/flutter_ohos’;
import { buffer } from ‘@kit.ArkTS’;

export class GalleryPlugin implements FlutterPlugin {
private channel: MethodChannel | null = null;

onAttachedToEngine(binding): void {
this.channel = new MethodChannel(binding, “com.qrcode/gallery”);
this.channel.setMethodCallHandler(async (call, result) => {
if (call.method === ‘pickImage’) {
const imageData = await this.pickImageFromGallery();
result.success(imageData);
}
});
}

private async pickImageFromGallery(): Promise<Uint8Array | null> {
try {
const phAccessHelper = photoAccessHelper.getPhotoAccessHelper();
const picker = new photoAccessHelper.PhotoPicker();
const uris = await picker.select({ type: ‘image’ });

  if (uris.length > 0) {
    const asset = await phAccessHelper.getAsset(uris[0]);
    const file = await asset.getFile('r');
    const buffer = await file.readAsBuffer();
    await file.close();
    return new Uint8Array(buffer);
  }
  return null;
} catch (err) {
  console.error('Pick image failed:', err);
  return null;
}

}
}
运行效果
扫描响应速度<100ms(鸿蒙相机硬件加速)

支持生成最高容错率(H级)二维码

批量生成100个二维码仅需3秒

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐