解决uni.chooseImage勾选相册原图,使用pathToBase64方法转Base64,提示“t ...

打印 上一主题 下一主题

主题 563|帖子 563|积分 1689

1.标题描述

上传图片时,后端吸收的参数类型为 Base64,于是我们便使用 uniapp 中的 uni.chooseImage API,搭配 image-tools 插件的 pathToBase64 方法来实现传递 Base64 格式图片的业务需求。
  1. // 业务代码
  2. import { pathToBase64 } from '@/utils/image-tools.js'
  3. uni.chooseImage({
  4.   count: 1,
  5.   sourceType: ['camera', 'album'],
  6.   async success(res) {
  7.     let ewm = res.tempFilePaths[0]
  8.     ewm = await pathToBase64(ewm)
  9.         const data = {
  10.           formData: {
  11.             ewm
  12.           }
  13.         }
  14.     const {data: res} = await _this.networkApi(data)
  15.     // 下方省略
  16.   },
  17. })
复制代码
H5 端没有标题,但在安卓APP 中,当用户勾选原图之后,便出现了标题,经调试排查,发现 await pathToBase64(ewm) 抛出了一个非常
  1. {
  2.     "type": "error",
  3.     "bubbles": false,
  4.     "cancelBubble": false,
  5.     "cancelable": false,
  6.     "lengthComputable": false,
  7.     "loaded": 0,
  8.     "total": 0,
  9.     "target": {
  10.         "fileName": "/storage/emulated/0/Pictures/Gallery/owner/xxx/IMG_20240202_133858.jpg",
  11.         "readyState": 2,
  12.         "result": null,
  13.         "error": {
  14.             "code": 15,
  15.             "message": "targetSdkVersion设置>=29后在Android10+系统设备不支持当前路径。请更改为应用运行路径!具体请看:https://ask.dcloud.net.cn/article/36199"
  16.         },
  17.         "onloadstart": null,
  18.         "onprogress": null,
  19.         "onload": "function() { [native code] }",
  20.         "onabort": null,
  21.         "onerror": "function() { [native code] }",
  22.         "onloadend": null
  23.     }
  24. }
复制代码
2.解决方案

经过阅读文章 https://ask.dcloud.net.cn/article/id-36199,并经过有关尝试后,有以下三种解决方案
2.1 后端不使用 Base64 的格式吸收图片

2.2 在 uni.chooseImage API中添加 sizeType: [‘compressed’] 配置,仅允许选择压缩图

  1. // 业务代码
  2. import { pathToBase64 } from '@/utils/image-tools.js'
  3. uni.chooseImage({
  4.   count: 1,
  5.   sourceType: ['camera', 'album'],
  6.   // 添加该配置,仅使用 压缩图
  7.   sizeType: ['compressed'],
  8.   async success(res) {
  9.     let ewm = res.tempFilePaths[0]
  10.     ewm = await pathToBase64(ewm)
  11.         const data = {
  12.           formData: {
  13.             ewm
  14.           }
  15.         }
  16.     const {data: res} = await _this.networkApi(data)
  17.     // 下方省略
  18.   },
  19. })
复制代码
2.3 使用 uni.saveFile 方法另存图片后,再转 Base64



  • utils 下封装如下方法
  1. export const saveFileSync = (tempFilePath) => {
  2.    return new Promise((resolve, reject) => {
  3.      uni.saveFile({
  4.        tempFilePath,
  5.        success: function (file) {
  6.          resolve(file.savedFilePath)
  7.        },
  8.        fail: function (error) {
  9.          reject(error)
  10.        }
  11.      })
  12.    })
  13. }
复制代码


  • 使用 saveFileSync,将选择的图片另行生存到本地,并获取生存的地址
  1. // 业务代码
  2. import { pathToBase64 } from '@/utils/image-tools.js'
  3. import { saveFileSync } from '@/utils/file.js'
  4. uni.chooseImage({
  5.   count: 1,
  6.   sourceType: ['camera', 'album'],
  7.   async success(res) {
  8.     let ewm = res.tempFilePaths[0]
  9.     // 使用 saveFileSync,将选择的图片另行保存到本地,并获取保存的地址
  10.     const path = await saveFileSync(ewm)
  11.     ewm = await pathToBase64(path)
  12.         const data = {
  13.           formData: {
  14.             ewm
  15.           }
  16.         }
  17.     const {data: res} = await _this.networkApi(data)
  18.     // 下方省略
  19.   },
  20. })
