Android 与 JS 交互数据上限(Base64图片传输问题)
在 Android 给 JS 传 Base64 格式的图片时报错 Refusing to load URL as it exceeds 2097152 characters2097152 字节 / 1024 / 1024 = 2 兆,这说明调用 loadUrl,最多只能传 2M 的内容Base64是将原文按照每 3 个字节一组分开,这个 3 字节组中的每一组将被按照位分解成 4 个部分,每个...
webview.loadUrl
在 Android 给 JS 传 Base64 格式的图片时
报错 Refusing to load URL as it exceeds 2097152 characters
2097152 字节 / 1024 / 1024 = 2 兆,这说明调用 loadUrl,最多只能传 2M 的内容
Base64是将原文按照每 3 个字节一组分开,这个 3 字节组中的每一组将被按照位分解成 4 个部分,每个部分 6 个位,在这 4 个部分的每个部分高位加上 2 个 0构成一个新的 4 字节组,新的字节组中,每个字节只有 6 位,能表示 64 个值。
如果原文不是三字节的倍数,可能多出一个字节和两个字节,分别会被转为 2 字节和 3 字节的 BASE64 编码,这时编码系统应该在形成的 BASE64 编码最后添加上填充符”=”,保证 BASE64 编码长度是4的倍数。所以在 BASE64 编码后添加的填充符 ”=” 可能为 0-2 个。
2兆 / 4 * 3 = 1.5 兆,所以传给 JS 的图片最多不能超过 1.5 兆
webview.evaluateJavascript
通过下面代码进行打印,可以发现 evaluateJavascript 加载大于 5兆 的图片均正常
new Thread(() -> {
//String data = BitmapUtil.toBase64(activity, uri);
StringBuilder sb = new StringBuilder();
for(int i=0;i<5 * 1048576;i++) {
sb.append("1");
}
String data = sb.toString();
webView.post(() -> {
//webView.loadUrl("javascript:console.log('" + data + ".length')");
//webView.evaluateJavascript("javascript:console.log('" + data + ".length')", value -> { });
});
}).start();
但是,当我将写死的 “字符串常量” 替换成 “Base64” 的图片数据时,却报错了
我就想,会不会是由于Base64的转换过程中,有某些特殊字符,导致 evaluateJavascript 无法解析
下面是图片转 Base64 的方法,FLAGS 用的是默认的 Base64.DEFAULT
private static final int BASE64_FLAGS = Base64.DEFAULT;
/**
* 从指定路径获取图片并转为Base64
*/
public static String toBase64(Context context, Uri uri) {
Bitmap bitmap = fromUri(context, uri);
if (bitmap != null) {
return toBase64(bitmap);
}
return null;
}
/**
* 将图片转为Base64
*/
public static String toBase64(Bitmap bitmap) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Bitmap.CompressFormat format = Bitmap.CompressFormat.PNG;
String mimeType = "image/png";
if(bitmap.getConfig() == Bitmap.Config.RGB_565) {
format = Bitmap.CompressFormat.JPEG;
mimeType = "image/jpeg";
}
bitmap.compress(format, 100, baos);
byte[] buffer = baos.toByteArray();
return toBase64(buffer, mimeType);
}
/**
* 将图片转为Base64
*/
public static String toBase64(byte[] buffer, String mimeType) {
String str = Base64.encodeToString(buffer, BASE64_FLAGS);
str = "data:" + mimeType + ";base64," + str;
return str;
}
将 Base64 的前10位 和 后10位 进行拼接,同样用 console.log 打印出来,发现正常。
再看一下打印,突然发现打印出来的 Base64 有换行符
这是因为 Base64.DEFAULT,当字符串长度超过76会自动添加换行符,将 Base64 的 FLAGS 改成 Base64.NO_WRAP,再跑一遍,可以了 ~ ~
3.5 兆多的图片,可以被前端正常获取并显示了。
但是注意,传大图给前端要花很长的时间!!!
因为它需要将图片数据按字节做一次转换,然后前端获取之后设置到属性里,显示的时候需要再转一次(混合开发内耗严重),加载一张图片,要让用户等很久,体验很差。
因此建议的做法是,图片压缩之后传给前端,然后要上传时,直接调用 android 接口,从本地上传
最大限制
即使使用了 webview.evaluateJavascript
也不是可以无限制的传递数据。如果数据太大,也会导致 OOM。
java.lang.OutOfMemoryError: Failed to allocate a 207812440 byte allocation with 25165824 free bytes and 144MB until OOM, max allowed footprint 410782184, growth limit 536870912
java 获取不到可用的内存上限。
网上有 activityManager.getMemoryClass()
和 runtime.totalMemory()
但是这些都是不能用来进行判断的,解决方案一般只有分片上传。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)