需求
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 插件市場