uni-app、H5+ 下载并保存、打开文件

2023-12-30 12:24:11


前言

紧接 上一篇保存图片到相册 ,项目中还有一个根据条件导出 Excel 文件并要求保存到手机上的需求,接下来也将分别介绍 uni-app 及 H5+ 两种方案。

一、uni-app 实现方案

1. H5 端发送消息

uni.webView.postMessage({
    data: {
        operType: 'saveFile',
        url: 'http://www.test.com/exportExcel',
        token: '123',
        params: {
            key1: 'value1',
            key2: 'value2'
        }
    }
});

2. uni-app 下载文件并保存

<template>
    <view>
        <web-view src="/hybrid/html/index.html" @message="handleMessage"></web-view>
    </view>
</template>

<script>
export default {
    methods: {
	    handleMessage(e) {
			const [opts] = e.detail.data; // e.detail.data 得到的是一个消息数组
			this.downloadFile(opts);
		},
		// 下载文件
		downloadFile(opts) {
			let {
				url,
				token,
				operType,
				params
			} = opts;
			if (params) url = url + JSON.stringify(params);
			uni.downloadFile({
				url,
				// timeout: 30000, 超时时间
				header: { token }, // 下载文件需要传递的请求头参数都设置在 header 对象中
				success: res => {
					const {
					    statusCode,
					    tempFilePath // 临时文件路径,下载后的文件会存储到一个临时文件
					} = res;
					console.log(tempFilePath);
					if (statusCode === 200) {
						console.log('下载文件成功');
						if (operType === 'saveImg') {
							this.saveImg(tempFilePath);
						}
						if (operType === 'saveFile') {
							this.saveFile(tempFilePath);
						}
					} else {
						uni.showToast({
							title: '下载文件失败'
						});
					}
				}
			})
		},
		// 保存文件
		saveFile(filePath) {
			uni.saveFile({
				tempFilePath: filePath,
				success: (res) => {
					uni.showToast({
						title: '文件保存成功'
					});
					console.log('文件保存成功,路径为:' + res.savedFilePath)
				},
				fail: (err) => {
					console.log('文件保存失败:' + err)
				}
			})
		},
	}
}
</script>

因为 uni.downloadFile 只支持 get 请求,原本导出 Excel 的后端请求是 post,参数都放在 body 中,与后端协商之后改为 get 方式,参数使用 url 中的 params 接收一个经过 JSON.stringify 转换的对象字符串。

uni.saveFile 保存成功之后,但无法设置文档的存放位置,而实际文档存放的位置对于用户来说又比较难找到,比如这是一个用 HBuilderX + 夜神模拟器调试 时打印的存储路径:

/storage/emulated/0/Android/data/io.dcloud.HBuilder/apps/HBuilder/doc/uniapp_save/17038344728620.xls

3. uni-app 打开文档

将保存文档的操作修改为了打开文档,打开文档之后用户可自行通过wx等分享此文档。以下为修改之后的代码:

<template>
    <view>
        <web-view src="/hybrid/html/index.html" @message="handleMessage"></web-view>
    </view>
</template>

<script>
export default {
    methods: {
	    handleMessage(e) {
			const [opts] = e.detail.data; // e.detail.data 得到的是一个消息数组
			this.downloadFile(opts);
		},
		// 下载文件
		downloadFile(opts) {
			let {
				url,
				token,
				operType,
				params
			} = opts;
			if (params) url = url + JSON.stringify(params);
			uni.downloadFile({
				url,
				// timeout: 30000, 超时时间
				header: { token }, // 下载文件需要传递的请求头参数都设置在 header 对象中
				success: res => {
					const {
					    statusCode,
					    tempFilePath // 临时文件路径,下载后的文件会存储到一个临时文件
					} = res;
					console.log(tempFilePath);
					if (statusCode === 200) {
						console.log('下载文件成功');
						if (operType === 'saveImg') {
							this.saveImg(tempFilePath);
						}
						if (operType === 'saveFile') {
							// this.saveFile(tempFilePath);
							this.openFile(tempFilePath);
						}
					} else {
						uni.showToast({
							title: '下载文件失败'
						});
					}
				}
			})
		},
		// 保存文件
		saveFile(filePath) {
			uni.saveFile({
				tempFilePath: filePath,
				success: (res) => {
					uni.showToast({
						title: '文件保存成功'
					});
					console.log('文件保存成功,路径为:' + plus.io.convertLocalFileSystemURL(res.savedFilePath));
				},
				fail: (err) => {
					console.log('文件保存失败:' + err);
				}
			})
		},
		// 打开文档
		openFile(filePath) {
			let platform = uni.getSystemInfoSync().platform; //当前环境
			if (platform == 'ios') {
				filePath = escape(filePath);
			}
			uni.openDocument({
				filePath,
				showMenu: true,
				success: function(res) {
					console.log('打开文档成功');
				},
				fail: function(e) {
					console.log(e);
					uni.showToast({
						title: '打开失败'
					})
				}
			});
		},
	}
}
</script>
  • uni.openDocument 的参数配置项中 showMenu: true 用于设置右上角是否有可以转发分享的功能
  • 下载的文件名中会包含中文字符,在执行打开文档方法的时候会在 ios 系统中打开文件失败,查找到一个解决方案是针对 ios 系统将 filepath 经过 escape() 转换之后就可正常打开

二、H5+ 实现方案

let params: {
    key1: 'value1',
    key2: 'value2'
}
let url = `http://www.test.com/exportExcel?params=${JSON.stringify(params)}`
let fileName = '测试.xls'
let options = {
	filename: `_downloads/${fileName}`,
	// timeout: 120 // 超时时间单位s,默认120s
}
let header = {
	token: '123'
}
plusDownloadFile(url, options, header)

// H5下载文件
plusDownloadFile(url, options = {}, header = {}) {
    let dtask = plus.downloader.createDownload(url, options, (d, status) => {
        if (status == 200) {
            this.$showToast.ok( '下载成功' );
            console.log('文件存储路径:' + d.filename);
            // 调用打开文件方法
            plus.runtime.openFile(options.filename);
        } else {
            this.$showToast.error('下载失败');
            plus.downloader.clear();
        }
    });
    Object.keys(header).forEach(k => {
    	dtask.setRequestHeader(k, header[k]);
    });
    // 开始下载
    dtask.start();
},

总结

  • 经过在项目中测试验证,两种方案都能下载并打开文件。
  • H5+ 的下载是支持 post 请求方式,请求参数是放在 options 的 data 中,不过需要注意这个 data 只接收 string 类型的参数,对象形式可通过 JSON.stringify 先转换,但是和 uni.downloadFile 一样都需要服务端支持,下载的请求接收参数拿到字符串之后再通过 JSON.parse 解析。
  • H5+ 的下载是支持修改文件的保存路径为以"_downloads/“、”_doc/“、”_documents/"开头的字符串,uni-app 的方式不支持。

文章来源:https://blog.csdn.net/qq_42966167/article/details/135287027
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。