如题,其实 H5 调起 Android 手机的相册相机功能,最好是使用 JS 与 Android 进行交互,因为这样可调节性大一些,可定制型强很多。

但是,现实的情况的的确确是发生了,H5 就是用了 input 标签,这样他能自动调起 Android 端的相机和文件,就像这样

H5 通过 input 标签,调起 Android 手机相册,点击取消时手机卡住_第1张图片

点击「上传头像」调起 Android 自带的相册和文件


H5 通过 input 标签,调起 Android 手机相册,点击取消时手机卡住_第2张图片

但是,当点击取消的时候,如果不做任何处理,手机就会卡住,无法操作。

那么发生了怎么办呢?只能找 百度、谷歌 “帮帮我了”呗

H5 通过 input 标签,调起 Android 手机相册,点击取消时手机卡住_第3张图片 那你帮帮我吧

那么最终的结果是什么呢?

在取消的时候,也要将结果返回,否则会引起界面卡住

具体怎么操作呢?来看看吧

1、给webview 添加这样的 WebChromeClient,并重写 input 调起的方法
public class MyFileWebChromeClient extends WebChromeClient {public static final int REQUEST_FILE_PICKER = 1;public ValueCallback mFilePathCallback;public ValueCallback mFilePathCallbacks;Activity mContext;/** * 记录选择图片的 uri */public Uri imageUri;@Overridepublic void onReceivedTitle(WebView webView, String s) {    super.onReceivedTitle(webView, s);}public MyFileWebChromeClient(Activity mContext) {    super();    this.mContext = mContext;}/** * Android < 3.0 调用这个方法 * * @param filePathCallback */public void openFileChooser(final ValueCallback filePathCallback) {    mFilePathCallback = filePathCallback;    take();}/** * 3.0 + 调用这个方法 * * @param filePathCallback * @param acceptType */public void openFileChooser(final ValueCallback filePathCallback, final String acceptType) {    mFilePathCallback = filePathCallback;    take();}/** * js上传文件的事件捕获,也就在这里啦 * Android >4.1.1调用这个方法 * * @param filePathCallback * @param acceptType * @param capture */public void openFileChooser(final ValueCallback filePathCallback, final String acceptType, final String capture) {    mFilePathCallback = filePathCallback;    take();}@Overridepublic boolean onShowFileChooser(final WebView webView, final ValueCallback filePathCallback, final FileChooserParams fileChooserParams) {    mFilePathCallbacks = filePathCallback;    take();    return true;}/** * 返回选择相册或者拍照的图片 */private void take() {    File imageStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyApp");    // Create the storage directory if it does not exist    if (!imageStorageDir.exists()) {        imageStorageDir.mkdirs();    }    File file = new File(imageStorageDir + File.separator + "IMG_" + String.valueOf(System.currentTimeMillis()) + ".jpg");    imageUri = Uri.fromFile(file);    final List cameraIntents = new ArrayList();    final Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);    final PackageManager packageManager = mContext.getPackageManager();    final List listCam = packageManager.queryIntentActivities(captureIntent, 0);    for (ResolveInfo res : listCam) {        final String packageName = res.activityInfo.packageName;        final Intent i = new Intent(captureIntent);        i.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));        i.setPackage(packageName);        i.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);        cameraIntents.add(i);    }    Intent i = new Intent(Intent.ACTION_GET_CONTENT);    i.addCategory(Intent.CATEGORY_OPENABLE);    i.setType("image/*");    Intent chooserIntent = Intent.createChooser(i, "Image Chooser");    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents.toArray(new Parcelable[]{}));    mContext.startActivityForResult(chooserIntent, REQUEST_FILE_PICKER);}}

结合注释,应该能看懂吧。

2、在 webview 所在的 activity 重写 onActivityResult 方法
public class MyFileOnActivityResult {private static MyFileOnActivityResult myFileOnActivityResult;public MyFileOnActivityResult(MyFileWebChromeClient myFileWebChromeClient) {    this.myFileWebChromeClient = myFileWebChromeClient;}public static MyFileOnActivityResult getInstance(MyFileWebChromeClient myFileWebChromeClient) {    if (myFileOnActivityResult == null) {        myFileOnActivityResult = new MyFileOnActivityResult(myFileWebChromeClient);    }    return myFileOnActivityResult;}MyFileWebChromeClient myFileWebChromeClient;/** * 以下代码是为了适应H5调用本地图片并且显示在h5上 */public void onActivityResult(int requestCode, int resultCode, Intent intent) {    if (requestCode == MyFileWebChromeClient.REQUEST_FILE_PICKER) {        if (null == myFileWebChromeClient.mFilePathCallback && null == myFileWebChromeClient.mFilePathCallbacks) {            return;        }        Uri result = ((intent == null || resultCode != RESULT_OK) ? null : intent.getData());        if (myFileWebChromeClient.mFilePathCallbacks != null) {            onActivityResultAboveL(requestCode, resultCode, intent);        } else if (myFileWebChromeClient.mFilePathCallback != null) {            myFileWebChromeClient.mFilePathCallback = null;        }    }}@SuppressWarnings("null")@TargetApi(Build.VERSION_CODES.BASE)private void onActivityResultAboveL(int requestCode, int resultCode, Intent data) {    if (requestCode != MyFileWebChromeClient.REQUEST_FILE_PICKER            || myFileWebChromeClient.mFilePathCallbacks == null) {        return;    }    Uri[] results = null;    if (resultCode == Activity.RESULT_OK) {        if (data == null) {            /**             * 如果返回的结构为空,那么不从结果里面拿数据,而是直接从选择图片的路径拿             */            results = new Uri[]{myFileWebChromeClient.imageUri};        } else {            /**             * 如果返回了数据,则将返回的数据解析成 uri             */            String dataString = data.getDataString();            ClipData clipData = data.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)};        }    }    /**     * 如果经过了上面的处理,result 不为空,说明用户确实取得了图片,那么将 result 返回即可     *     * 否则,返回空的图片(图片只有名字,并没有真正的图片)     */    if (results != null) {        myFileWebChromeClient.mFilePathCallbacks.onReceiveValue(results);        myFileWebChromeClient.mFilePathCallbacks = null;    } else {        results = new Uri[]{myFileWebChromeClient.imageUri};        myFileWebChromeClient.mFilePathCallbacks.onReceiveValue(results);        myFileWebChromeClient.mFilePathCallbacks = null;    }}}

