【vue】Uniapp 打包Android 文件选择上传问题详解~

需求

uniapp兼容android app,pc,h5的文件选择并上传功能。

需要支持拍照和相册选择,以及选择其他类型文件上传~

实践过程和问题

开始使用uni-file-picker组件

以为很顺利,android模拟器测试……

忽略了平台兼容性提示~😭

Get:上传图片或拍照,使用uniapp自带的uni.chooseImage即可……

还需要上传非媒体问题(图片、音频、影片)。本以为uni.chooseFile就OK了~

But

提示

uniapp提示:Android端可以使用Native.js

  • App端如需选择非媒体文件,可在插件市场搜索文件选择,其中Android端可以使用Native.js,无需原生插件,而iOS端需要原生插件。
  • App端如果想选择下载到_doc、_downloads、_documents等plus.io控制的目录下的文件,可通过plus.io Api,自己做选择框。

官方提示到此为止~

AI求解

于是,开始了漫长的AI问答……

deepseek、豆包、文心全问一遍~(其实内核是不是都deepseek🙂)

都”快速“给出答案代码,然而”打包“测试已经没反应;好一点的依旧只能选图片~

举一个栗子~

问:Android端使用Native.js进行选择文件上传

答:

1. 配置权限

manifest.json文件中配置文件读取权限:


{
    "plus": {
        "permission": {
            "readExternalStorage": {
                "desc": "读取设备外部存储空间的文件",
                "android": {
                    "name": "android.permission.READ_EXTERNAL_STORAGE"
                }
            }
        }
    }
}

2. 编写选择文件的 Native.js 代码

在页面的<script>标签内或单独的 JS 文件中编写选择文件的逻辑:


