開發與維運

技術乾貨 | “選圖預覽並上傳”的場景如何解?全網最全方案彙總來了

封面圖0108.png

選擇本地相冊圖片或者拍照,然後預覽並且上傳是移動應用中一個典型的使用場景,比如常見的身份證信息上傳等。

不少客戶都反饋有類似的場景,並且在使用上都或多或少的遇到一些問題,最後找到 mPaaS,希望我們能夠提供一些最佳實踐。在這裡分享下對應場景的一些優化解決方案。

選圖方案

方案1:使用 Android 原生 Webview

前端通過 input 標籤,指定 type=file,通過原生 webview 的支持實現選擇文件。

Android 原生 webView 並不支持選擇文件上傳,需要外殼自己擴展 WebChromeClient 裡的 openFileChooser 或者 onShowFileChooser,然後去喚起系統選擇文件彈框,選擇文件會使用系統提供的組件或者其他支持的 app,返回的 uri 有的直接是文件的 url,有的是 contentprovider 的 uri,需要統一處理一下返回 uri 格式。

這種方案存在以下問題:

  • 外殼定製實現的邏輯較多,還需要對系統不同文件選擇器返回的地址做兼容,容易有兼容性問題;

  • 選擇文件實現依賴系統的文件選擇器,不同手機實現不一致,無法做到統一;

方案2:使用 mPaas 的 H5 容器

如果業務使用了 mPaas 的 H5 容器後,雖然容器內已經內置了喚起文件選擇器的一系列操作,但是還是一樣存在系統文件選擇器不可控的風險。比如如果業務希望選擇的是一張圖片,但是喚起後的效果可能是下面這個樣子,部分客戶也是無法接受的。

1.png

方案3:實現 jsapi 喚起 Native 自定義的選圖頁面

這種方案就是利用 H5 容器提供的自定義 jsapi 的能力,自定義一個選圖的 jsapi,然後前端去調用,去喚起 Native 自己實現的選圖頁面,最後結果通過 base64 的形式返回給前端做顯示。這樣就解決了前面提到系統選擇文件不可控的問題。

但是當這個方案上線後,還是遇到了一些問題,主要因為通過 jsbridge 只能返回 json,所以圖片數據是通過 base64 的形式返回的。但是因為有多選的場景,如果用戶選擇了多張圖片後,返回的 base64 數據會特別大,導致在一些低端設備上有一些 OOM 的問題,同時大量 base64 轉 JSON 的過程中,也會出現 ANR。所以也是不能上線的。

方案4:選圖返回本地路徑,WebView 攔截訪問本地資源

為了解決前面提到的返回 base64 存在的穩定性問題,所以我們在選圖的時候,是返回了一個本地的地址,然後 Native 模塊攔截 WebView 的資源訪問,去本地拿到對應的圖片返回給 WebView 顯示。

比如選圖後返回給 WebView 的地址是:https://www.mPaas.com.cn/mpaas.jpg,www.mPaas.com.cn 是我們自定義的一個域名,我們攔截這個特定自定義域名,然後去本地相冊去找 mpaas.jpg對應的圖片攔截返回。通過這樣的一個轉換邏輯,解決了 base64 傳遞的問題。

文件上傳方案

通過以上的描述,我們對比了各種選圖方案實現的優缺點,最後沉澱了最佳實踐。選圖實現了後,下一步就是上傳。對於上傳也經歷了類似的方案演進。

方案1:使用 RPC 接口上傳

對於使用了 mPaas 的用戶,第一步想到的肯定是通過 RPC 接口實現文件的上傳,但是在實際驗證過程中,我們發現對於一些比較大的圖片上傳,RPC 接口直接返回了 403 的報錯:Http Transport error[413] : Request Entity Too Large]. 很明顯是因為文件過大導致服務端掛掉了。

主要因為 RPC 的定位是用做業務數據通道,一般建議的大小是 200K 以內,對於直接上傳大文件的數據,會有穩定性風險,甚至因為這個把整個網關打掛。

2.png

方案2:使用 OSS 方案上傳

對於類似的文件上傳場景,建議是直接使用 OSS 的方案進行上傳,比如常見的阿里雲 OSS 方案:help.aliyun.com/product/31815.html。

OSS 是專門為解決文件存儲整條鏈路設計的一套方案,解決了文件上傳的各種場景,用戶可以集成對應的 Android 和 iOS 的 SDK 實現對本地文件的上傳。

結語

僅僅是一個選圖上傳預覽這樣一個場景,就可以有這麼多不同的方案演進,沒有最好的方案,只有最合適的方案。如有更多技術問題,歡迎釘釘搜索“32930171”加入 mPaaS 技術交流群。

作者名片-榮陽.jpg

- END -

動態-logo.gif

底部banner.png

Leave a Reply

Your email address will not be published. Required fields are marked *