Android WebView內嵌網頁input無法選擇文件解決打賞

最近發現公司APP內嵌的網頁點擊上傳圖片沒任何效果,查資料得知是Android安全限制,WebView內網頁默認沒有讀取本地文件的權限。雖然網上有解決方案,但是由于Android版本幾經波折,API簽名大相徑庭,想要完全兼容,要實現多個方法,為方便以后使用,簡單記錄一下。

首先,在使用WebView的頁面,增加如下全局變量,方便回調使用:

private static final String FILE_CHOOSER = "選擇操作";
private String mCM;
private ValueCallback<Uri> mUM;
private ValueCallback<Uri[]> mUMA;
private final static int FCR = 1;

然后覆蓋onActivityResult方法,內部實現如下:

//解決android input[type=file] 無法選擇圖片
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);
    if (Build.VERSION.SDK_INT >= 21) {
        Uri[] results = null;
        //Check if response is positive
        if (resultCode == Activity.RESULT_OK) {
            if (requestCode == FCR) {
                if (null == mUMA) {
                    return;
                }
                if (intent == null) {
                    //Capture Photo if no image available
                    if (mCM != null) {
                        results = new Uri[]{Uri.parse(mCM)};
                    }
                } else {
                    String dataString = intent.getDataString();
                    if (dataString != null) {
                        results = new Uri[]{Uri.parse(dataString)};
                    }
                }
            }
        }
        mUMA.onReceiveValue(results);
        mUMA = null;
    } else {
        if (requestCode == FCR) {
            if (null == mUM) return;
            Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData();
            mUM.onReceiveValue(result);
            mUM = null;
        }
    }
}

關鍵部分,繼承WebChromeClient,并實現如下方法,最終調用WebView的setWebChromeClient方法:

//For Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
    mUM = uploadMsg;
    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("*/*");
    startActivityForResult(Intent.createChooser(intent, FILE_CHOOSER), FCR);
}
// For Android 3.0+, above method not supported in some android 3+ versions, in such case we use this
public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
    mUM = uploadMsg;
    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("*/*");
    startActivityForResult(Intent.createChooser(intent, FILE_CHOOSER), FCR);
}
//For Android 4.1+
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
    mUM = uploadMsg;
    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("*/*");
    startActivityForResult(Intent.createChooser(intent, FILE_CHOOSER), FCR);
}
//For Android 5.0+
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
    if (mUMA != null) {
        mUMA.onReceiveValue(null);
    }
    mUMA = filePathCallback;
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
        File photoFile = null;
        try {
            photoFile = createImageFile();
            takePictureIntent.putExtra("PhotoPath", mCM);
        } catch (IOException ex) {
            Log.e(TAG, "Image file creation failed", ex);
        }
        if (photoFile != null) {
            mCM = "file:" + photoFile.getAbsolutePath();
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
        } else {
            takePictureIntent = null;
        }
    }
    Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
    contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
    contentSelectionIntent.setType("*/*");
    Intent[] intentArray;
    if (takePictureIntent != null) {
        intentArray = new Intent[]{takePictureIntent};
    } else {
        intentArray = new Intent[0];
    }
    Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
    chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
    chooserIntent.putExtra(Intent.EXTRA_TITLE, FILE_CHOOSER);
    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
    startActivityForResult(chooserIntent, FCR);
    return true;
}
// Create an image file
private File createImageFile() throws IOException {
    @SuppressLint("SimpleDateFormat")
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "img_" + timeStamp + "_";
    File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
    return File.createTempFile(imageFileName, ".jpg", storageDir);
}

注:最后一步四個主要方法中,startActivityForResult實為WebView所在Activity的方法,這里因為我自己的WebView做了定制,實現直接寫在Activity,并且定義了接口傳入自定義的WebView內,這樣分離了WebView與Activity的代碼,如果你WebView沒有做定制等,這里可以改為YourActivity.this.startActivityForResult,請悉知。

Android WebView內嵌網頁input無法選擇文件解決
文章《Android WebView內嵌網頁input無法選擇文件解決》二維碼
  • 微信打賞
  • 支付寶打賞

已有8條評論

  1. MrYanga

    大神,我問一下,有些手機拍照之后照片回調時候獲取不到,估計是什么問題啊?

    2017-09-16 11:04 回復
  2. MrYanga

    大神可否留下QQ,有點小問題需要請教一下.

    2017-09-16 10:41 回復
  3. ilikecss

    這個領域一點都不了解。。

    2017-03-14 12:05 回復
    • 樸人博客

      我也是做一步記錄一步咯,之前也不知道,最近發現這個問題,查了才知道

      2017-03-14 15:13 回復
  4. YOUTUBE下載

    謝謝分享,收藏備用啊

    2017-03-10 11:49 回復
  5. 時刻業余兼職

    路過支持下技術達人

    2017-02-28 18:28 回復

(必填)

(必填)

(可選)

黑龙江22选5开奖