每天学习一点点,成功增加一大步

webView 调用本地照相、图库

Android zhanghui 312℃

最近在做一套基于 H5 打包的在线客服APP,在即时通讯中需要用到调用本地照相、图库,之前也记录实践过的一篇《webView支持H5页面通过js实现文件上传、图片上传》,但这只是做到了通过 Android 的文件管理工具来选择图片上传,而且不是我们常见的可以选择相机拍照,或者是直接访问相册来取图片。

H5页面的标签

<input type="file" accept=".jpeg, .jpg, .png" name="upload_file" id="js-title-img-input">

AndroidManifest权限

<uses-permission android:name="android.permission.INTERNET"/>  
<uses-permission android:name="android.permission.CAMERA"/>  
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  
<uses-feature android:name="android.hardware.camera" /> <!-- 使用照相机权限 -->  
<uses-feature android:name="android.hardware.camera.autofocus" /> <!-- 自动聚焦权限 -->  
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />  
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  

由于安卓6.0之后只在Manifest文件中写上个权限列表,已经不行了,需要写代码动态申请权限,请看

Android permission 访问权限大全

在 Application 的 onCreate 中

//兼容7.0拍照
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
            StrictMode.setVmPolicy(builder.build());
        }

自定义 WebChromeClien

class MyWebChromeClient extends WebChromeClient {
        其他代码、、、

       // For Android < 3.0
        public void openFileChooser(ValueCallback<Uri> uploadMsg) {
            WebCameraHelper.getInstance().mUploadMessage = uploadMsg;
            WebCameraHelper.getInstance().showOptions(CubeAndroid.this);
        }

        // For Android > 4.1.1
        public void openFileChooser(ValueCallback<Uri> uploadMsg,
                                    String acceptType, String capture) {
            WebCameraHelper.getInstance().mUploadMessage = uploadMsg;
            WebCameraHelper.getInstance().showOptions(CubeAndroid.this);
        }

        // For Android > 5.0支持多张上传
        @Override
        public boolean onShowFileChooser(WebView webView,
                                         ValueCallback<Uri[]> uploadMsg,
                                         FileChooserParams fileChooserParams) {
            WebCameraHelper.getInstance().mUploadCallbackAboveL = uploadMsg;
            WebCameraHelper.getInstance().showOptions(CubeAndroid.this);
            return true;
        }
    }

最重要的核心类 WebCameraHelper

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.provider.MediaStore;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;

import com.example.…….util.FileUtil;
import com.example.…….util.PermissionUtil;

/**
 * @desc web页面调用本地照相机、图库的相关助手
 */

public class WebCameraHelper {
    private static class SingletonHolder {
        static final WebCameraHelper INSTANCE = new WebCameraHelper();
    }

    public static WebCameraHelper getInstance() {
        return SingletonHolder.INSTANCE;
    }

    /**
     * 图片选择回调
     */
    public ValueCallback<Uri> mUploadMessage;
    public ValueCallback<Uri[]> mUploadCallbackAboveL;

    public Uri fileUri;
    public static final int TYPE_REQUEST_PERMISSION = 3;
    public static final int TYPE_CAMERA = 1;
    public static final int TYPE_GALLERY = 2;

