uniapp在安卓10+情况下移动文件的解决方案

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拍了一张照片,然后想把这张照片保存在手机本地,等有网络后再次发给谁,这个需求相对的怪异对不对,也别管了,我自己都觉得怪异,反正就是这么个需求。

那么,要明确这么几个问题

  1. 安卓10+,uniapp开发的应用只能读写应用目录下的文件,也就是沙盒里面的文件

  2. 承接上面的问题,不管是拍照,还是直接选取本地的图片,那么,想要移动这个图片,就不能选原图了,因为选择原图之后,图片路径指向就到了沙盒外面,所以这个问题要注意

  3. 那么,怎么移动图片呢,推荐使用plus.io中的moveTo(直接移动)或copyTo(复制)方法,经测,这两个都可行,网上都说copy好用而move不好用,我不知道他们的具体问题是啥,所以也不好评价他们为啥会得出这么怪异的结论

  4. 既然说到用moveTo方法,那看看uniapp怎么说的,它说moveTo只支持沙盒目录,正好印证了上面我说的,移动文件只能在应用目录下面

    以下是针对分区存储机制作出文件操作目录限制的5+API:

    以上API设置了不支持的目录部分会返回code =15的错误信息!,部分会返回执行失败的错误回调具体以API为准!

  5. 那么,到底该怎么写代码呢,官方也没说,它只给了一个沙盒目录的写法,如下,怎么被坑的,就是被这个官方推荐的链接给坑的。经过好几天的实测,发现文件的移动应该是在外部存储空间目录,就是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.PUBLIC_DOCUMENTS 对应绝对路径 file:///storage/emulated/0/Android/data/%PACKAGENAME%/.%APPID%/documents
      • plus.io.PUBLIC_DOWNLOADS 对应绝对路径 file:///storage/emulated/0/Android/data/%PACKAGENAME%/.%APPID%/downloads

到了这里,前因后果都说的差不多了,可以上代码了

我把相关的代码放上来

启动相机部分

				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个参数和一个回调函数,第一个参数是解析后的新目录,第二个参数类似重命名,回调函数就是成功与否了

还有一个坑,就是这几个回调函数能不能写成箭头函数的问题,我一度以为自己已经完全吃透了箭头函数的写法,但从现实来看,并没有,之前我这里都写的是箭头函数,因为疯狂报错,我全部改成了原始的写法,但我不确定到底是哪个错误引起的,箭头函数不一定背这个锅。如果还没完全搞明白箭头函数怎么写,还是老老实实写回原始的吧。

猜你喜欢

转载自blog.csdn.net/u012848304/article/details/130134091
今日推荐