开发者工具箱-鸿蒙二维码工具开发笔记

鸿蒙二维码工具开发笔记

前言

最近在搞鸿蒙工具箱,心血来潮想加个二维码工具。说实话,一开始我还挺自信的,觉得不就是个简单的二维码嘛,能有多难?结果一上手才发现,我太天真了!各种格式、参数、保存、扫描,搞得我头都大了。特别是那个扫描功能,动不动就崩溃,气得我直想砸键盘。

写这个工具的时候踩了不少坑,比如扫描封装、图片保存、权限处理等等。记得有一次,我熬到凌晨三点还在调试那个该死的保存功能,差点把电脑砸了。不过功夫不负有心人,最后都搞定了,现在用起来还挺顺手的。看着用户反馈说"真好用",心里那个美啊!

一、功能说明

1.1 主要功能

  • 支持二维码生成
  • 支持二维码扫描
  • 支持从相册选择图片
  • 支持保存二维码到相册
  • 支持复制扫描结果
  • 收藏功能

1.2 界面功能

  • 生成/扫描切换标签
  • 内容输入框
  • 二维码预览
  • 扫描按钮
  • 保存按钮
  • 复制按钮

二、实现过程

2.1 开发小故事

故事一:扫描功能的崩溃风波

记得刚开始写这个功能的时候,我直接用了系统自带的扫描模块,心想:"这不就是调用个API的事嘛,简单!"结果各种问题接踵而至。最搞笑的是有个用户扫了个模糊的二维码,程序直接崩溃了。用户一看就炸了:"这什么鬼?我要的是友好的错误提示!"我心想:"不就是个错误提示嘛,简单!"结果一上手才发现,得加try-catch,还得给出具体的错误信息,真是让人头大。最后改了好几版,加了个加载动画,这才好多了。

故事二:保存功能的尴尬时刻

还有一次,有个用户说保存功能不好用,我一开始还觉得挺委屈:"这不是挺简单的吗?"结果自己试了一下,发现确实有点问题。最尴尬的是,保存的时候没有提示,而且有时候会保存失败。用户反馈说:"保存了半天,结果不知道存哪去了,气死我了!"我赶紧改了好几版,加了个保存成功的提示,这才好多了。现在想想,真是感谢那位用户的反馈,要不然我还真发现不了这个问题。

后来仔细研究了一下,发现保存功能其实挺复杂的:

  1. 首先得把二维码转换成图片格式,这个过程中可能会遇到内存问题(有时候一不小心就OOM了,真服了)
  2. 然后要申请相册权限,这个权限申请还挺麻烦的(有时候弹窗都不弹,气死个人)
  3. 最后保存到相册的时候,还得处理各种异常情况

最搞笑的是,有一次我测试的时候,保存成功了,但是图片死活找不到。折腾了半天才发现,原来是保存路径的问题。鸿蒙系统的相册路径和普通安卓不太一样,得用专门的API。这个坑踩得我真是哭笑不得。

故事三:大图片的卡死危机

最搞笑的是处理大图片的问题。一开始没考虑性能,结果有个用户发了个超大的图片过来,程序直接卡死了。我心想:"不就是个图片嘛,简单!“结果一上手才发现,得考虑内存占用,还得做异步处理。最后改了好几遍,加了个加载状态,这才好多了。现在想想,真是感谢那位用户的"大图片”,要不然我还真发现不了这个性能问题。

故事四:复制功能的意外发现

还有个小插曲,有个用户说复制功能不好用,我一开始还觉得挺委屈:"这不是挺简单的吗?"结果自己试了一下,发现确实有点问题。最搞笑的是,复制的时候没有提示,而且有时候会复制失败。用户说:"复制了半天,结果不知道复制成功没有,气死我了!"我赶紧改了好几版,加了个复制成功的提示,这才好多了。现在想想,真是感谢那位用户的反馈,要不然我还真发现不了这个问题。

2.2 核心功能实现

  1. 导入模块
import router from '@ohos.router'
import promptAction from '@ohos.promptAction'
import { scanCore, scanBarcode } from '@kit.ScanKit'
import { hilog } from '@kit.PerformanceAnalysisKit'
import pasteboard from '@ohos.pasteboard'
import common from '@ohos.app.ability.common'
import image from '@ohos.multimedia.image'
import fileio from '@ohos.fileio'
import { photoAccessHelper } from '@kit.MediaLibraryKit'
import { StorageUtil } from '../../utils/storage'
import { componentSnapshot } from '@kit.ArkUI'
import { fileIo } from '@kit.CoreFileKit'
import { BusinessError } from '@kit.BasicServicesKit'
  1. 扫描功能实现
private startScan() {
  try {
    let options: scanBarcode.ScanOptions = {
      scanTypes: [scanCore.ScanType.ALL],
      enableMultiMode: true,
      enableAlbum: true
    }

    scanBarcode.startScanForResult(getContext(this), options, (error, result: scanBarcode.ScanResult) => {
      if (error) {
        hilog.error(0x0001, 'QRCodeTool', `Failed to get ScanResult. Code: ${error.code}, message: ${error.message}`)
        promptAction.showToast({ message: '扫描失败' })
        return
      }

      if (result) {
        try {
          console.info('Scan result:', JSON.stringify(result))
          
          let scanText = ''
          if (typeof result === 'object') {
            scanText = result['originalValue'] || result['result'] || result['value'] || ''
          }

          if (scanText) {
            this.scanContent = scanText
            hilog.info(0x0001, 'QRCodeTool', `Scan success: ${scanText}`)
            promptAction.showToast({ message: '扫描成功' })
          } else {
            hilog.error(0x0001, 'QRCodeTool', 'Empty scan result')
            promptAction.showToast({ message: '未获取到扫描内容' })
          }
        } catch (err) {
          hilog.error(0x0001, 'QRCodeTool', `Parse result error: ${err}`)
          promptAction.showToast({ message: '解析扫描结果失败' })
        }
      }
    })
  } catch (error) {
    hilog.error(0x0001, 'QRCodeTool', `Failed to startScanForResult. Code: ${error.code}, message: ${error.message}`)
    promptAction.showToast({ message: '启动扫码失败' })
  }
}
  1. 保存功能实现