function pickFile(callback) {
    const Intent = plus.android.importClass('android.content.Intent');
    const intent = new Intent(Intent.ACTION_GET_CONTENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    // 设置选择所有类型文件
    intent.setType('*/*'); 

    plus.android.startActivityForResult(intent, function (intentData) {
        if (intentData) {
            const uri = intentData.getData();
            const ContentResolver = plus.android.importClass('android.content.ContentResolver');
            const cursor = plus.android.invoke(plus.android.runtimeMainActivity, 'getContentResolver')
              .query(uri, ['_data'], null, null, null);
            if (cursor.moveToFirst()) {
                const columnIndex = cursor.getColumnIndex('_data');
                const filePath = cursor.getString(columnIndex);
                cursor.close();
                callback(filePath);
            }
        }
    });
}

3. 编写上传文件的代码

结合uni.uploadFile方法来上传选择的文件:

<template>
    <view class="container">
        <button @click="pickAndUpload">选择并上传文件</button>
    </view>
</template>

<script>
export default {
    methods: {
        pickAndUpload() {
            pickFile((filePath) => {
                if (filePath) {
                    this.uploadFile(filePath);
                } else {
                    uni.showToast({
                        title: '未选择文件',
                        icon: 'none'
                    });
                }
            });
        },
        uploadFile(filePath) {
            uni.uploadFile({
                url: 'https://your - server - url.com/api/upload', // 替换为实际的上传接口地址
                filePath: filePath,
                name: 'file',
                success: function (res) {
                    console.log('文件上传成功', res.data);
                    uni.showToast({
                        title: '文件上传成功',
                        icon:'success'
                    });
                },
                fail: function (err) {
                    console.log('文件上传失败', err);
                    uni.showToast({
                        title: '文件上传失败',
                        icon: 'none'
                    });
                }
            });
        }
    }
};
</script>

<style scoped>
.container {
    padding: 20px;
}
</style>

很详细~

然而只有一个问题:不work!

o(╯□╰)o

正确答案

最后还在uniapp的论坛上找到了答案,已经通过android app测试,可用~

使用原生的Native.js调用📱平台的文件管理器,选择文件并向上传文件的相关方法传递所选文件的正确路径。

如果会安卓原生编程,代码so easy。

// from DCloud
window.PickFile = function(callback,acceptType){  
    function ip(obj){  
        plus.android.importClass(obj);  
        return obj;  
    }  
    if(plus.os.name == 'Android' && typeof callback == 'function'){  
        var CODE_REQUEST = 1000;  
        var context = plus.android.runtimeMainActivity();  
        ip(context);  
        var Intent = plus.android.importClass('android.content.Intent');  
        var intent = new Intent(Intent.ACTION_GET_CONTENT);  
        intent.addCategory(Intent.CATEGORY_OPENABLE);  
        if(acceptType){  
            intent.setType(acceptType);  
        }else{  
            intent.setType("*/*");  
        }  
        context.onActivityResult = function(requestCode,resultCode,intentData){  
            if(requestCode == CODE_REQUEST){  
                if(intentData){  
                    var uriValue = intentData.getData();  
                    plus.android.importClass(uriValue);  
                    var scheme = uriValue.getScheme();  
                    if(scheme == 'content'){//还需要进行数据库查询,一般图片数据  
                        var cursor = ip(context.getContentResolver()).query(uriValue,['_data'], null, null, null);  
                        if(cursor){  
                            ip(cursor).moveToFirst();  
                            var columnIndex = cursor.getColumnIndex('_data');  
                            picturePath = cursor.getString(columnIndex);  
                            cursor.close();  
                            callback(picturePath);//返回文件路径  
                        }  
                    }else if(scheme == 'file'){  
                        callback(uriValue.getPath());//返回文件路径  
                    }  
                }else{  
                    callback(null);  
                }  
            }  
        }  
        context.startActivityForResult(intent,CODE_REQUEST);  
    }  
}

实现

为了h5还是先判断下环境

const BaseInfo = uni.getAppBaseInfo();

BaseInfo.uniPlatform==="app”的话用,h5还是uni.chooseFile

function ip(obj){  
     plus.android.importClass(obj);  
     return obj;  
 }
uploadFileInit(){
	const CODE_REQUEST = 500;  
           let context = plus.android.runtimeMainActivity();  
          
           ip(context);  
	let Intent = plus.android.importClass('android.content.Intent');  
           let intent = new Intent(Intent.ACTION_GET_CONTENT);  
           intent.addCategory(Intent.CATEGORY_OPENABLE);  
           intent.setType("*/*");   

            context.onActivityResult = function(requestCode,resultCode,intentData){  
            
               if(requestCode == CODE_REQUEST){  
                   if(intentData){  
                      
                       var uriValue = intentData.getData();  
                       plus.android.importClass(uriValue);  
                       var scheme = uriValue.getScheme();  
                       
                       if(scheme == 'content'){//还需要进行数据库查询,一般图片数据  
                           var cursor = ip(context.getContentResolver()).query(uriValue,['_data'], null, null, null);  
                           if(cursor){  
                               ip(cursor).moveToFirst();  
                               var columnIndex = cursor.getColumnIndexOrThrow('_data');  
                               try{
                               var filePath = cursor.getString(columnIndex);  
                               _this.filePath = filePath;
                           
                               cursor.close();
                              //  _this.调用上传接口的方法(filePath, ‘文件类型’);
                              }catch(e){
                               
                              }
                           }  
                       }else if(scheme == 'file'){  
                         
                         // 路径 uriValue.getPath()
                       }  
                   }else{  
                     uni.showToast({
                       title: '选择文件失败',
                       icon: 'none'
                     });
                   }  
               }  
           }  
           context.startActivityForResult(intent,CODE_REQUEST);  
}

找了好久~真机测试可行~

吐槽

uniapp这个是个坑,明明很多文件选择插件,都不兼容~

官方会推荐兼容的插件——当然:收费~

其他实现方式推荐

曲线救国:web-view

在 web-view 组件内可以使用 input 元素进行选择,使用表单或者 xhr 上传;

在插件市场搜索:全文件上传选择非原生

全文件上传选择非原生2.0版 - DCloud 插件市场

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值