uniapp在安卓10+情况下移动文件的解决方案
首先看一个简单的问题,就是uniapp如何将下载的图片保存到手机本地,直接看下面的代码
const imgUrl = 'https://fanyi-cdn.cdn.bcebos.com/static/translation/img/header/logo_e835568.png'
let dtask = plus.downloader.createDownload(imgUrl, {
//1.本地路径开头使用file://;
//2.Android平台本地绝对路径为"storage/emulated/0",就是用户文件管理器能看到的了;
//3.创建"xxx"作为文件夹名称,后缀是用于文件命名和格式修改,大家可以使用变量。
filename: 'file:///storage/emulated/0/nameplate/' + filename //利用保存路径,实现下载文件的重命名
}, (d, status) => { //d为下载的文件对象;status下载状态
// console.log(d, status)
if(status == 200){
//d.filename是文件在保存在本地的相对路径,使用下面的API可转为平台绝对路径
// let fileSaveUrl = plus.io.convertLocalFileSystemURL(d.filename)
// plus.runtime.openFile(d.filename); //选择软件打开文件
uni.showToast({
title: '保存成功',
duration: 2000
})
} else {
uni.showToast({
title: '保存失败',
duration: 2000
})
}
})
dtask.start()
主要说明一个问题,就是安卓平台本地路径的问题,'file:///storage/emulated/0/nameplate/' + filename
这行代码实际上是在用户打开安卓手机文件管理器的根目录下的nameplate文件夹下下载指向imgUrl链接的图片,如果没有nameplate文件夹,则会新建一个文件夹
回到主题,有这么个需求,手机在离线情况下,app拍了一张照片,如何把这张照片保存在手机本地呢?写了三天的bug终于搞通了
这个问题困扰了我好几天的时间,主要遇到了的是下面这个问题:
安卓10+平台,APP不能直接将文件存储到任何的本地目录,通俗来说,就是没有手机文件夹的访问权限,所以,如果想要像上面那样,把文件移动或者复制到nameplate文件夹下,根本做不到,不要问为啥下载图片可以做到,这根本就不是同一个概念。这里的保存图片,是将刚刚拍摄的照片(这个照片是临时的,不要选择原图)存在了应用下的一个沙盒目录里,注意,**“应用下”**很重要。相当复杂,根本解释不明白,笑死,这里给个链接,就是涉及到code: 15
报错时的解决方案
适配Android10+设备注意事项
博主非安卓开发,看的一知半解,大概意思就是,uniapp开发的安卓应用,只能在自己的应用下对文件进行读写,官方称之为沙盒目录,当然,也可以访问有限几个公共目录,诸如相册、音乐之类的
那这不完蛋了,那开发的安卓应用要使用手机里面的文件可咋办,怎么说呢,无解,很头疼
再次回到主题,手机离线状态下,用开发的app拍了一张照片,然后想把这张照片保存在手机本地,等有网络后再次发给谁,这个需求相对的怪异对不对,也别管了,我自己都觉得怪异,反正就是这么个需求。
那么,要明确这么几个问题
-
安卓10+,uniapp开发的应用只能读写应用目录下的文件,也就是沙盒里面的文件
-
承接上面的问题,不管是拍照,还是直接选取本地的图片,那么,想要移动这个图片,就不能选原图了,因为选择原图之后,图片路径指向就到了沙盒外面,所以这个问题要注意
-
那么,怎么移动图片呢,推荐使用plus.io中的moveTo(直接移动)或copyTo(复制)方法,经测,这两个都可行,网上都说copy好用而move不好用,我不知道他们的具体问题是啥,所以也不好评价他们为啥会得出这么怪异的结论
-
既然说到用moveTo方法,那看看uniapp怎么说的,它说moveTo只支持沙盒目录,正好印证了上面我说的,移动文件只能在应用目录下面
以下是针对
分区存储
机制作出文件操作目录限制的5+API:- plus.io中的getAudioInfo、getVideoInfo、getFileInfo、getImageInfo仅支持应用沙盒目录和系统公共目录
- plus.io中的DirectoryEntry对象的removeRecursively、getDirectory、getFile、remove、copyTo、moveTo仅支持应用沙盒目录
- plus.io中的DirectoryEntry对象的getMetadata 、getParent仅支持应用沙盒目录和系统公共目录
- DirectoryReader.readEntries仅支持应用沙盒目录和系统功能目录
- FileWriter.write、FileWriter.truncate、FileReader.readAsText仅支持应用沙盒目录
- plus.camera.CameraOptions中的filename仅支持应用沙盒目录。
- plus.gallery.save中的path仅支持应用沙盒目录。
- plus.zip.compress中的src、zipfile仅支持应用沙盒目录。
- plus.zip.decompress中的zipfile、target仅支持应用沙盒目录。
- plus.zip.CompressImageOptions中的dst仅支持应用沙盒目录、src仅支持应用沙盒目录和系统公共目录。
- plus.map相关的plus.maps.Marker.setIcon、setIcons、plus.maps.Bubble.setIcon图片地址仅支持应用沙盒目录。
- plus.nativeObj.Bitmap.save中的path 仅支持应用沙盒目录。
- plus.video.VideoPlayerStyles中的src仅支持应用沙盒目录和系统公共目录。
- plus.nativeUI.toast自定义ToastStyles后android11设备不支持应用进入后台弹出toast显示。
以上API设置了不支持的目录部分会返回code =15的错误信息!,部分会返回执行失败的错误回调具体以API为准!
-
那么,到底该怎么写代码呢,官方也没说,它只给了一个沙盒目录的写法,如下,怎么被坑的,就是被这个官方推荐的链接给坑的。经过好几天的实测,发现文件的移动应该是在外部存储空间目录,就是
file:///storage/emulated/0/Android/data/%PACKAGENAME%/.%APPID%/documents
这个东西,但是它给错了,经测,正确写法是file:///storage/emulated/0/Android/data/%PACKAGENAME%/apps/%APPID%/doc
,当然,这个目录其实要自己打印,可能每个安卓版本都不一样,所以我才会被坑了如此之久应用沙盒目录分为:
- 内部存储空间目录
- plus.io.PRIVATE_WWW 对应绝对路径
file:///data/user/0/%PACKAGENAME%/files/apps/%APPID%/www
- plus.io.PRIVATE_DOC 对应绝对路径
file:///data/user/0/%PACKAGENAME%/files/apps/%APPID%/doc
- plus.io.PRIVATE_WWW 对应绝对路径
- 外部存储空间目录
- plus.io.PUBLIC_DOCUMENTS 对应绝对路径
file:///storage/emulated/0/Android/data/%PACKAGENAME%/.%APPID%/documents
- plus.io.PUBLIC_DOWNLOADS 对应绝对路径
file:///storage/emulated/0/Android/data/%PACKAGENAME%/.%APPID%/downloads
- plus.io.PUBLIC_DOCUMENTS 对应绝对路径
- 内部存储空间目录
到了这里,前因后果都说的差不多了,可以上代码了
我把相关的代码放上来
启动相机部分
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
that.resShow = true
let filepath = res.tempFilePaths[0]
that.phtotoUrl = filepath
}
})
这段代码是拍摄图片时需要用到的,注意看,sizeType有两个可选参数,一个是原图’original’,还有一个就是压缩图’compressed’,我这里只选了压缩图,是因为我发现选择原图的话,后面又会报错,就是下面这个让人头疼的报错,主要原因还是原图不在沙盒目录下,选择压缩图,会在应用目录下面创建一个临时的文件路径
{"code":15,"message":"targetSdkVersion设置>=29后在Android10+系统设备不支持当前路径。请更改为应用运行路径!具体请看:https://ask.dcloud.net.cn/article/36199"}
文件移动部分
moveDirecty(){
const oldPath = this.phtotoUrl
const newLocalPath = 'file:///storage/emulated/0/Android/data/%PACKAGENAME%/apps/%APPID%/doc'
const filename = '/' + Date.now() + '.png'
plus.io.resolveLocalFileSystemURL(newLocalPath, function(entry1){
console.log('新目录----'+entry1.fullPath)
plus.io.resolveLocalFileSystemURL(oldPath, function(entry2) {
console.log('旧文件---'+entry2.fullPath)
entry2.moveTo(entry1, filename, function(res){
console.log('移动成功')
}, function(e){
console.log('内层移动失败'+JSON.stringify(e))
})
}, function(e){
console.log('移动失败'+JSON.stringify(e))
})
}, function(e){
console.log('外层操作失败'+JSON.stringify(e))
})
}
上面说了这么多,到这里应该差不多了,不过这里一串的异步代码,让人看了非常无语,没办法,只能这么写了,上面的这个代码其实也搞了很久才搞明白,下面解释一下
plus.io.resolveLocalFileSystemURL
这个是安卓解析路径的方法,它有一个参数和一个回调函数,参数就是文件路径,回调函数只有一个参数,它是个啥玩意儿呢,就是将你前面传递的文件路径解析出来
这里我嵌套了两层plus.io.resolveLocalFileSystemURL
,一个解析原图片的路径,一个解析目标文件的路径,最里层就正儿八经的用到了moveTo这个方法,注意写法,是解析出来的对象再调用这个方法,entry2是旧目录,moveTo传递2个参数和一个回调函数,第一个参数是解析后的新目录,第二个参数类似重命名,回调函数就是成功与否了文章来源:https://www.toymoban.com/news/detail-433772.html
还有一个坑,就是这几个回调函数能不能写成箭头函数的问题,我一度以为自己已经完全吃透了箭头函数的写法,但从现实来看,并没有,之前我这里都写的是箭头函数,因为疯狂报错,我全部改成了原始的写法,但我不确定到底是哪个错误引起的,箭头函数不一定背这个锅。如果还没完全搞明白箭头函数怎么写,还是老老实实写回原始的吧。文章来源地址https://www.toymoban.com/news/detail-433772.html
到了这里,关于uniapp在安卓10+情况下移动文件的解决方案的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!