热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Androidwebview实现h5的inputtype="file"选择图片调用系统相册/相机并进行图片压缩功能

一、引言webview怎么实现web的选择图片功能,如何让h5通过webview调用系统相册和相机,并在图片传回h5的时已经将图片做了压缩处理?本

一、引言

webview怎么实现web的选择图片功能,如何让h5通过webview调用系统相册和相机,并在图片传回h5的时已经将图片做了压缩处理?本篇就是解决这方面的问题。

这边h5 的上传文件只是限定于图片类型,不需要pdf、txt等其他类型,如果要写一个普通的不限定于图片的上传文件功能可以参考https://www.jianshu.com/p/b0f1fdbfd502。

二、Webview实现

Webview要调用系统相册/相机,需要setWebChromeClient并重写WebChromeClient的方法。

mWebView.setWebChromeClient(new WebChromeClient(){

// For Android <3.0
public void openFileChooser(ValueCallback valueCallback) {
mUploadCallBack = valueCallback;
showFileChooser();
}
// For Android >= 3.0
public void openFileChooser(ValueCallback valueCallback, String acceptType) {
mUploadCallBack = valueCallback;
showFileChooser();
}
//For Android >= 4.1
public void openFileChooser(ValueCallback valueCallback, String acceptType, String capture) {
mUploadCallBack = valueCallback;
showFileChooser();
}
// For Android >= 5.0
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
mUploadCallBackAboveL = filePathCallback;
showFileChooser();
return true;
}
});

/**
* 打开选择图片/相机
*/
private void showFileChooser() {
Intent intent1 = new Intent(Intent.ACTION_PICK, null);
intent1.setDataAndType(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
// Intent intent1 = new Intent(Intent.ACTION_GET_CONTENT);
// intent1.addCategory(Intent.CATEGORY_OPENABLE);
// intent1.setType("image/*");
Intent intent2 = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
mCameraFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator +
System.currentTimeMillis() + ".jpg";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// android7.0注意uri的获取方式改变
Uri photoOutputUri = FileProvider.getUriForFile(
MainActivity.this,
BuildConfig.APPLICATION_ID + ".fileProvider",
new File(mCameraFilePath));
intent2.putExtra(MediaStore.EXTRA_OUTPUT, photoOutputUri);
} else {
intent2.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mCameraFilePath)));
}
Intent chooser = new Intent(Intent.ACTION_CHOOSER);
chooser.putExtra(Intent.EXTRA_TITLE, "File Chooser");
chooser.putExtra(Intent.EXTRA_INTENT,intent1);
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[]{intent2});
startActivityForResult(chooser, REQUEST_CODE_FILE_CHOOSER);
}

然后,在onActivityResult里处理获取到的图片。

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_FILE_CHOOSER) {
Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
// 压缩到多少宽度以内
int maxW = 1000;
// 压缩到多少大小以内,1024kb
int maxSize = 1024;
if (result == null) {
// 看是否从相机返回
File cameraFile = new File(mCameraFilePath);
if (cameraFile.exists()) {
result = Uri.fromFile(cameraFile);
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result));
}
}
if (result != null) {
// 根据uri获取路径
String path = FileUtils.getPath(this, result);
if (!TextUtils.isEmpty(path)) {
File f = new File(path);
if (f.exists() && f.isFile()) {
// 按大小和尺寸压缩图片
Bitmap b = getCompressBitmap(path, maxW, maxW, maxSize);
String basePath = Environment.getExternalStorageDirectory().getAbsolutePath();
String compressPath = basePath + File.separator + "photos" + File.separator
+ System.currentTimeMillis() + ".jpg";
// 压缩完保存在文件里
if (saveBitmapToFile(b, compressPath)) {
Uri newUri = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
newUri = FileProvider.getUriForFile(
MainActivity.this,
BuildConfig.APPLICATION_ID + ".fileProvider",
new File(compressPath));
} else {
newUri = Uri.fromFile(new File(compressPath));
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (mUploadCallBackAboveL != null) {
if (newUri != null) {
mUploadCallBackAboveL.onReceiveValue(new Uri[]{newUri});
mUploadCallBackAboveL = null;
return;
}
}
} else if (mUploadCallBack != null) {
if (newUri != null) {
mUploadCallBack.onReceiveValue(newUri);
mUploadCallBack = null;
return;
}
}
}
}
}
}
clearUploadMessage();
return;
}
}

如果没有图片返回给h5,记得要执行下面代码,避免h5下次点击选择图片时无法响应。

/**
* webview没有选择图片也要传null,防止下次无法执行
*/
private void clearUploadMessage(){
if (mUploadCallBackAboveL != null) {
mUploadCallBackAboveL.onReceiveValue(null);
mUploadCallBackAboveL = null;
}
if (mUploadCallBack != null) {
mUploadCallBack.onReceiveValue(null);
mUploadCallBack = null;
}
}

相关的压缩和保存图片代码如下:

/**
* 根据路径获取bitmap(压缩后)
*
* @param srcPath 图片路径
* @param width 最大宽(压缩完可能会大于这个,这边只是作为大概限制,避免内存溢出)
* @param height 最大高(压缩完可能会大于这个,这边只是作为大概限制,避免内存溢出)
* @param size 图片大小,单位kb
* @return 返回压缩后的bitmap
*/
public static Bitmap getCompressBitmap(String srcPath, float width, float height, int size) {
BitmapFactory.Options newOpts = new BitmapFactory.Options();
// 开始读入图片,此时把options.inJustDecodeBounds 设回true了
newOpts.inJustDecodeBounds = true;
BitmapFactory.decodeFile(srcPath, newOpts);
newOpts.inJustDecodeBounds = false;
int w = newOpts.outWidth;
int h = newOpts.outHeight;
int scaleW = (int) (w / width);
int scaleH = (int) (h / height);
int scale = scaleW if (scale <= 1) {
scale = 1;
}
newOpts.inSampleSize = scale;// 设置缩放比例
// 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
// 压缩好比例大小后再进行质量压缩
return compressImage(bitmap, size);
}
/**
* 图片质量压缩
*
* @param image 传入的bitmap
* @param size 压缩到多大,单位kb
* @return 返回压缩完的bitmap
*/
public static Bitmap compressImage(Bitmap image, int size) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
int optiOns= 100;
image.compress(Bitmap.CompressFormat.JPEG, options, baos);
// 循环判断如果压缩后图片是否大于size,大于继续压缩
while (baos.toByteArray().length / 1024 > size) {
// 重置baos即清空baos
baos.reset();
// 每次都减少10
options -= 10;
// 这里压缩options%,把压缩后的数据存放到baos中
image.compress(Bitmap.CompressFormat.JPEG, options, baos);
}
// 把压缩后的数据baos存放到ByteArrayInputStream中
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
// 把ByteArrayInputStream数据生成图片
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
return bitmap;
}
/**
* bitmap保存为文件
*
* @param bm bitmap
* @param filePath 文件路径
* @return 返回保存结果 true:成功,false:失败
*/
public static boolean saveBitmapToFile(Bitmap bm, String filePath) {
try {
File file = new File(filePath);
file.deleteOnExit();
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
boolean b = false;
if (filePath.toLowerCase().endsWith(".png")) {
b = bm.compress(Bitmap.CompressFormat.PNG, 100, bos);
} else {
b = bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);
}
bos.flush();
bos.close();
return b;
} catch (FileNotFoundException e) {
} catch (IOException e) {
}
return false;
}

对于根据uri获取图片路径的代码也比较关键。相关代码可以参考https://www.jianshu.com/p/25c35da68db2

如果你的应用混淆了要注意下,openFileChooser方法并不是WebChromeClient的对外开放的方法,因此这个方法会被混淆,解决办法也比较简单,只需要在混淆文件里控制一下即可:

-keepclassmembers class * extends android.webkit.WebChromeClient{
public void openFileChooser(...);
}

好了,这样就可以让webview调用原生相机和相册选择图片,并对图片做压缩处理。


推荐阅读
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 目前正在做毕业设计,一个关于校园服务的app,我会抽取已完成的相关代码写到文章里。一是为了造福这个曾经帮助过我的社区,二是写文章的同时更能巩固相关知识的记忆。一、前言在爬取教务系统 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 图像因存在错误而无法显示 ... [详细]
  • 本文介绍了Android中的assets目录和raw目录的共同点和区别,包括获取资源的方法、目录结构的限制以及列出资源的能力。同时,还解释了raw目录中资源文件生成的ID,并说明了这些目录的使用方法。 ... [详细]
  • 代理模式的详细介绍及应用场景
    代理模式是一种在软件开发中常用的设计模式,通过在客户端和目标对象之间增加一层中间层,让代理对象代替目标对象进行访问,从而简化系统的复杂性。代理模式可以根据不同的使用目的分为远程代理、虚拟代理、Copy-on-Write代理、保护代理、防火墙代理、智能引用代理和Cache代理等几种。本文将详细介绍代理模式的原理和应用场景。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • 在一对一直播源码使用过程中,有时会出现软键盘切换闪屏问题,就是当切换表情的时候屏幕会跳动,因此要对一对一直播源码表情面板无缝切换进行优化。 ... [详细]
  • 人工智能推理能力与假设检验
    最近Google的Deepmind开始研究如何让AI做数学题。这个问题的提出非常有启发,逻辑推理,发现新知识的能力应该是强人工智能出现自我意识之前最需要发展的能力。深度学习目前可以 ... [详细]
  • Arduino + ESP32C3 + TFT(1.8‘ ST7735S)基础平台(实验四)直接显示网络图片
    ------------------------------------------------------------------------------------------ ... [详细]
  • 安卓端开源移动浏览器开源项目
    进入android开发以来,webview用的比较多,后来又看了一些基于webview的浏览器代码,慢慢的将积累的东西做成了一个安卓移动浏 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 由于同源策略的限制,满足同源的脚本才可以获取资源。虽然这样有助于保障网络安全,但另一方面也限制了资源的使用。那么如何实现跨域呢,以下是实现跨域的一些方法。 ... [详细]
author-avatar
心理学点滴_312
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有