Android WebView上传图片(base64)到H5(JS)

最近项目需求是H5调用安卓的方法选择图片或者打开照相机拍照,然后传给H5显示图片,最后由H5上传到服务器。查了一下资料,大概有以下几种方法:

  1. 利用WebChromeClient的openFileChooser(5.0+是onShowFileChooser)
  2. JS调用安卓端定义好的接口选择图片或者打开照相机,获取到图片信息(base64)之后,安卓端调用JS方法回调给H5
  3. JS调用安卓端定义好的接口选择图片或者打开照相机,安卓端上传图片给服务器,服务器返回图片的URL,最后安卓端调用JS方法把图片的URL传给H5

先来比较一下这三种方法:

第一种方法,看上去应该很好用,毕竟是系统原生方法,但是随着安卓系统版本的不断更新,WebChromeClient的openFileChooser方法返回的参数都有所改变,到了5.0+更是换了个名字,这都不是重点,重点是出了4.4这个奇葩,居然不支持openFileChooser,所以这个方法要做适配和解决4.4这个奇葩才可行。嫌麻烦的我怎么可能选这个方法呢(´Д`)解决方案可以参考以下两个链接的内容: 
http://stackoverflow.com/questions/5907369/file-upload-in-webview/http://blog.csdn.net/mengzuixilou/article/details/48374971

第二种方法,是我最后采用了的方法,可能是因为我比较二,所以喜欢第二种方法吧。囧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")
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

其中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 + ")");
    }

}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

H5只需要在这样调用即可

//选择图片
window.opreation.choosePhoto('getPhoto')
//打开照相机
window.opreation.openCamera('getPhoto')
 
 
  • 1
  • 2
  • 3
  • 4

getPhoto就是JS定义的方法,需要安卓端回调使用的,定义如下

function getPhoto(response) {
    //因为response是JSON对象,所以直接通过key(img)获取value
    response.img
    //......后面省略
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5

封装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
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

大致流程如下: 
JS调用了安卓的方法打开图库/照相机–>获取图片–>压缩–>转成base64–>封装成JSONObject–>调用JS方法回传图片数据 
至于一些WebView的优化和设置、图片压缩、base64的转换等等可以参考网上的其他资料。

再说明一下为什么不直接传base64字符串,而是将它封装成JSON对象。因为当在部分性能比较差的手机上面(4.0真机、4.2模拟器),把base64这样长的字符串直接传给JS的话会出现像下面这样的问题

Console: Uncaught SyntaxError: Unexpected token ILLEGAL at null:1
 
 
  • 1

居然是一个我看不懂的JS错误,搜索了一下基本都没有范对应的错(PS:还是我不够细心看问题呢)后来无意间发现了这篇文章 
http://blog.csdn.net/waww116529/article/details/52850018 
主要原因就是图片流太大,不过作者应该是写错了一点,传JSON对象的时候,应该不用再加单引号或者双引号了,我试过加了是没反应的。像下面这样就可以了。

webView.loadUrl("javascript:" + methodName + "(" + base64JSONObject + ")");
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要在 Android Webview 中将 H5 资源本地化,可以使用以下步骤: 1. 在 Android 项目的 assets 目录下创建一个文件夹(比如说叫做 html),将 H5 资源放到该文件夹下。 2. 在 Webview 中加载 H5 页面时,将其 URL 改为本地路径,例如: ```java webView.loadUrl("file:///android_asset/html/index.html"); ``` 3. 在 Webview 的 setWebViewClient 方法中重写 shouldInterceptRequest 方法,拦截 H5 页面资源请求,并返回本地资源的 InputStream,例如: ```java webView.setWebViewClient(new WebViewClient() { @Override public WebResourceResponse shouldInterceptRequest(WebView view, String url) { if (url.contains("html/")) { // 判断是否为 H5 资源请求 try { AssetManager assetManager = getAssets(); InputStream inputStream = assetManager.open(url.replace("file:///android_asset/", "")); String mimeType = getMimeType(url); // 获取资源的 MIME 类型 return new WebResourceResponse(mimeType, "UTF-8", inputStream); } catch (IOException e) { e.printStackTrace(); } } return super.shouldInterceptRequest(view, url); } }); ``` 4. 在 getMimeType 方法中根据文件后缀名获取 MIME 类型,例如: ```java private String getMimeType(String url) { String extension = MimeTypeMap.getFileExtensionFromUrl(url); String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); return mimeType != null ? mimeType : "application/octet-stream"; } ``` 这样就可以在 Android Webview 中将 H5 资源本地化了。需要注意的是,在加载 H5 页面时,如果 H5 页面中包含外部链接,例如 CDN 链接,这些链接将不会被拦截,仍然会从网络中加载。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值