    /**
     * 包含拍照和相册选择
     */
    public void showOptions(final Activity act) {
        AlertDialog.Builder alertDialog = new AlertDialog.Builder(act);
        alertDialog.setOnCancelListener(new ReOnCancelListener());
        alertDialog.setTitle("选择");
        alertDialog.setItems(new CharSequence[]{"相机", "相册"},
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        if (which == 0) {
                            PermissionUtil permissionUtil = new PermissionUtil(act);
                            if (permissionUtil.isCamera()) {
                                toCamera(act);
                            }
                        } else {
                            Intent i = new Intent(
                                    Intent.ACTION_PICK,
                                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI);// 调用android的图库
                            act.startActivityForResult(i,
                                    TYPE_GALLERY);
                        }
                    }
                });
        alertDialog.show();
    }

    /**
     * 点击取消的回调
     */
    private class ReOnCancelListener implements
            DialogInterface.OnCancelListener {

        @Override
        public void onCancel(DialogInterface dialogInterface) {
            if (mUploadMessage != null) {
                mUploadMessage.onReceiveValue(null);
                mUploadMessage = null;
            }
            if (mUploadCallbackAboveL != null) {
                mUploadCallbackAboveL.onReceiveValue(null);
                mUploadCallbackAboveL = null;
            }
        }
    }

    /**
     * 请求拍照
     *
     * @param act
     */
    public void toCamera(Activity act) {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);// 调用android的相机
        // 创建一个文件保存图片
        fileUri = Uri.fromFile(FileUtil.getImgFile(act.getApplicationContext()));
        intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
        act.startActivityForResult(intent, TYPE_CAMERA);
    }

    /**
     * startActivityForResult之后要做的处理
     *
     * @param requestCode
     * @param resultCode
     * @param intent
     */
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
        if (requestCode == TYPE_CAMERA) { // 相册选择
            if (resultCode == -1) {//RESULT_OK = -1,拍照成功
                if (mUploadCallbackAboveL != null) { //高版本SDK处理方法
                    Uri[] uris = new Uri[]{fileUri};
                    mUploadCallbackAboveL.onReceiveValue(uris);
                    mUploadCallbackAboveL = null;
                } else if (mUploadMessage != null) { //低版本SDK 处理方法
                    mUploadMessage.onReceiveValue(fileUri);
                    mUploadMessage = null;
                } else {
//                    Toast.makeText(CubeAndroid.this, "无法获取数据", Toast.LENGTH_LONG).show();
                }
            } else { //拍照不成功,或者什么也不做就返回了,以下的处理非常有必要,不然web页面不会有任何响应
                if (mUploadCallbackAboveL != null) {
                    mUploadCallbackAboveL.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent));
                    mUploadCallbackAboveL = null;
                } else if (mUploadMessage != null) {
                    mUploadMessage.onReceiveValue(fileUri);
                    mUploadMessage = null;
                } else {
//                    Toast.makeText(CubeAndroid.this, "无法获取数据", Toast.LENGTH_LONG).show();
                }

            }
        } else if (requestCode == TYPE_GALLERY) {// 相册选择
            if (mUploadCallbackAboveL != null) {
                mUploadCallbackAboveL.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent));
                mUploadCallbackAboveL = null;
            } else if (mUploadMessage != null) {
                Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData();
                mUploadMessage.onReceiveValue(result);
                mUploadMessage = null;
            } else {
//                Toast.makeText(CubeAndroid.this, "无法获取数据", Toast.LENGTH_LONG).show();
            }
        }
    }
}

还需要一个小小的文件管理类,来获取缓存图库

public class FileUtil {

    public static final String IMAGE_NAME = "Image";

    /**
     * @param context 上下文对象
     * @param dir     存储目录
     * @return
     */
    public static String getFilePath(Context context, String dir) {
        String directoryPath = "";
//判断SD卡是否可用 
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            directoryPath = context.getExternalFilesDir(dir).getAbsolutePath();
// directoryPath =context.getExternalCacheDir().getAbsolutePath() ;
        } else {
//没内存卡就存机身内存
            directoryPath = context.getFilesDir() + File.separator + dir;
// directoryPath=context.getCacheDir()+File.separator+dir;
        }
        File file = new File(directoryPath);
        if (!file.exists()) {//判断文件目录是否存在
            file.mkdirs();
        }
//        Common.Log("getFilePath", directoryPath);
        return directoryPath;
    }

 // 其他代码
    ……

    // 图片缓存路径
    public static String getImageCacheDirPath(Context appContext) {

        String imagePath = getFilePath(appContext, IMAGE_NAME);
        return imagePath;
    }

    public static File getImgFile(Context context) {
        File file = new File(getImageCacheDirPath(context));
        if (!file.exists()) {
            file.mkdirs();
        }
        String imgName = new SimpleDateFormat("yyyyMMdd_HHmmss")
                .format(new Date());
        File imgFile = new File(file.getAbsolutePath() + File.separator
                + "IMG_" + imgName + ".jpg");
        return imgFile;
    }
}

然后在Activity或Fragment中。只要设置一下WebChromeClient,然后在onActivityResult中做返回处理

 webView.setWebChromeClient(new MyWebChromeClient());//设置WebChromeClient

……

 @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        WebCameraHelper.getInstance().onActivityResult(requestCode, resultCode, intent);
    }

转载请注明:隨習筆記 » webView 调用本地照相、图库

喜欢 (1)