3***@qq.com
3***@qq.com
  • 发布:2022-09-02 15:39
  • 更新:2022-09-02 15:39
  • 阅读:2242

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

分类:uni小程序sdk

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>  
2 关注 分享
dev_pz 晓贰丑

要回复文章请先登录注册