为了方便使用,搞了一个类,再 onActivityResult 中调用即可

这样:

  @Overrideprotected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {    MyFileOnActivityResult instance = MyFileOnActivityResult.getInstance(myFileWebChromeClient);    instance.onActivityResult(requestCode, resultCode, data);    super.onActivityResult(requestCode, resultCode, data);}
3、在点击时,也要判断下是否赋予了 拍照 和 读写 sd 卡的权限,这里就不贴代码了

ok , 这样就能解决点击取消键,界面卡住的问题了。

4、代码提交到 github 了,用户名 「guaju」,仓库名「AndroidCommonUtils」有需要看看吧
感谢各位朋友的支持,关注,转发,持续更新,蟹蟹!

更多相关文章

  1. Android手机直播(四)Android Media API
  2. Android 最快速获取通讯录所有手机号、对应姓名和头像
  3. Android 手机跳转到权限管理界面汇总
  4. android sqlite 存储图片
  5. Android保存照片到相册
  6. adbWireless能够让手机用无线来取代USB连接而使用ADB工具
  7. 学习笔记之——Android中的Picasso实现圆形头像、圆角图片工具类
  8. ndroid显示在线图片
  9. Android 根据所给的图片位置获得Thumbnail

随机推荐

  1. android 中imageview 与diallog综合应用
  2. Android Fastboot源码分析
  3. Android Ant批量打包
  4. android通过google api获取天气信息示例
  5. Android Q自定义开关机动画
  6. You must supply a layout_width attribu
  7. textview之url
  8. 石头剪刀布(android)
  9. 解耦问题
  10. Android Studio 无法预览xml布局视图