最近公司需要开发新的项目,为了节省时间成本,要求整体嵌入H5界面。对,没看错是整体嵌入,心中一万只草泥马奔腾,没办法大佬就是大佬,还是的照做。

今天来说说h5上传头像的问题吧。网上有很多的解决方案,开始我觉得好像很简单,都有成功案例,等把代码copy下来,发现并不能运行成功,真是一脸懵逼...N脸懵逼。

先说说为什么别人的代码都说测试通过了而在我这里都不行了呢?

去google了一把,因为在4.4之后的内核不再是基于webkit内核,禁用了file域来读取手机本地文件,卧槽不是说向下兼容的么,兼容尼玛啊。上张图,

这就是为什么拍照之后并不能正确读取到数据。问题找到之后,那么解决就很好解决了。拍完照片之后,根据路径把图片插入到系统图库里面,完美解决。

 File cameraFile = new File(mCameraFilePath);Bitmap bitmap1 = getimage(cameraFile.getPath());result = Uri.parse(MediaStore.Images.Media.insertImage(mContext.getContentResolver(), bitmap1, null, null));Log.e(TAG,"5.0-result="+result);uploadMessage.onReceiveValue(result);

下面在解决一下系统版本兼容的问题,需要重写WebChromeClient的以下方法,因为方法中有hide,你只需要重写就是。

// For Android < 3.0public void openFileChooser(ValueCallback<Uri> valueCallback) {uploadMessage = valueCallback;openImageChooserActivity();}// For Android  >= 3.0public void openFileChooser(ValueCallback valueCallback, String acceptType) {uploadMessage = valueCallback;openImageChooserActivity();}//For Android  >= 4.1public void openFileChooser(ValueCallback<Uri> valueCallback, String acceptType, String capture) {uploadMessage = valueCallback;openImageChooserActivity();}// For Android >= 5.0@Overridepublic boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {uploadMessageAboveL = filePathCallback;openImageChooserActivity();return true;}

看见有的同学,说重写不起作用,我暂时是没遇到的,如果遇到了再解决吧。下面贴一个webchromeclient 的完整代码,你只需要拷过去,简单调用,在添加以下权限就可以了。

