uni-app 安卓10以上上傳原圖解決方案

Android 10及以上版本中,由于系統對文件訪問的限制,使用chooseImage并勾選原圖上傳后,返回的是圖片的外部存儲路徑,如:'file:///storage/emulated/0/DCIM/Camera/'。這種外部存儲路徑,無法直接轉換成所需要的數據格式,如base64。

上傳原圖解決方案

為了適配Android 10及以上版本,需要將文件從外部存儲路徑拷貝到應用的私有目錄(如_doc/),然后在應用內部進行操作。

1. 使用uni.chooseImageplus.gallery.pick選擇圖片
  • ??這些API會返回一個臨時路徑,該路徑是應用可以訪問的。
2. 將文件拷貝到應用的私有目錄
  • 使用plus.io.resolveLocalFileSystemURL解析應用的私有目錄路徑(如_doc/)。

  • 使用fileEntry.copyTo將文件從臨時路徑拷貝到目標路徑。

代碼示例:

export default {data() {return {tempFilePath: '', // 臨時文件路徑targetFilePath: '' // 目標文件路徑};},methods: {async chooseImage() {// 調用uni.chooseImage選擇圖片uni.chooseImage({count: 1,sizeType: ['original', 'compressed'],sourceType: ['album', 'camera'],success: (res) => {this.tempFilePath = res.tempFilePaths[0];this.saveImageToDoc();},fail: (err) => {console.error('選擇圖片失敗:', err);}});},saveImageToDoc() {const fileName = this.tempFilePath.split('/').pop();this.targetFilePath = `_doc/${fileName}`;// 確保目標目錄存在plus.io.resolveLocalFileSystemURL('_doc/', (root) => {console.log('目標目錄已存在');// 檢查目標文件是否存在plus.io.resolveLocalFileSystemURL(this.targetFilePath, (fileEntry) => {fileEntry.remove(() => {console.log('文件已刪除,可以重新復制');this.copyFile(root);}, (error) => {console.error('刪除文件失敗:', error.message);});}, (error) => {console.log('目標文件不存在,可以直接復制');this.copyFile(root);});}, (error) => {console.error('目標目錄不存在,創建目錄');plus.io.resolveLocalFileSystemURL('/', (fs) => {fs.getDirectory('doc', { create: true }, () => {console.log('目錄創建成功');this.copyFile(fs.root);}, (error) => {console.error('目錄創建失敗:', error.message);});}, (error) => {console.error('無法訪問根目錄:', error.message);});});},copyFile(root) {plus.io.resolveLocalFileSystemURL(this.tempFilePath, (entry) => {entry.copyTo(root, fileName, (newEntry) => {console.log('文件復制成功:', newEntry.fullPath);//這里就拿到了圖片的私有路徑,可進行轉換操作uni.showModal({title: '成功',content: '圖片已保存到應用的_doc目錄',showCancel: false});}, (error) => {console.error('復制文件失敗:', error.message);});}, (error) => {console.error('解析文件路徑失敗:', error.message);});}}
};

注意:私有目錄多了很多無用的圖片,故需在使用完成后,立刻清理。

以上,就是一個簡單的實現demo。

但是,如果選擇了多個原圖上傳,可能會報錯。因為在循環中調用copyFile時,可能會遇到以下問題:

  1. 異步操作的順序問題:由于copyFile是異步操作,循環中的每次調用可能會同時進行,導致文件路徑沖突或其他問題。

  2. 文件刪除操作的時機問題:你在copyFile中嘗試在所有文件處理完成后刪除原文件,但由于異步操作的不確定性,可能會導致刪除操作提前執行,影響后續操作。

循環上傳解決方案

為了解決這些問題,可以使用以下方法:

  1. 使用Promiseasync/await:確保每次文件操作完成后再進行下一次操作。

  2. 在所有文件處理完成后統一刪除:避免在每次復制后立即刪除文件,而是等到所有文件處理完成后統一刪除。

代碼實例:

async handleChooseImage(sourceType) {if (sourceType === 'camera') {this.handleStartGyro();}try {if (sourceType === 'album') {// 從相冊中選擇圖片console.log("從相冊中選擇多張圖片:");await new Promise((resolve, reject) => {plus.gallery.pick(async (e) => {if (e.files.length === 0) {console.log("取消選擇圖片");resolve();return;}uni.showToast({title: "上傳中",icon: "loading"});for (const [index, data] of e.files.entries()) {await this.saveImageToDoc(data, index, e.files.length);}uni.hideLoading();uni.showToast({title: "上傳完成",icon: "success"});resolve();}, (e) => {console.log("取消選擇圖片");resolve();}, {filter: "image",multiple: true});});} else {// 從相機中選擇圖片const res = await uni.chooseImage({count: 9,sizeType: ["original"],sourceType: [sourceType]});const imagePaths = res.tempFilePaths;let gyroData = '';if (sourceType === 'camera') {gyroData = this.gyroValueRaw.join(',');}this.gyroModule && this.gyroModule.stopCustomSensor();if (this.gyroUpdateTimer) clearInterval(this.gyroUpdateTimer);uni.showToast({title: "上傳中",icon: "loading"});for (const [index, path] of imagePaths.entries()) {await this.handleUploadNew(path, index, imagePaths.length, gyroData);}uni.hideLoading();uni.showToast({title: "上傳完成",icon: "success"});uni.removeStorageSync("workData");setTimeout(() => {uni.redirectTo({url: "/pages/work/work"});}, 1000);}} catch (error) {console.error("選擇照片失敗:", error);uni.showToast({title: "選擇照片失敗",icon: "none"});}
},async saveImageToDoc(tempFilePath, index, total) {const fileName = tempFilePath.split('/').pop();this.targetFilePath = `_doc/${fileName}`;// 確保目標目錄存在const root = await this.ensureDirectoryExists('_doc/');// 檢查目標文件是否存在let fileEntry;try {fileEntry = await this.resolveFileEntry(this.targetFilePath);await fileEntry.remove();console.log('文件已刪除,可以重新復制');} catch (error) {console.log('目標文件不存在,可以直接復制');}// 復制文件const newEntry = await this.copyFile(root, tempFilePath, fileName);console.log('文件復制成功:', newEntry.fullPath);// 上傳文件await this.handleUploadNew(newEntry.fullPath, index, total);if (index === total - 1) {uni.hideLoading();uni.showToast({title: "所有圖片已上傳",icon: "success"});}
},ensureDirectoryExists(dirPath) {return new Promise((resolve, reject) => {plus.io.resolveLocalFileSystemURL(dirPath, (root) => {resolve(root);}, (error) => {console.error('目標目錄不存在,創建目錄');plus.io.resolveLocalFileSystemURL('/', (fs) => {fs.getDirectory(dirPath, { create: true }, (root) => {resolve(root);}, (error) => {console.error('目錄創建失敗:', error.message);reject(error);});}, (error) => {console.error('無法訪問根目錄:', error.message);reject(error);});});});
},resolveFileEntry(filePath) {return new Promise((resolve, reject) => {plus.io.resolveLocalFileSystemURL(filePath, (fileEntry) => {resolve(fileEntry);}, (error) => {reject(error);});});
},copyFile(root, tempFilePath, fileName) {return new Promise((resolve, reject) => {plus.io.resolveLocalFileSystemURL(tempFilePath, (entry) => {entry.copyTo(root, fileName, (newEntry) => {resolve(newEntry);}, (error) => {console.error('復制文件失敗:', error);reject(error);});}, (error) => {console.error('解析文件路徑失敗:', error);reject(error);});});
},

優化點說明

  1. 使用async/await

    • plus.gallery.pick的回調改為async函數,并在循環中使用await來同步處理每個文件。

    • 確保每次文件處理完成后才進行下一次操作。

  2. 統一處理邏輯

    • saveImageToDoc方法改為異步方法,確保文件復制和上傳操作是同步進行的。

  3. 錯誤處理

    • 使用try-catch捕獲異步操作中的錯誤,并提供詳細的錯誤提示。

  4. 用戶體驗

    • 在操作過程中顯示加載提示。

    • 在操作完成后提供明確的反饋信息。

通過這些優化,代碼將更加健壯、易讀,并且可以避免并發問題。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/77458.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/77458.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/77458.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

迭代器模式:統一不同數據結構的遍歷方式

迭代器模式:統一不同數據結構的遍歷方式 一、模式核心:分離數據遍歷與數據表示 在開發中,我們經常需要遍歷不同的數據結構,如數組、鏈表、樹等。若在客戶端代碼中直接編寫遍歷邏輯,不僅會導致代碼冗余,而…

Oracle 如何停止正在運行的 Job

Oracle 如何停止正在運行的 Job 先了解是dbms_job 還是 dbms_scheduler,再確定操作命令。 一 使用 DBMS_JOB 包停止作業(適用于舊版 Job) 1.1 查看正在運行的 Job SELECT job, what, this_date, this_sec, failures, broken FROM user_j…

真實波幅策略思路

該策略是一種基于ATR(Average True Range)指標的交易策略,主要用于期貨市場中的日內交易。策略的核心思想是利用ATR指標來識別市場的波動范圍,并結合均線過濾來確定買入和賣出的時機。 交易邏輯思維 1. 數據準備與初始化 - 集合競…

Web3技術如何提升用戶數據保護

在這個信息爆炸的時代,用戶數據保護已成為全球關注的焦點。Web3 技術,作為下一代互聯網的代表,以其去中心化、安全性和用戶主權等特點,為用戶數據保護提供了新的解決方案。本文將探討 Web3 技術如何提升用戶數據保護。 去中心化存…

銀河麒麟系統 達夢8 安裝 dlask 框架后端環境

適配的一套環境為 dmPython2.5.8 dmSQLAlchemy1.4.39 Flask2.0.3 Flask-Cors3.0.10 Flask-SQLAlchemy2.5.1 SQLAlchemy1.4.54 Werkzeug2.2.2其中 # sqlalchemy-dm1.4.39 通過dmdbms目錄內文件進行源碼安裝 (MindSpore) [ma-user python]$pwd /home/syl/dmdbms/drivers/python…

利用 i2c 快速從 Interface 生成 Class

利用 i2c 快速從 Interface 生成 Class(支持 TS & ArkTS) 在日常 TypeScript 或 ArkTS 開發中,需要根據 interface 定義手動實現對應的 class,這既重復又容易出錯。分享一個命令行工具 —— interface2class,簡稱…

015-C語言字符函數和字符串函數

C語言字符函數和字符串函數 文章目錄 C語言字符函數和字符串函數1. 字符分類函數2. 字符轉換函數3. strlen4. strcpy5. strcat6. strcmp7. strncpy8. strncat9. strncmp10. strstr11. strtok12. strerror 1. 字符分類函數 C語言中有一系列函數是專門做字符分類的,也…

CGAL邊折疊edge_collapse的問題

使用edge_collapse對一個模型簡化,之后回收垃圾,collect_garbage 處理之前的頂點和三角形數量: number_of_vertices: 955730 number_of_faces: 1903410 num_vertices: 955730 num_faces: 1903410 處理之后的頂點和三角形數量:…

用c語言實現——順序隊列支持用戶輸入交互、入隊、出隊、查找、遍歷、計算隊列長度等功能。確定判斷判滿的方法為:犧牲一個存儲單元方式

一、知識介紹 1.基本原理 在順序隊列中,我們使用一個固定大小的數組來存儲隊列中的元素,并使用兩個指針(front 和 rear)來分別表示隊頭和隊尾的位置。 隊列為空的條件:front rear 隊列滿的條件:rear 1…

JVM 系列:JVM 內存結構深度解析

你點贊了嗎?你關注了嗎?每天分享干貨好文。 高并發解決方案與架構設計。 海量數據存儲和性能優化。 通用框架/組件設計與封裝。 如何設計合適的技術架構? 如何成功轉型架構設計與技術管理? 在競爭激烈的大環境下&#xff0c…

手機上的APN是什么,該怎么設置

網上說改個APN就可以讓網速快幾倍,那到底APN是個什么東西,真的能讓網速快幾倍嗎? APN的作用 網絡連接基礎:APN(接入點名稱)是手機連接移動網絡的“橋梁”,負責識別運營商網絡類型(…

微服務治理與可觀測性

服務注冊與發現 核心功能 服務實例動態變化:實例可能因擴縮容、故障或遷移導致IP變動。服務依賴解耦:調用方無需硬編碼服務地址,降低耦合度。負載均衡:自動選擇健康實例,提升系統可用性。 核心組件 服務注冊中心&am…

嵌入式linux系統中內存管理的方法與實現

第一:linux內核管理詳解圖形 第二:Linux內存管理詳細分析 深入剖析Linux內核內存管理 作為嵌入式系統開發者,理解Linux內核的內存管理對于開發高效、穩定的系統至關重要。在這篇文章中,我們將詳細解析Linux內核如何劃分物理內存和虛擬內存,頁表、MMU(內存管理單元)與TL…

【dataframe顯示不全問題】打開一個行列超多的excel轉成df之后行列顯示不全

出現問題如下圖: 解決方案~ display.width解決列顯示不全 pd.set_option(display.max_columns,1000) pd.set_option(display.width, 1000) pd.set_option(display.max_colwidth,1000) pd.set_option(display.max_rows,1000)

Linux——Shell編程之正則表達式與文本處理器(筆記)

目錄 基礎正則表達式 1:基礎正則表達式示例 (4)查找任意一個字符“.”與重新字符“*” (5)查找連續字符范圍“{ }” 文本處理器 一、sed工具 二、awk工具 (1)按行輸出文本 (2&#xff0…

OpenHarmony系統-源碼下載,環境搭建,編譯,燒錄,調試

獲取源碼 以OpenHarmony5.0.3為例 repo init -u https://gitee.com/openharmony/manifest -b OpenHarmony-5.0.3-Release --no-repo-verify repo sync -c repo forall -c git lfs pull搭建環境 安裝必要的工具和命令 apt-get install -y apt-utils binutils bison flex bc …

Vue3 本地打包啟動白屏解決思路!! !

“為什么我訪問 http://127.0.0.1:5501/index.html 白屏,刪了 index.html 再訪問 / 就又活過來了?” —— 你的項目與 SPA 路由的“宮斗大戲” 一、問題復現 場景 本地通過 VSCode Live Server(或其他靜態服務器)啟動了打包后的 V…

數字人(2):數字人技術全景透視(2025演進版)

隨著人工智能技術的迅猛發展,數字人技術發展也是一日千里。站在當下,著眼未來,我們一起在回眸透視過去的基礎上,一起共同眺望數字人技術的未來。 一、數字人技術體系重構 我們可以用三維定義對數字人技術進行框架重構 維度 技術內涵 典型特征 物理層 人體數字化建模技術 …

小剛說C語言刷題——1035 判斷成績等級

1.題目描述 輸入某學生成績,如果 86分以上(包括 86分)則輸出 VERY GOOD ,如果在 60到 85之間的則輸出 GOOD (包括 60和 85),小于 60 的則輸出 BAD。 輸入 輸入只有一行,包括 1個整數。 輸出 輸出只有一行&#xf…

React-在使用map循環數組渲染列表時須指定唯一且穩定值的key

在渲染列表的時候,我們須給組件或者元素分配一個唯一值的key, key是一個特殊的屬性,不會最終加在元素上面,也無法通過props.key來獲取,僅在react內部使用。react中的key本質是服務于diff算法, 它的默認值是null, 在diff算法過程中…