Android WebView 拍照和選擇圖片

Android WebView 嵌套網頁中有js調取拍照和選擇圖片上傳的功能,這個需要在我們的代碼中去實現方法

首先基礎WebView設置

        WebSettings settings = mWebView.getSettings();
        settings.setJavaScriptEnabled(true);    //設置webview支持javascript
//        settings.setJavaScriptCanOpenWindowsAutomatically(true);
        settings.setLoadsImagesAutomatically(true);    //支持自動加載圖片
        settings.setUseWideViewPort(true);    //設置webview推薦使用的窗口,使html界面自適應屏幕
        settings.setLoadWithOverviewMode(true);
        settings.setSaveFormData(true);    //設置webview保存表單數據
        settings.setSavePassword(true);    //設置webview保存密碼

        int mDensity = DensityUtils.getDensityDpi(context);
        if (mDensity == 120) {
            settings.setDefaultZoom(WebSettings.ZoomDensity.CLOSE);
        } else if (mDensity == 160) {
            settings.setDefaultZoom(WebSettings.ZoomDensity.MEDIUM);
        } else if (mDensity == 240) {
            settings.setDefaultZoom(WebSettings.ZoomDensity.FAR);
        }
//        settings.setDefaultZoom(WebSettings.ZoomDensity.MEDIUM);    //設置中等像素密度,medium=160dpi
        settings.setSupportZoom(true);    //支持縮放
        settings.setSupportMultipleWindows(true);
        settings.setAppCacheEnabled(true); //設置APP可以緩存
        settings.setDatabaseEnabled(true);
        settings.setDomStorageEnabled(true);//返回上個界面不刷新  允許本地緩存
        //        settings.setCacheMode(WebSettings.LOAD_DEFAULT);// 設置緩存LOAD_DEFAULT   LOAD_CACHE_ONLY,LOAD_NO_CACHE
        settings.setAllowFileAccess(true);// 設置可以訪問文件
        settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);//不支持放大縮小
        settings.setDisplayZoomControls(false);//不支持放大縮小
        //      NORMAL:正常顯示,沒有渲染變化。
        //      SINGLE_COLUMN:把所有內容放到WebView組件等寬的一列中。   //這個是強制的,把網頁都擠變形了
        //      NARROW_COLUMNS:可能的話,使所有列的寬度不超過屏幕寬度。 //好像是默認的

        mWebView.setLongClickable(true);
        mWebView.setScrollbarFadingEnabled(true);
        mWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
        mWebView.setDrawingCacheEnabled(true)

js調取拍照和選擇圖片功能,兼容3.0以上

//5.0以下使用
    private ValueCallback<Uri> uploadMessage;
// 5.0及以上使用
    private ValueCallback<Uri[]> uploadMessageAboveL;

                    //覆蓋WebView默認使用第三方或系統默認瀏覽器打開網頁的行為,使網頁用WebView打開
                     mWebView.setWebChromeClient(new WebChromeClient() {
                           // For Android < 3.0
                           public void openFileChooser(ValueCallback<Uri> valueCallback) {
                                 uploadMessage = valueCallback;
                                 openImageChooserActivity();
                            }

                            // For Android  >= 3.0
                           public void openFileChooser(ValueCallback valueCallback, String acceptType) {
                                uploadMessage = valueCallback;
                                openImageChooserActivity();
                            }

                            //For Android  >= 4.1
                            public void openFileChooser(ValueCallback<Uri> valueCallback, String acceptType, String capture) {
                                uploadMessage = valueCallback;
                                openImageChooserActivity();
                            }

                            // For Android >= 5.0
                            @Override
                            public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
                                uploadMessageAboveL = filePathCallback;
                                openImageChooserActivity();
                                return true;
                            }
                      });

這里需要彈出一個對話框讓用戶選擇拍照和圖庫,這里用的是第三方MaterialDialog

這里有個需要注意的地方,就是如果沒有調用onReceiveValue(null)的方法,下一次js將無法生效,
我這里讓用戶不能按返回鍵和點擊屏幕外消失,當點擊取消按鈕的時候調用onReceiveValue(null)方法