package com.choe.webviewdemo2;import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ClipData;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebStorage;
import android.webkit.WebView;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;/*** @author cyk* @date 2016/12/14 14:02* @email choe0227@163.com* @desc* @modifier* @modify_time* @modify_remark*/
public class MyWebChromeClient extends WebChromeClient {private Activity mContext;private String mCameraFilePath;private  ValueCallback<Uri> uploadMessage;private  ValueCallback<Uri[]> uploadMessageAboveL;private final static String TAG="MyWebChromeClient";private final static int FILE_CHOOSER_RESULT_CODE = 10000;public MyWebChromeClient(Activity context) {mContext = context;}@Overridepublic void onProgressChanged(WebView view, int newProgress) {super.onProgressChanged(view, newProgress);}// For Android < 3.0public void openFileChooser(ValueCallback<Uri> valueCallback) {uploadMessage = valueCallback;openImageChooserActivity();}// For Android  >= 3.0public void openFileChooser(ValueCallback valueCallback, String acceptType) {uploadMessage = valueCallback;openImageChooserActivity();}//For Android  >= 4.1public void openFileChooser(ValueCallback<Uri> valueCallback, String acceptType, String capture) {uploadMessage = valueCallback;openImageChooserActivity();}// For Android >= 5.0@Overridepublic boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {uploadMessageAboveL = filePathCallback;openImageChooserActivity();return true;}@Override//扩容public void onReachedMaxAppCacheSize(long requiredStorage, long quota, WebStorage.QuotaUpdater quotaUpdater) {quotaUpdater.updateQuota(requiredStorage*2);}@Overridepublic void onConsoleMessage(String message, int lineNumber, String sourceID) {Log.e("h5端的log", String.format("%s -- From line %s of %s", message, lineNumber, sourceID));}private void openImageChooserActivity() {initDialog();}/*** 上传头像时的弹出框*/private void initDialog(){new AlertDialog.Builder(mContext).setTitle("更改头像").setItems(new String[]{"拍照", "图库选取"},new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog,int which) {switch (which) {case 0:Intent i1=createCameraIntent();mContext.startActivityForResult(Intent.createChooser(i1, "Image Chooser"), FILE_CHOOSER_RESULT_CODE);break;case 1:Intent i=createFileItent();mContext.startActivityForResult(Intent.createChooser(i, "Image Chooser"), FILE_CHOOSER_RESULT_CODE);break;}}}).setNegativeButton("取消", null).show();}/*** 创建选择图库的intent* @return*/private Intent createFileItent(){Intent i = new Intent(Intent.ACTION_GET_CONTENT);i.addCategory(Intent.CATEGORY_OPENABLE);i.setType("image/*");Intent   intent = new Intent(Intent.ACTION_PICK,MediaStore.Images.Media.EXTERNAL_CONTENT_URI);intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,"image/*");return intent;}/*** 创建调用照相机的intent* @return*/private Intent createCameraIntent() {VersionUtils.checkAndRequestPermissionAbove23(mContext);Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);File externalDataDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);System.out.println("externalDataDir:" + externalDataDir);File cameraDataDir = new File(externalDataDir.getAbsolutePath()+ File.separator + "browser-photo");cameraDataDir.mkdirs();mCameraFilePath = cameraDataDir.getAbsolutePath() + File.separator+ System.currentTimeMillis() + ".jpg";System.out.println("mcamerafilepath:" + mCameraFilePath);cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(new File(mCameraFilePath)));return cameraIntent;}/*** 处理拍照返回函数* @param requestCode* @param resultCode* @param data*/public  void onActivityResult(int requestCode, int resultCode, Intent data){if (requestCode == FILE_CHOOSER_RESULT_CODE) {if (null == uploadMessage&& null == uploadMessageAboveL)return;Uri result = data == null || resultCode != Activity.RESULT_OK ? null: data.getData();if (uploadMessageAboveL != null) {//5.0以上onActivityResultAboveL(requestCode, resultCode, data);}else if(uploadMessage != null) {if (result == null && data == null&& resultCode == Activity.RESULT_OK) {File cameraFile = new File(mCameraFilePath);Bitmap bitmap1 = getimage(cameraFile.getPath());result = Uri.parse(MediaStore.Images.Media.insertImage(mContext.getContentResolver(), bitmap1, null, null));}Log.e(TAG,"5.0-result="+result);uploadMessage.onReceiveValue(result);uploadMessage = null;}}}/*** 处理拍照返回函数  5。0以上* @param requestCode* @param resultCode* @param intent*/@TargetApi(Build.VERSION_CODES.LOLLIPOP)private void onActivityResultAboveL(int requestCode, int resultCode, Intent intent) {Log.e(TAG,"5.0+ 返回了");if (requestCode != FILE_CHOOSER_RESULT_CODE || uploadMessageAboveL == null)return;Uri[] results = null;if (resultCode == Activity.RESULT_OK) {if (intent != null) {String dataString = intent.getDataString();ClipData clipData = intent.getClipData();if (clipData != null) {results = new Uri[clipData.getItemCount()];for (int i = 0; i < clipData.getItemCount(); i++) {ClipData.Item item = clipData.getItemAt(i);results[i] = item.getUri();}}if (dataString != null)results = new Uri[]{Uri.parse(dataString)};}else {File cameraFile = new File(mCameraFilePath);Bitmap bitmap1 = getimage(cameraFile.getPath());Uri result = Uri.parse(MediaStore.Images.Media.insertImage(mContext.getContentResolver(), bitmap1, null, null));results=new Uri[]{result};}}uploadMessageAboveL.onReceiveValue(results);uploadMessageAboveL = null;}/*** 根据图片路径获取图p片* @param srcPath* @return*/private Bitmap getimage(String srcPath) {BitmapFactory.Options newOpts = new BitmapFactory.Options();// 开始读入图片,此时把options.inJustDecodeBounds 设回true了newOpts.inJustDecodeBounds = true;Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);// 此时返回bm为空newOpts.inJustDecodeBounds = false;int w = newOpts.outWidth;int h = newOpts.outHeight;// 现在主流手机比较多是800*480分辨率,所以高和宽我们设置为float hh = 800f;// 这里设置高度为800ffloat ww = 480f;// 这里设置宽度为480f// 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可int be = 1;// be=1表示不缩放if (w > h && w > ww) {// 如果宽度大的话根据宽度固定大小缩放be = (int) (newOpts.outWidth / ww);} else if (w < h && h > hh) {// 如果高度高的话根据宽度固定大小缩放be = (int) (newOpts.outHeight / hh);}if (be <= 0)be = 1;newOpts.inSampleSize = be;// 设置缩放比例// 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了bitmap = BitmapFactory.decodeFile(srcPath, newOpts);return compressImage(bitmap);// 压缩好比例大小后再进行质量压缩}/*** 裁剪图片大小* @param image* @return*/private Bitmap compressImage(Bitmap image) {ByteArrayOutputStream baos = new ByteArrayOutputStream();image.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中int options = 100;while (baos.toByteArray().length / 1024 > 100) { // 循环判断如果压缩后图片是否大于100kb,大于继续压缩baos.reset();// 重置baos即清空baosimage.compress(Bitmap.CompressFormat.JPEG, options, baos);// 这里压缩options%,把压缩后的数据存放到baos中options -= 10;// 每次都减少10}ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把压缩后的数据baos存放到ByteArrayInputStream中Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream数据生成图片return bitmap;}
}

在webview的界面,需要重写onActivityResult方法,并调用处理选择图片返回的方法。

protected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);Log.e(TAG,"收到返回消息了");mMyWebChromeClient.onActivityResult(requestCode,resultCode,data);}

添加上这些东西,上传头像基本搞定。

忘了说了,适配6.0的时候,还需要进行一下权限申请,拍照属于危险权限。

