uni小程序, 嵌入原生app, 文件下载到指定目录的实现方式

uni小程序, 嵌入原生app, 文件下载到指定目录的实现方式

  • 实现该功能的时候, 两个问题需要解决, 1.uni.openDocument,只能打开几个常规后缀的文件 2. 下载文件下到了沙盒里面. _download开头的内部路径, 用户下次找不到了
    为解决这两个问题, 我也是做了很多尝试, 现在将最终实现方式记录分享, 希望对你有些帮助
  1. 使用 plus.runtime.openFile 打开文件, 没有文件格式限制, 遇到打不开的文件时, 会有异常回调可以使用, 提示用户安装相关软件即可.
  2. 利用plus.downloader.createDownload 下载文件文档上说明只能保存到_dowloads, _doc,等几个固定开头的沙盒文件夹里, 所以只能扩展原生Moudle, 将文件移动到Download文件夹下

一下是代码部分,仅供参考

  • 原生部分代码, 自定义Module,复制文件,一定要提前获取到用户的读写数据的权限!!!, 否则会提示权限问题, 文件无法复制
public class UniUesOaHeModule extends UniModule {

    /**
     * 输出日志
     */
    @UniJSMethod(uiThread = false)
    public void uniLog(String s) {
        XLog.debug(s);
    }

    /**
     * 沙盒文件移入媒体库
     */
    @UniJSMethod(uiThread = false)
    public void scanIntoMedia(String filePath, UniJSCallback callback) {
        if (StringUtil.isEmpty(filePath)) {
            if (callback != null) {
                JSONObject data = new JSONObject();
                data.put("code", "error");
                data.put("message", "文件路径不能为空");
                callback.invokeAndKeepAlive(data);
            }
        }
        if (mUniSDKInstance != null) {
            String[] split = filePath.split("/");
            String fileName = split[split.length -1];
            String targetPath = "/storage/emulated/0/Download/" + fileName;

            FileUtil fileUtil = FileUtil.INSTANCE;
            XLog.debug("开始转义目录");
            XLog.debug("由:[ " + filePath + " ] 转移至 : [ "+ targetPath + " ]");
            //tod
            fileUtil.copyFileWithFileChannel(new File(filePath), new File(targetPath));

            //对于小米来说, 拷贝到Downloads文件夹下, 系统就会自动扫描到了, 不知道其他机型怎么样
            //图片等常规文件,能出现在 `最近`里, dwg在Download里能找到, 但是不会在 `最近` 里显示,可能是系统原因
            Context context = mUniSDKInstance.getContext();
            Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
            Uri contentUri = Uri.parse(targetPath);
            XLog.debug("将要扫描的地址是: " + contentUri.getPath());
            mediaScanIntent.setData(contentUri);
            context.sendBroadcast(mediaScanIntent);
            XLog.debug("发送扫描指令");
            if (callback != null) {
                JSONObject data = new JSONObject();
                data.put("code", "success");
                data.put("message", "添加到Download目录成功");
                data.put("filePathAfterMove", "file:/"+ targetPath);
                callback.invokeAndKeepAlive(data);
            }
        }else{
            XLog.debug("实例不存在");
            if (callback != null) {
                JSONObject data = new JSONObject();
                data.put("code", "error");
                data.put("message", "实例不存在");
                callback.invokeAndKeepAlive(data);
            }
        }

        /**
         * 下面的不管用, 可能是只能扫描固定的几个媒体库路径, 上面的直接复制到Downloads下, 不用扫描都能发现
         */
//
//        if (StringUtil.isEmpty(filePath)) {
//            if (callback != null) {
//                JSONObject data = new JSONObject();
//                data.put("code", "error");
//                data.put("message", "文件路径不能为空");
//                callback.invokeAndKeepAlive(data);
//            }
//        }
//        if (mUniSDKInstance != null) {
//            Context context = mUniSDKInstance.getContext();
//            try {
//                MediaScannerConnection.scanFile(context, new String[]{filePath}, null,
//                        new MediaScannerConnection.OnScanCompletedListener() {
//                            public void onScanCompleted(String path, Uri uri) {
//                                XLog.debug("扫描的路径是: " + path + ":");
//                                XLog.debug("返回的uri: " + uri);
//                                if (callback != null) {
//                                    JSONObject data = new JSONObject();
//                                    data.put("code", "success");
//                                    data.put("message", "媒体库扫描完成!!!!");
//                                    callback.invokeAndKeepAlive(data);
//                                }
//                            }
//                        });
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//        } else {
//            if (callback != null) {
//                JSONObject data = new JSONObject();
//                data.put("code", "error");
//                data.put("message", "移入媒体库失败, 找不到mUniSDKInstance实例");
//                callback.invokeAndKeepAlive(data);
//            }
//        }
    }

}
  • FileUtil, 只贴这一个复制文件的函数