//圖片
    private final static int FILE_CHOOSER_RESULT_CODE = 128;
//拍照
    private final static int FILE_CAMERA_RESULT_CODE = 129;
//拍照圖片路徑
    private String cameraFielPath;

    private void openImageChooserActivity() {
        new MaterialDialog.Builder(this)
                .items(R.array.photo)
                .positiveText("取消")
                .onPositive(new MaterialDialog.SingleButtonCallback() {
                    @Override
                    public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                        if (uploadMessageAboveL != null) {
                            uploadMessageAboveL.onReceiveValue(null);
                            uploadMessageAboveL = null;
                        }
                        if (uploadMessage != null) {
                            uploadMessage.onReceiveValue(null);
                            uploadMessage = null;
                        }
                        dialog.dismiss();
                    }
                })
                .cancelable(false)
                .canceledOnTouchOutside(false)
                .itemsCallback(new MaterialDialog.ListCallback() {
                    @Override
                    public void onSelection(MaterialDialog dialog, View itemView, int position, CharSequence text) {
                        if (position == 0) {
                            takeCamera();
                        } else if (position == 1) {
                            takePhoto();
                        }
                    }
                }).show();
    }
 
//選擇圖片
 private void takePhoto() {
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("image/*");
        startActivityForResult(Intent.createChooser(i, "Image Chooser"), FILE_CHOOSER_RESULT_CODE);
    }

//拍照
    private void takeCamera() {
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (CommonUtil.hasSdcard()) {
              //這里可能需要檢查文件夾是否存在
              //File file = new File(Environment.getExternalStorageDirectory() + "/APPNAME/");
              //if (!file.exists()) {
              //  file.mkdirs();
              //}
            cameraFielPath = Environment.getExternalStorageDirectory() + "upload.jpg";
            File outputImage = new File(cameraFielPath);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(outputImage));
            startActivityForResult(intent, FILE_CAMERA_RESULT_CODE);
        }
    }

最后一步在界面onActivityResult中判斷進行操作

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (null == uploadMessage && null == uploadMessageAboveL) return;
        if (resultCode != RESULT_OK) {//同上所說需要回調onReceiveValue方法防止下次無法響應js方法
            if (uploadMessageAboveL != null) {
                uploadMessageAboveL.onReceiveValue(null);
                uploadMessageAboveL = null;
            }
            if (uploadMessage != null) {
                uploadMessage.onReceiveValue(null);
                uploadMessage = null;
            }
            return;
        }
        Uri result = null;
        if (requestCode == FILE_CAMERA_RESULT_CODE) {
            if (null != data && null != data.getData()) {
                result = data.getData();
            }
            if (result == null && hasFile(cameraFielPath)) {
                result = Uri.fromFile(new File(cameraFielPath));
            }
            if (uploadMessageAboveL != null) {
                uploadMessageAboveL.onReceiveValue(new Uri[]{result});
                uploadMessageAboveL = null;
            } else if (uploadMessage != null) {
                uploadMessage.onReceiveValue(result);
                uploadMessage = null;
            }
        } else if (requestCode == FILE_CHOOSER_RESULT_CODE) {
            if (data != null) {
                result = data.getData();
            }
            if (uploadMessageAboveL != null) {
                onActivityResultAboveL(data);
            } else if (uploadMessage != null) {
                uploadMessage.onReceiveValue(result);
                uploadMessage = null;
            }
        }
    }

    /**
     * 判斷文件是否存在
     */
    public static boolean hasFile(String path) {
        try {
            File f = new File(path);
            if (!f.exists()) {
                return false;
            }
        } catch (Exception e) {
            // TODO: handle exception
            return false;
        }
        return true;
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void onActivityResultAboveL(Intent intent) {
        Uri[] results = null;
        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)};
        }
        uploadMessageAboveL.onReceiveValue(results);
        uploadMessageAboveL = null;
    }

完結 ,代碼就這么多 經過測試可以完成圖片的選擇和拍照。做個記錄方便下次使用

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容