webview调用本地照相、图库

作者: 颤抖的闪电 | 来源:发表于2017-12-09 15:16 被阅读224次

    前言:因为一直在做E家的项目,刚好碰到这么一个功能,就是页面需要调用相机、图库,但是因为SDK版本高低不同,尤其是7.0+的,需要做适配,所以自己总结了一两个类,功能简单而且易懂,拿下来就能用。
    一个意外的坑,如果点击没有反应,要去看看设置->权限那里,是不是没有打开相关的权限,例如读取SD卡、摄像头等,很重要,很重要,很重要。准备开始了:

    一、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" />  
    
    三、在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
    **
     * @desc web页面调用本地照相机、图库的相关助手
     * @auth 方毅超
     * @time 2017/12/8 16:25
     */
    
    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) {
                                if (ContextCompat.checkSelfPermission(act,
                                        Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                                    // 申请WRITE_EXTERNAL_STORAGE权限
                                    ActivityCompat
                                            .requestPermissions(
                                                    act,
                                                    new String[]{Manifest.permission.CAMERA},
                                                    TYPE_REQUEST_PERMISSION);
                                } else {
                                    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(FileManager.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();
                }
            }
        }
    }
    
    六、还需要一个小小的文件管理类FileManager
    /**
     * @desc
     * @auth 方毅超
     * @time 2017/12/8 14:41
     */
    
    public class FileManager {
    
        public static final String ROOT_NAME = "RongYifu";
        public static final String LOG_NAME = "UserLog";
        public static final String CACHE_NAME = "Cache";
        public static final String IMAGE_NAME = "Image";
        public static final String RECORD_NAME = "Voice";
    
        public static final String ROOT_PATH = File.separator + ROOT_NAME
                + File.separator;
        public static final String LOG_PATH_NAME = File.separator + LOG_NAME
                + File.separator;
        public static final String CACHE_PATH_NAME = File.separator + CACHE_NAME
                + File.separator;
        public static final String IMAGE_PATH_NAME = File.separator + IMAGE_NAME
                + File.separator;
        public static final String RECORD_PATH_NAME = File.separator + RECORD_NAME
                + File.separator;
    
        public static final String ACTION_DEL_ALL_IMAGE_CACHE = "com.citic21.user_delImageCache";
        public static final String CODE_ENCODING = "utf-8";
    
        public static String getRootPath(Context appContext) {
    
            String rootPath = null;
            if (checkMounted()) {
                rootPath = getRootPathOnSdcard();
            } else {
                rootPath = getRootPathOnPhone(appContext);
            }
            return rootPath;
        }
    
        public static String getRootPathOnSdcard() {
            File sdcard = Environment.getExternalStorageDirectory();
            String rootPath = sdcard.getAbsolutePath() + ROOT_PATH;
            return rootPath;
        }
    
        public static String getRootPathOnPhone(Context appContext) {
            File phoneFiles = appContext.getFilesDir();
            String rootPath = phoneFiles.getAbsolutePath() + ROOT_PATH;
            return rootPath;
        }
    
        public static String getSdcardPath() {
            File sdDir = null;
            boolean sdCardExist = checkMounted(); // 判断sd卡是否存在
            if (sdCardExist) {
                sdDir = Environment.getExternalStorageDirectory();// 获取跟目录
                return sdDir.getPath();
            }
            return "/";
        }
    
        // SD卡剩余空间
        public long getSDFreeSize() {
            // 取得SD卡文件路径
            File path = Environment.getExternalStorageDirectory();
            StatFs sf = new StatFs(path.getPath());
            // 获取单个数据块的大小(Byte)
            long blockSize = sf.getBlockSize();
            // 空闲的数据块的数量
            long freeBlocks = sf.getAvailableBlocks();
            // 返回SD卡空闲大小
            // return freeBlocks * blockSize; //单位Byte
            // return (freeBlocks * blockSize)/1024; //单位KB
            return (freeBlocks * blockSize) / 1024 / 1024; // 单位MB
        }
    
        public static boolean checkMounted() {
            return Environment.MEDIA_MOUNTED.equals(Environment
                    .getExternalStorageState());
        }
    
        public static String getUserLogDirPath(Context appContext) {
    
            String logPath = getRootPath(appContext) + LOG_PATH_NAME;
            return logPath;
        }
    
        // 缓存整体路径
        public static String getCacheDirPath(Context appContext) {
    
            String imagePath = getRootPath(appContext) + CACHE_PATH_NAME;
            return imagePath;
        }
    
        // 图片缓存路径
        public static String getImageCacheDirPath(Context appContext) {
    
            String imagePath = getCacheDirPath(appContext) + IMAGE_PATH_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;
        }
    
    
        // 创建拍照处方单路径
        public static File initCreatImageCacheDir(Context appContext) {
            String rootPath = getImageCacheDirPath(appContext);
            File dir = new File(rootPath);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            return dir;
        }
    
    
        public static final String getFileSize(File file) {
            String fileSize = "0.00K";
            if (file.exists()) {
                fileSize = FormetFileSize(file.length());
                return fileSize;
            }
            return fileSize;
        }
    
        public static String FormetFileSize(long fileS) {// 转换文件大小
            DecimalFormat df = new DecimalFormat("0.00");
            String fileSizeString = "";
            if (fileS < 1024) {
                fileSizeString = df.format((double) fileS) + "B";
            } else if (fileS < 1048576) {
                fileSizeString = df.format((double) fileS / 1024) + "K";
            } else if (fileS < 1073741824) {
                fileSizeString = df.format((double) fileS / 1048576) + "M";
            } else {
                fileSizeString = df.format((double) fileS / 1073741824) + "G";
            }
            return fileSizeString;
        }
    
        public static boolean writeStringToFile(String text, File file) {
            try {
                return writeStringToFile(text.getBytes(CODE_ENCODING), file);
            } catch (UnsupportedEncodingException e1) {
                e1.printStackTrace();
                return false;
            }
        }
    
        static void close(Closeable c) {
            if (c != null) {
                try {
                    c.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
        }
    
        public static boolean writeStringToFile(byte[] datas, File file) {
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(file);
                fos.write(datas);
                fos.flush();
                return true;
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                close(fos);
            }
            return false;
        }
    
        /**
         * @param oldpath URL 的 md5+"_tmp"
         * @param newpath URL 的 md5+
         * @return
         */
        public static boolean renameFileName(String oldpath, String newpath) {
            try {
                File file = new File(oldpath);
                if (file.exists()) {
                    file.renameTo(new File(newpath));
                }
                return true;
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return false;
        }
    
        public static final boolean isFileExists(File file) {
            if (file.exists()) {
    
                return true;
            }
            return false;
        }
    
        public static final long getFileSizeByByte(File file) {
            long fileSize = 0l;
            if (file.exists()) {
                fileSize = file.length();
                return fileSize;
            }
            return fileSize;
        }
    
    
        public static boolean checkCachePath(Context appContext) {
            String path = getCacheDirPath(appContext);
            File file = new File(path);
            if (!file.exists()) {
                return false;
            }
            return true;
        }
    
    
        public static String getUrlFileName(String resurlt) {
            if (!TextUtils.isEmpty(resurlt)) {
                int nameIndex = resurlt.lastIndexOf("/");
                String loacalname = "";
                if (nameIndex != -1) {
                    loacalname = resurlt.substring(nameIndex + 1);
                }
    
                int index = loacalname.indexOf("?");
                if (index != -1) {
                    loacalname = loacalname.substring(0, index);
                }
                return loacalname;
            } else {
                return resurlt;
            }
        }
    
        // 存储map类型数据 转换为Base64进行存储
        public static String SceneList2String(Map<String, String> SceneList)
                throws IOException {
            ByteArrayOutputStream toByte = new ByteArrayOutputStream();
    
            ObjectOutputStream oos = null;
            try {
                oos = new ObjectOutputStream(toByte);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
            try {
                oos.writeObject(SceneList);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
            // 对byte[]进行Base64编码
    
            String SceneListString = new String(Base64.encode(toByte.toByteArray(),
                    Base64.DEFAULT));
            return SceneListString;
    
        }
    }
    

    至此,所有角色介绍完毕,以下看看大概怎么用吧!可以在Activity或Fragment中。只要设置一下WebChromeClient,然后在onActivityResult中做返回处理:

    1、webView.setWebChromeClient(new MyWebChromeClient());//设置WebChromeClient
    
    2、 @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
            super.onActivityResult(requestCode, resultCode, intent);
            WebCameraHelper.getInstance().onActivityResult(requestCode, resultCode, intent);
        }
    

    后言:情况就是这么个情况。这是自己东拼西凑总结的一个小小使用方法。
    感谢:
    android Webview 上传图片兼容各android版本
    Android 7.0 FileUriExposedException 解决,支持新浪微博
    android 7.0系统解决拍照的问题android.os.FileUriExposedException:
    Android7.0下调用相机闪退的解决方案,这还有一个拍视频功能的

    相关文章

      网友评论

        本文标题:webview调用本地照相、图库

        本文链接:https://www.haomeiwen.com/subject/gdguixtx.html