Android WebView上傳圖片(base64)到H5(JS)
最近專案需求是H5呼叫安卓的方法選擇圖片或者開啟照相機拍照,然後傳給H5顯示圖片,最後由H5上傳到伺服器。查了一下資料,大概有以下幾種方法:
- 利用WebChromeClient的openFileChooser(5.0+是onShowFileChooser)
- JS呼叫安卓端定義好的介面選擇圖片或者開啟照相機,獲取到圖片資訊(base64)之後,安卓端呼叫JS方法回撥給H5
- JS呼叫安卓端定義好的介面選擇圖片或者開啟照相機,安卓端上傳圖片給伺服器,伺服器返回圖片的URL,最後安卓端呼叫JS方法把圖片的URL傳給H5
先來比較一下這三種方法:
第一種方法,看上去應該很好用,畢竟是系統原生方法,但是隨著安卓系統版本的不斷更新,WebChromeClient的openFileChooser方法返回的引數都有所改變,到了5.0+更是換了個名字,這都不是重點,重點是出了4.4這個奇葩,居然不支援openFileChooser,所以這個方法要做適配和解決4.4這個奇葩才可行。嫌麻煩的我怎麼可能選這個方法呢(´Д`)解決方案可以參考以下兩個連結的內容:
第二種方法,是我最後採用了的方法,可能是因為我比較二,所以喜歡第二種方法吧。囧rz 主要的問題都是跟H5之間的互動,不過還是遇到部分機型傳遞不到資料的問題(圖片流太大),後面將會詳細講解我最後的方案。
第三種方法,簡單粗暴而且可行性很高,因為上傳圖片到伺服器的方法已經很成熟了,所以基本不必擔心傳不到圖片對應的URL給H5,而且傳給H5的資料量少。但是,有個缺點就是要展示的圖片不一定是要上傳到伺服器的,而是使用者點選了“上傳”按鈕才會上傳到伺服器。所以,這個方法看起來有點彆扭,最後還是沒有用到這個方案。
下面將詳細講解第二種方法 <( ̄ ﹌  ̄)@m
首先,設定WebView使其支援JS呼叫JAVA方法
private OperationPresenter operationPresenter = new OperationPresenter(this);
private WebView mWebView;
//設定WebView支援JS
mWebView.getSettings().setJavaScriptEnabled(true);
//新增JS可呼叫的例項物件,第二個引數為JS可用的物件名
mWebView.addJavascriptInterface(operationPresenter, "operation" )
其中OperationPresenter程式碼如下
public class OperationPresenter {
private IOperationView view;
private String methodName;
public OperationPresenter(IOperationView view) {
this.view = view;
}
/**
* 選擇圖片
*
* @param methodName JS方法名
*/
@JavascriptInterface
public void choosePhoto(String methodName) {
this.methodName = methodName;
view.onChoosePhoto();
}
/**
* 開啟照相機
*
* @param methodName JS方法名
*/
@JavascriptInterface
public void openCamera(String methodName) {
this.methodName = methodName;
view.onOpenCamera();
}
/**
* 部分低端機可能會因為字串太長而不能直接傳base64
* 需要把base64封裝到JSON物件中
*
* @param base64JSONObject 包含base64的JSON物件
*/
public void sendPhoto(WebView webView, JSONObject base64JSONObject) {
webView.loadUrl("javascript:" + methodName + "(" + base64JSONObject + ")");
}
}
H5只需要在這樣呼叫即可
//選擇圖片
window.opreation.choosePhoto('getPhoto')
//開啟照相機
window.opreation.openCamera('getPhoto')
getPhoto就是JS定義的方法,需要安卓端回撥使用的,定義如下
function getPhoto(response) {
//因為response是JSON物件,所以直接通過key(img)獲取value
response.img
//......後面省略
}
封裝JSONObject並回調
//獲取Bitmap並用自己封裝的工具類解釋成base64
String baseData = ImgUtils.bitmap2Base64(bitmap);
if (!TextUtils.isEmpty(baseData)) {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("img", "data:image/png;base64," + baseData);
operationPresenter.sendPhoto(mWebView, jsonObject);
} catch (JSONException e) {
//TODO
}
}
大致流程如下:
JS呼叫了安卓的方法開啟相簿/照相機–>獲取圖片–>壓縮–>轉成base64–>封裝成JSONObject–>呼叫JS方法回傳圖片資料
至於一些WebView的優化和設定、圖片壓縮、base64的轉換等等可以參考網上的其他資料。
再說明一下為什麼不直接傳base64字串,而是將它封裝成JSON物件。因為當在部分效能比較差的手機上面(4.0真機、4.2模擬器),把base64這樣長的字串直接傳給JS的話會出現像下面這樣的問題
Console: Uncaught SyntaxError: Unexpected token ILLEGAL at null:1
居然是一個我看不懂的JS錯誤,搜尋了一下基本都沒有範對應的錯(PS:還是我不夠細心看問題呢)後來無意間發現了這篇文章
http://blog.csdn.net/waww116529/article/details/52850018
主要原因就是圖片流太大,不過作者應該是寫錯了一點,傳JSON物件的時候,應該不用再加單引號或者雙引號了,我試過加了是沒反應的。像下面這樣就可以了。
webView.loadUrl("javascript:" + methodName + "(" + base64JSONObject + ")");
有更多更好的WebView上傳圖片到H5的方法請留言發連結,小弟不勝感激!