复制代码
3.原因探究

声明:下方大多是我排查BUG、探索标题产生原因的过程记录,开发任务重的同学可以先去忙哈~


  • 用户通过相册选择图片的地址的绝对路径为 file:///storage/emulated/0/Pictures 开头,经过阅读文章 https://ask.dcloud.net.cn/article/id-36199 可以知道,该目录属于体系公共目录
  • 文章中提到:“andorid 11逼迫实行分区存储。不允许应用读写操纵非应用沙盒目录和体系公共目录下的资源文件。dcloud已对分区存储机制做了适配工作。但也增加了开发者对文件目录操纵的规则。在分区存储的环境下分出两个可操文件数据目录 体系公共目录 和 应用沙盒目录。”
  • 大概意思就是 安卓自身不允许应用访问自身存储空间(应用沙盒目录)之外的内容,dcloud 对分区存储机制进行了优化,除了自身存储空间外,体系公共目录也能通过一定手段来进行读写
  • 对于体系公共目录,“当我们拥有权限,也能通过路径直接访问。”,这一点,大概就是体系在读写相册前,需要授权的原因,在完成授权后,我们便能够读写 相册 等体系公共目录
  • 由此我推测,当用户勾选了原图之后, dcloud 对分区存储机制的优化失效了,应用无法访问体系公共目录,导致抛出非常,但经过尝试发现,其他未进行 Base64 转化的地方,勾选原图也可以实现图片的正常上传
  • 于是又对文章阅读了两遍,发现对 体系公共目录的描述中有如许一句话

  • 以是推测 image-tools 中的 pathToBase64 方法,存在对体系公共目录的文件进行了写操纵,但经过阅读源码、查阅有关文档发现,应该不存在写操纵,也就不会出现对体系公共目录操纵越权的举动
  1. export function pathToBase64(path) {
  2. // 省略其他代码
  3.         if (typeof plus === 'object') {
  4.           plus.io.resolveLocalFileSystemURL(
  5.             getLocalFilePath(path),
  6.             function(entry) {
  7.               entry.file(
  8.                 function(file) {
  9.                   var fileReader = new plus.io.FileReader()
  10.        
  11.                   fileReader.onload = function(data) {
  12.                     resolve(data.target.result)
  13.                   }
  14.        
  15.                   fileReader.onerror = function(error) {
  16.                     reject(error)
  17.                   }
  18.        
  19.                   fileReader.readAsDataURL(file)
  20.                 },
  21.                 function(error) {
  22.                   reject(error)
  23.                 }
  24.               )
  25.             },
  26.             function(error) {
  27.               reject(error)
  28.             }
  29.           )
  30.        
  31.           return
  32.         }
  33. // 省略其他代码
  34. }
复制代码


  • 至此,我对“解决 uni.chooseImage 勾选相册原图,搭配 image-tools 插件的 pathToBase64 方法转 Base64,提示“targetSdkVersion设置>=29后在Android10+体系设备不支持当前路径”的标题”的探究就无果而终了
  • 有知道原因的同学或先辈可以在批评区留言指教一番,先行感谢~
4.使用 uni.saveFile 方法另存图片,能够解决该标题标原因

接上文,应用程序在分区存储的环境下,分出了两个可操做文件数据目录:体系公共目录 和 应用沙盒目录,只管 dcloud 对分区存储机制做了适配工作,但体系公共目录的操纵权限天然不如应用沙盒目录来的广泛、自由
而使用 uni.saveFile 可以将选择自相册(体系公共目录)的文件,另存到应用沙盒目录中,由此便可以规避各种各样的操纵标题了。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

郭卫东

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表