admin管理员组文章数量:1530518
该项目已发布到uniapp官方插件商店供大家免费使用借鉴:iso 安卓 文件下载模板 - DCloud 插件市场
在uniapp中提供了相应的文件下载api,但是无法对已下载的文件进行统一的管理。也不能对重复下载进行过滤。所以我封装了一个专用于处理app下载任务的组件。思路是通过本地缓存来保存我们所有下载文件的url,和名称等字段,将来在下载前进行筛选去重。下载成功更新这个缓存。放弃使用uniapp的api转用plus,这样可以更灵活的实现文件管理(调用原生api的io)。从而对下载文件进行增删改查。
相关代码已上传gitee,正在开源审核中。先上关键代码。
获取下载文件的地址,可以写成异步请求
getInfo() {
this.downLoadInfo.object.down_url = 'https://lmg.jj20/up/allimg/tp02/1Z9191923035R0-0-lp.jpg'
// console.log(this.downLoadInfo)
this.localStorageCheck()
},
//PLUS-APP封装下载
plusDownload() {
//拦截多次下载请求
if (!this.downLoadFlag || this.downloadStatus == 3) {
return
}
uni.showLoading({
title: '下载中...'
});
this.downLoadFlag = false
//设置不同平台的文件保存路径
if (plus.os.name == 'Android') {
//公共文件
// this.downloaderOptions = {
// filename: 'file://storage/emulated/0/xiaobaidownload/'+this.fileInfo.title
// }
//沙盒
this.downloaderOptions = {}
} else if (plus.os.name == 'iOS') {
// this.savePath ='/Library/Pandora/downloads'
//ios只能在沙盒内打开
this.downloaderOptions = {}
}
const url = this.downLoadInfo.object.down_url
// console.log(this.downLoadInfo)
this.dtask = plus.downloader.createDownload(url, {
...this.downloaderOptions //利用保存路径,实现下载文件的重命名
}, (d, status) => {
// 下载完成
if (status == 200) {
this.filePath = d.filename
// console.log(this.filePath)
this.canOpen = true //可以打开文件
this.downLoadFlag = true
//下载成功后操作缓存记录下载信息
try {
const item = {
name: this.downLoadInfo.title, //文件下载名
path: this.downLoadInfo.object.down_url, //可作为未下载文件的唯一标识
fullPath: d.filename // _downloads/****.png 可作为本地下载文件的唯一标识
}
this.downLoadInfoValue.data.push(item)
const value = JSON.stringify(this.downLoadInfoValue)
// console.log(value)
plus.storage.setItem("downLoadList_", value);
} catch (e) {
// error
console.log(e)
}
uni.showToast({
title: '下载成功'
})
uni.hideLoading()
} else {
console.log("Download failed: " + status);
this.dtask.clear() //清除下载器
uni.showToast({
title: '下载失败',
icon: 'error'
})
}
});
this.dtask.addEventListener('statechanged', (dtask) => {
if (!dtask) {
return;
}
// no default
switch (dtask.state) {
case 0:
// console.log('开始下载');
this.downloadStatus = 0
break;
case 2:
// console.log('链接到服务器...');
this.downloadStatus = 2
break;
case 3:
this.program = parseInt(dtask.downloadedSize / dtask.totalSize * 100)
this.downloadStatus = 3
break;
case 4:
// console.log('监听下载完成');
this.downloadStatus = 4
break;
case 5:
// console.log('下载任务已暂停');
this.downloadStatus = 5
break;
}
});
this.dtask.start();
// console.log(this.dtask)
},
//利用本地缓存进行下载管理
localStorageCheck() {
plus.storage.getItemAsync('downLoadList_', success => {
this.downLoadInfoValue = JSON.parse(success.data)
if (this.downLoadInfoValue.data.length != 0) {
this.beDownLoadedFlag = this.downLoadInfoValue.data.some(el => {
//对比请求来的接口数据和本地存在的value
this.filePath = el.fullPath
return el.path === this.downLoadInfo.object.down_url
})
if (this.beDownLoadedFlag) {
uni.showToast({
title: '本课件已下载,可直接打开',
icon: 'none'
})
}
} else if (this.downLoadInfoValue.data.length == 0) {
console.log('下载记录为空')
}
}, error => {
// console.log(error)
if (error.code == -3) {
// plus.storage.setItem('downLoadList', []);
uni.setStorage({ //这里的逻辑可以移植到登录页,登录成功后生成key
key: 'downLoadList_',
data: [],
success: () => {
this.downLoadInfoValue = JSON.parse(plus.storage.getItem(
"downLoadList_"))
console.log();
}
});
}
});
// console.log(plus.storage.getItem('downLoadList'))
},
pause(flag) {
if (flag === true) {
this.dtask.pause()
this.resumeOrpause = !this.resumeOrpause
} else if (flag === false) {
this.dtask.resume()
this.resumeOrpause = !this.resumeOrpause
}
},
openFile() {
plus.runtime.openFile(this.filePath);
// plus.runtime.openFile('/storage/emulated/0/Android/data/io.dcloud.HBuilder/downloads/厚涂入门技法讲解.pdf');
},
toFilesManagement() { //此方法不是该页面功能,下载页面不会再向下跳转。
uni.navigateTo({
url: '/pages/filelist/filelist'
})
},
openThis() {
//从缓存里取相应fullPath
plus.runtime.openFile(this.fullPath);
},
cancle() {
// 取消下载
console.log('取消下载')
plus.downloader.clear();
//删除未完成文件
this.$storemit('REMOVE_UNFINISHED_FILE', this.dtask.filename)
},
},
这里会出现个小问题就是如果是在文件没有下载完成的情况下,用户退出该页面。原理上讲,因为下载任务是调用了手机端的原生api和页面生命周期不构成关系。但是为了合乎使用逻辑,我在组件销毁后清除下载任务并删除为完成的文件。当然如果需要下载任务在后台运行的这里可以忽略。
mutations: {
REMOVE_UNFINISHED_FILE(state, value) {
plus.io.requestFileSystem(plus.io.PUBLIC_DOWNLOADS, entry => {
//创建目录对象的读取对象
var directoryReader = entry.root.createReader();
directoryReader.readEntries(fs => {
//使用some方法提高性能
fs.some((el,index,arr) => {
// console.log(index+'-'+arr.length)
if (el.toURL() === value) {
el.remove(success => {
console.log('删除未完成的:'+value)
}, e => {})
return true
}
})
})
}, e => {
console.log('error')
})
}
},
此处利用的是vuex的muations,因为在组件销毁前处理复杂逻辑业务需要时间,绝大多数是无法在组件销毁前完成的,所以转移到store里是比较不错的思路。
然后就是对下载文件的管理:这里用到了plus的文件管理系统api。默认路径为app的沙盒plus.io.PUBLIC_DOWNLOADS,相关的知识可以自行阅读plus文档。
plus.io.requestFileSystem(plus.io.PUBLIC_DOWNLOADS, entry => {
//创建目录对象的读取对象
this.directoryReader = entry.root.createReader();
this.list()
}, e => {
console.log('error')
})
//获取缓存文件列表
plus.storage.getItemAsync('downLoadList_', success => {
this.downLoadInfoValue = JSON.parse(success.data)
// console.log(this.downLoadInfoValue)
}, e => {
console.log('获取下载文件缓存失败')
})
上述代码写在onLoad函数,完成移动端对文件读写操作对象的实例化。
在plus和uniapp的api使用对比过程中,会发现其实uniapp只是对plus的大多数api进行了二次封装,比如打开文件这个功能,如果用plus会顺畅许多也不会有失效问题。而uniapp时常因为未知原因导致api失效,而plus不会。比如 plus.runtime.openFile(this.fullPath);,打开本地文件这个功能。
剩下的就是将缓存,本地文件还有下载任务的统一协调。总体思路并不复杂,关键还是不能局限于uniapp的有限api,毕竟uniapp的底层代码也都是调用的plus。希望大家看完鄙人的浅见能有所收获和启发。
版权声明:本文标题:uniapp 实现ios端和安卓端的文件下载,多文件管理 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dongtai/1725194754a1012314.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论