/*** 6.0 手机系统以上 检查并请求权限* @param context 必须为 Activity*/public static void checkAndRequestPermissionAbove23(Activity context){int i = ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA);if (i!= PackageManager.PERMISSION_GRANTED){ActivityCompat.requestPermissions(context,new String[]{Manifest.permission.CAMERA},Constant.TAKE_PHOTO_PERMISSION);}}

到这里,基本就适配了所有版本,亲测可用。

Android WebView嵌入H5之file头像上传文件,适配所有版本相关推荐

  1. php 下 html5 XHR2 + FormData + File API 上传文件

    FormData的作用: FormData对象可以帮助我们自动的打包表单数据,通过XMLHttpRequest的send()方法来提交表单.当然FormData也可以动态的append数据.FormD ...

  2. android 华为裁剪全图,华为手机头像上传裁剪操作 报错

    华为手机头像上传操作, 裁剪点存储--进入裁剪后--点确定, 就直接报错退出程序了,其他机型测都是成功的,求大神指教 报错代码 @Override protected void onActivityR ...

  3. DISCUZ论坛插件h5手机电脑头像上传3.7.1带扩展插件【收集免费分享】

    一个支持电脑和手机h5技术头像上传的插件. 说明:本插件h5电脑版和h5手机版为自主全新开发的触屏版头像上传,体验好,性能好,绿色. 主要特点:支持H5电脑版和H5手机版头像上传. 支持鼠标和触屏操作 ...

  4. springboot 头像上传 文件流保存 文件流返回浏览器查看 区分操作系统 windows 7 or linux...

    1 //我的会员中心 头像上传接口 2 /*windows 调试*/ 3 @Value("${appImg.location}") 4 private String winPath ...

  5. 点击头像上传文件的效果

    原理:label里的for和input里的id一样的话,点击label就等于点击input,这样把默认头像的图片放到label里,并把label的for和input(type:file)里的id设置成 ...

  6. ie8及其以下版本兼容性问题之input file隐藏上传文件

    文件上传时,默认的file标签很难看,而且每个浏览器下都有很大差距.因此我们基本都把真正的file标签给隐藏,然后创建一个标签来替代它.但是由于IE出于安全方面的考虑上传文件时必须点击file的浏览按 ...

  7. input[type=file] 异步上传文件

    背景 UI如图所示,其中有一个拍照图标,点击后要选择拍照或者从相册中选择要上传的图片. 拍照上传部分的代码如下 html部分 <div class="take-photo"& ...

  8. SSH Secure File Transfer上传文件错误:encountered 1 errors during the transfer解决办法

    在使用SSH 工具向Linux服务器上传文件时,弹出 encountered 1 errors during the transfer 错误. 解决方案: 1.准备上传的那个文件所在目录路径存在(), ...

  9. angular文件上传php,Angular2里获取(input file)上传文件的内容的方法

    最近在用Angular2,需要有一个上传文件的功能,但是又不想用库,所以直接用原生的input file 标签. 然后想获取上传的内容,于是先想了个愚蠢的方法,先通过id获取到这个input标签,然后 ...

最新文章

  1. 儿童学python编程入门用途-干货 | 看了此文,家长就知道为啥要让孩子学Python?...
  2. 从网页中读取数据 python_数据分析硬核技能:用 Python 爬取网页
  3. Vue状态管理vuex
  4. centos7下安装低版本mysql_centos7下使用yum安装制定版本mysql
  5. centos7 network网络服务重启报错failed to start lsb
  6. Gradle DSL method not found: ‘compile()’
  7. 敏捷系列情景剧 | 如何“正确”开每日站会
  8. 最新版python如何安装qt5_Python3 搭建Qt5 环境的方法示例
  9. Spark官方3 ---------Spark Streaming编程指南(1.5.0)
  10. 前端逼死强迫症系列之javascript
  11. openssl生成CA证书
  12. 常用电感封装与电流关系
  13. 单片机简易计算机设计实物,单片机设计的带余数的简易计算器
  14. 开发板、单片机、ARM的区别与对比
  15. Deepin 20社区版设置双屏显示
  16. win10 激活工具 Re-LoaderByR@1n.exe
  17. 安全防御----防火墙
  18. 惠普打印机故障代码_HP打印机故障代码
  19. 移除挖矿程序过程记录
  20. 《Java SE实战指南》15-04:接口和抽象类的区别

热门文章

  1. json语法和json解析
  2. [转载]项目风险管理七种武器-碧玉刀
  3. java实现一个简单的射击游戏1
  4. 无线手柄发送接收间断的问题
  5. MobileNets进化史
  6. 编写一个 SNTP 客户端
  7. 打造Flutter高性能富文本编辑器——协议篇
  8. harmonyos2.0能在电脑安装么,华为鸿蒙系统2.0怎么安装 HarmonyOS2.0安装攻略
  9. 国产W806 SPI主机/从机驱动程序
  10. CSS:实现多行文本垂直居中的四种方法