// 打包 PixelMap 为 jpg 格式
async packingPixelMap2Jpg(pixelMap: PixelMap): Promise<ArrayBuffer> {
  const imagePackerApi = image.createImagePacker();
  const packOpts: image.PackingOption = { format: "image/jpeg", quality: 98 };
  let imageBuffer: ArrayBuffer = new ArrayBuffer(1);
  try {
    imageBuffer = await imagePackerApi.packing(pixelMap, packOpts);
  } catch (err) {
    console.error(`Invoke packingPixelMap2Jpg failed, err: ${JSON.stringify(err)}`);
  }
  return imageBuffer;
}

// 保存图片到相册
async savePhotoToGallery(context: common.UIAbilityContext) {
  let helper = photoAccessHelper.getPhotoAccessHelper(context);
  try {
    const imageBuffer = await this.packingPixelMap2Jpg(this.pixmap as image.PixelMap)
    
    let uri = await helper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg');
    let file = await fileIo.open(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
    await fileIo.write(file.fd, imageBuffer);
    await fileIo.close(file.fd);
    promptAction.showToast({ message: '已保存至相册!' });
  }
  catch (error) {
    const err: BusinessError = error as BusinessError;
    console.error(`Failed to save photo. Code is ${err.code}, message is ${err.message}`);
  }
}
  1. 复制功能实现
private async copyToClipboard(content: string) {
  try {
    const pasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, content)
    const systemPasteboard = pasteboard.getSystemPasteboard()
    await systemPasteboard.setData(pasteData)
    await promptAction.showToast({ message: '已复制到剪贴板' })
  } catch (error) {
    console.error('复制失败:', error)
    await promptAction.showToast({ message: '复制失败' })
  }
}

2.3 临时解决方案

  1. 扫描问题

    • 临时方案:直接用扫描模块,简单粗暴
    • 问题:格式错误就崩溃,用户体验差
    • 最终方案:加try-catch,给出友好提示
  2. 保存问题

    • 临时方案:直接保存,简单
    • 问题:没有提示,体验差,权限处理不完善
    • 最终方案:
      • 加保存成功提示
      • 完善权限申请流程
      • 优化错误处理
      • 确保文件正确关闭
      • 添加详细的错误提示
  3. 大图片问题

    • 临时方案:同步处理,简单
    • 问题:大图片会卡死
    • 最终方案:异步处理,加加载状态
  4. 复制问题

    • 临时方案:直接复制,简单
    • 问题:没有提示,体验差
    • 最终方案:加复制成功提示

三、踩坑记录

3.1 遇到的问题

  1. 扫描问题

    • 问题:格式错误就崩溃
    • 解决:加try-catch
    • 建议:给出友好提示
  2. 保存问题

    • 问题:保存失败
    • 解决:使用SaveButton和componentSnapshot
    • 建议:注意权限申请
  3. 大图片问题

    • 问题:会卡死
    • 解决:异步处理
    • 建议:加加载状态
  4. 复制问题

    • 问题:没有提示
    • 解决:加提示
    • 建议:处理错误

3.2 优化建议

  1. 功能优化

    • 支持更多二维码格式
    • 加个历史记录
    • 支持批量扫描
    • 二维码美化、自定义样式、批量生成啥的都能加
  2. 性能优化

    • 优化扫描速度
    • 减少内存占用
    • 及时释放资源
    • 多线程、算法优化、结果缓存、异步处理都可以试试
  3. 用户体验

    • 加个使用说明
    • 支持快捷键
    • 动画效果、主题、分享、收藏、导入、备份啥的都能加

四、总结

这个二维码工具,基本功能都齐了:

  • 支持二维码生成
  • 支持二维码扫描
  • 支持保存到相册
  • 支持复制结果
  • 收藏常用设置

说实话,开发这个工具的过程真是让我又爱又恨。爱的是看着它从无到有,一步步变得更好用;恨的是各种坑踩得我头都大了。不过现在想想,这些坑踩得值!要不是这些坑,我还真发现不了这么多可以优化的地方。

有些边角问题其实还没完全搞定,比如有时候扫描还是会有点慢,保存大图片的时候偶尔会卡一下(有时候还会莫名其妙弹个错,真服了)。不过大部分场景都能用,用户反馈也还不错。后面有空再慢慢优化吧,毕竟好产品都是慢慢打磨出来的。

五、参考资料

欢迎体验

这个二维码工具已经集成到鸿蒙开发者工具箱里了,欢迎下载体验!如果遇到问题,欢迎随时反馈,我会继续改进的!

鸿蒙开发者工具箱


作者:在人间耕耘
邮箱:1743914721@qq.com
版权声明:本文为原创文章


如果你也遇到类似问题,欢迎留言交流。大家一起进步,一起成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值