/**
     * 复制文件
     */
    fun copyFileWithFileChannel(fileSource: File, fileDest:File) {
        var fi: FileInputStream? = null
        var fo: FileOutputStream? = null
        var `in`: FileChannel? = null
        var out: FileChannel? = null
        try {
            fi = FileInputStream(fileSource)
            fo = FileOutputStream(fileDest)
            `in` = fi.channel//得到对应的文件通道
            out = fo.channel//得到对应的文件通道
            `in`!!.transferTo(0, `in`.size(), out)//连接两个通道,并且从in通道读取,然后写入out通道
        } catch (e: IOException) {
            e.printStackTrace()
        } finally {
            try {
                fi!!.close()
                `in`!!.close()
                fo!!.close()
                out!!.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
    }

别忘记注册组件
UniSDKEngine.registerModule(“UniUesOaHeModule”, UniUesOaHeModule::class.java)

uni小程序代码, download2是最终使用的方法, 其他的是测试时使用的

<template>
	<!-- 这是图纸展示页面 -->
	<page-head title="无匹配数据" v-if="designDrawingArray.length == 0"></page-head>
	<view v-else>
		<!-- {{designDrawingArray}} -->
		<view v-for="(item, index) in designDrawingArray" :key="item.id">
			<!-- {{ item.name }} - {{ item.remark }} -->
			<uni-card :title="item.name" :sub-title="item.remark">
				<view v-if="item.attachmentList.length > 0">
					<uni-list>
						<uni-list-item v-for="(attachmentItem, attachmentIndex) in item.attachmentList"
							:key="attachmentItem.id" :title="attachmentItem.attachName"
							@click="download2(attachmentItem.attachUrl,attachmentItem.attachSize)" showArrow link>
						</uni-list-item>
					</uni-list>
				</view>
				<view v-else>
					暂无图纸
				</view>
			</uni-card>
		</view>
	</view>
</template>

<script>
	import config from "@/common/config.js"
	var uniUesOaHeModule = uni.requireNativePlugin("UniUesOaHeModule")

	export default {
		data() {
			return {
				designDrawingArray: []
			}
		},
		onLoad(e) {
			var contractType = e.contractType
			var contractId = e.contractId
			this.queryHeDesignDrawingWithAttachmentList(contractType, contractId)
		},
		methods: {
			queryHeDesignDrawingWithAttachmentList(contractType, contractId) {
				this.$http.post({
					url: '/engineering/queryHeDesignDrawingWithAttachmentList.action',
					data: {
						contractType: contractType,
						contractId: contractId
					},
					success: (res) => {
						console.log(res)
						if (res.status == 200) {
							this.designDrawingArray = res.data
						}
					}
				})
			},
			// 该方法不再使用, openDocument只能打开常用格式的文件, 不能打开dwg
			downLoadAttachment(url) {
				var downloadUrl = config.serverUrl + url
				console.log("下载地址---" + downloadUrl)
				uni.showModal({
					title: '提示',
					content: '确定下载该图纸?',
					success: function(res) {
						if (res.confirm) {
							uni.showLoading({
								title: '下载中'
							})
							var self = this
							uni.downloadFile({
								url: downloadUrl,
								success: (res) => {
									//保存到本地
									console.log("下载成功,临时路径是---" + res.tempFilePath)
									uni.saveFile({
										tempFilePath: res.tempFilePath, //文件的临时路径
										success: function(res) {
											const savedFilePath = res.savedFilePath;
											uni.showToast({
												title: '将临时文件保存完成,保存的地址为:' +
													savedFilePath,
												icon: 'none'
											});
											uni.hideLoading();
											uni.showModal({
												title: '提示',
												content: '打开下载文件?',
												success: function(res) {
													// 打开文件
													if (res.confirm) {
														uni.showToast({
															title: '点击了确定打开文件',
															icon: 'none'
														});
														uni.openDocument({
															filePath: savedFilePath,
															showMenu: true,
															success: function(
																res
															) {
																console
																	.log(
																		'打开文档成功'
																	);
																uni.showToast({
																	title: '打开文档成功',
																	icon: 'none'
																});
															},
															fail: function(
																res
															) {
																console
																	.log(
																		'打开文档失败'
																	);
																uni.showToast({
																	title: '打开文档失败',
																	icon: 'none'
																});
															}
														});
													}
												}
											})
										},
										fail: function(err) {}
									});
								},
								fail: (err) => {
									uni.showToast({
										title: '下载失败',
										icon: 'none'
									});
								}
							})
						}
					}
				});
			},
			download2(url,fileSize) {
				var logger = this.$log
				var downloadUrl = config.serverUrl + url
				logger(uniUesOaHeModule, "下载地址---" + downloadUrl)
				
				//测试方便,使用390576, 正式使用下面50M
				// if(fileSize > 1000 * 1000 * 50){
				if(fileSize > 390576){
					logger(uniUesOaHeModule, "文件大于50M,使用浏览器下载: "+ fileSize)
					plus.runtime.openURL(downloadUrl)
				}else{
					logger(uniUesOaHeModule, "文件小于50M: "+ fileSize)
					var pathArray = url.split('/')
					var fileName = pathArray[pathArray.length - 1]
					uni.showLoading({
						title: '下载中'
					})
					let dtask = plus.downloader.createDownload(downloadUrl, {
						//利用保存路径,实现下载文件的重命名,文档上说明只能保存到_dowloads, _doc,等几个固定开头的沙盒文件夹里,
						// filename:localFile  
					}, function(d, status) {
						uni.hideLoading();
						if (status == 200) {
							//下载成功,d.filename是文件在保存在本地的相对路径,使用下面的API可转为平台绝对路径
							logger(uniUesOaHeModule, "下载完成了,现在要去打开文件,文件地址也就是d.fileName: " + d.filename)
							let fileSaveUrl = plus.io.convertLocalFileSystemURL(d.filename);
							logger(uniUesOaHeModule, "将d.fileName 沙盒文件路径转化为android平台的路径: " + fileSaveUrl)
					
							//这样下载打开文件, 除非用户自己操作或移动到自己知道的文件夹下, 下次他就找不到了, 因此调用原生Module,将这个文件放到/Download下,下次能看到
							uniUesOaHeModule.scanIntoMedia(fileSaveUrl,
								(ret) => {
									console.log(JSON.stringify(ret))
									if(ret.code == 'success'){
										//文件转移到Download目录成功了
										plus.runtime.openFile(ret.filePathAfterMove,{},function(error){
											logger(uniUesOaHeModule,"打开文件有问题: "+ JSON.stringify(error))
											uni.showToast({
												title: '没有能打开该文件的软件,请安装',
												icon: 'none',
												duration: 3000
											});
										});
									}
								})
						} else {
							uni.showToast({
								title: '下载失败',
								icon: 'none',
								duration: 3000
							});
							plus.downloader.clear(); //清除下载任务
						}
					})
					dtask.addEventListener("statechanged", function(task, status) {
						logger(uniUesOaHeModule, "task:" + JSON.stringify(task) + "===========status" + status)
						switch (task.state) {
							case 2:
								break;
							case 3:
								let prg = parseInt((parseFloat(task.downloadedSize) / parseFloat(task.totalSize)) *100);
								// logger(uniUesOaHeModule, prg + "%")
								break;
							case 4:
								break;
						}
					}, false);
					dtask.start();
				}
			},
			test(url, fileSize){
				var logger = this.$log
				var downloadUrl = config.serverUrl + url
				logger(uniUesOaHeModule, "下载地址---" + downloadUrl)
				// uni.showToast({
				// 	title: '测试打开外部文件',
				// 	icon: 'none'
				// });
				// plus.runtime.openFile("file://storage/emulated/0/Download/e96cca6878b14911940c4ad9db8e1ff7_a(9).jpg",{},function(error){
				// 	// logger(uniUesOaHeModule,"打开文件出错: "+ JSON.stringify(error))
				// 	console.log(JSON.stringify(error))
				// 	uni.showToast({
				// 		title: '1111111111',
				// 		icon: 'none'
				// 	});
				// });
				//大于50M, 建议使用浏览器下载
				
				if(fileSize > 1000 * 1000 * 50){
					logger(uniUesOaHeModule, "文件大于50M: "+ fileSize)
				}else{
					logger(uniUesOaHeModule, "文件小于50M: "+ fileSize)
				}
				plus.runtime.openURL(downloadUrl)
			}
		}
	}
</script>

<style>

</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值