Android 4.4 WebView file chooser not opening?

后端 未结 9 493
南旧
南旧 2020-12-14 07:25

We are creating an app which uses the webview and will access a page where the user needs to upload a file. We are experiencing problems with Android 4.4 where the file choo

相关标签:
9条回答
  • 2020-12-14 07:51

    WebView is working as intended

    If I understand correctly what the above link says , you (me and probably some hundreds more developers) are looking for a hack

    0 讨论(0)
  • 2020-12-14 07:52

    Have a look this. Because api 19 4.4, webview has been migrated to use Chromium, not WebChromeClient anymore.

    0 讨论(0)
  • 2020-12-14 07:53

    I have tried the File Chooser in a webview using the latest Android release 4.4.3, and it's working fine. I guess Google has fixed the issue.

    0 讨论(0)
  • 2020-12-14 07:54

    This Code worked for me.

        private class MyWebChromeClient extends WebChromeClient {
        //The undocumented magic method override
        //Eclipse will swear at you if you try to put @Override here
    
    
        // For Android 3.0+
        public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
            mUploadMessage = uploadMsg;
            Intent i = new Intent(Intent.ACTION_GET_CONTENT);
            i.addCategory(Intent.CATEGORY_OPENABLE);
            i.setType("*/*");
            MainActivity1.this.startActivityForResult(Intent.createChooser(i, "File Browser"), FILECHOOSER_RESULTCODE);
        }
    
        //For Android 4.1+ only
        protected void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture)
        {
            mUploadMessage = uploadMsg;
            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
            intent.addCategory(Intent.CATEGORY_OPENABLE);
            intent.setType("*/*");
            startActivityForResult(Intent.createChooser(intent, "File Browser"), FILECHOOSER_RESULTCODE);
        }
    
        protected void openFileChooser(ValueCallback<Uri> uploadMsg)
        {
            mUploadMessage = uploadMsg;
            Intent i = new Intent(Intent.ACTION_GET_CONTENT);
            i.addCategory(Intent.CATEGORY_OPENABLE);
            i.setType("*/*");
            startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
        }
    
        // For Lollipop 5.0+ Devices
        public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
            if (uploadMessage != null) {
                uploadMessage.onReceiveValue(null);
                uploadMessage = null;
            }
    
            uploadMessage = filePathCallback;
            Intent intent = null;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                intent = fileChooserParams.createIntent();
            }
            try {
                startActivityForResult(intent, REQUEST_SELECT_FILE);
            } catch (ActivityNotFoundException e) {
                uploadMessage = null;
                Toast.makeText(getApplicationContext(), "Cannot Open File Chooser", Toast.LENGTH_LONG).show();
                return false;
            }
            return true;
        }
    
        @Override
        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
    
            Log.d("LogTag", message);
            result.confirm();
            return true;
        }
    }
    
      @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_SELECT_FILE) {
            if (uploadMessage == null) return;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, data));
            }
            uploadMessage = null;
        } else if (requestCode == FILECHOOSER_RESULTCODE) {
            if (null == mUploadMessage)
                return;
            // Use MainActivity.RESULT_OK if you're implementing WebView inside Fragment
            // Use RESULT_OK only if you're implementing WebView inside an Activity
            Uri result = data == null || resultCode != MainActivity.RESULT_OK ? null : data.getData();
            mUploadMessage.onReceiveValue(result);
            mUploadMessage = null;
        }
    }
    
    0 讨论(0)
  • 2020-12-14 07:54

    Android Kotlin,

    MyWebViewChromeClient class:

    class MyWebViewChromeClient(private val mContext: MyMainActivity): WebChromeClient() {
    
        override fun onShowFileChooser(webView: WebView, filePathCallback: ValueCallback<Array<Uri>>, fileChooserParams: FileChooserParams): Boolean {
            mContext.mUploadMessageArray?.onReceiveValue(null)
            mContext.mUploadMessageArray = filePathCallback
    
            val contentSelectionIntent = Intent(Intent.ACTION_GET_CONTENT)
            contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE)
            contentSelectionIntent.type = "*/*"
            val intentArray: Array<Intent?> = arrayOfNulls(0)
    
            val chooserIntent = Intent(Intent.ACTION_CHOOSER)
            chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent)
            chooserIntent.putExtra(Intent.EXTRA_TITLE, "File Chooser")
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray)
            mContext.startActivityForResult(chooserIntent, mContext.FILECHOOSER_RESULTCODE)
            return true
        }
    

    MyMainActivity class:

    class MyMainActivity : MyBaseActivity() {
    
        val FILECHOOSER_RESULTCODE = 1001
        var mUploadMessageArray: ValueCallback<Array<Uri>>? = null
    
        private lateinit var mWebView: MyWebView
        private lateinit var mContext: Context
    
        override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
            if (requestCode == FILECHOOSER_RESULTCODE) {
                if (mUploadMessageArray == null) {
                    return
                }
                val result = if (intent == null || resultCode != Activity.RESULT_OK) null else data?.data
                result?.let {
                    val uriArray: Array<Uri> = arrayOf(it)
                    mUploadMessageArray?.onReceiveValue(uriArray)
                    mUploadMessageArray = null
                } ?: kotlin.run {
                    mUploadMessageArray?.onReceiveValue(null)
                    mUploadMessageArray = null
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-14 07:57

    I was working on this issue too, and the problem and here is my solution

    private class MyWebChromeClient extends WebChromeClient {
    
    
        /**
         * This is the method used by Android 5.0+ to upload files towards a web form in a Webview
         *
         * @param webView
         * @param filePathCallback
         * @param fileChooserParams
         * @return
         */
        @Override
        public boolean onShowFileChooser(
                WebView webView, ValueCallback<Uri[]> filePathCallback,
                WebChromeClient.FileChooserParams fileChooserParams) {
    
            if (mFilePathCallback != null) {
                mFilePathCallback.onReceiveValue(null);
            }
            mFilePathCallback = filePathCallback;
    
            Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
            contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
            contentSelectionIntent.setType("image/*");
    
            Intent[] intentArray = getCameraIntent();
    
            Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
            chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
            chooserIntent.putExtra(Intent.EXTRA_TITLE, "Seleccionar Fuente");
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
    
            startActivityForResult(chooserIntent, INPUT_FILE_REQUEST_CODE);
    
            return true;
        }
    
        @Override
        public void onProgressChanged(WebView view, int newProgress) {
    
            mProgressBar.setVisibility(View.VISIBLE);
            WebActivity.this.setValue(newProgress);
            super.onProgressChanged(view, newProgress);
        }
    
        @Override
        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
    
            Log.d("LogTag", message);
            result.confirm();
            return true;
        }
    
        /**
         * Despite that there is not a Override annotation, this method overrides the open file
         * chooser function present in Android 3.0+
         *
         * @param uploadMsg
         * @author Tito_Leiva
         */
        public void openFileChooser(ValueCallback<Uri> uploadMsg) {
    
            mUploadMessage = uploadMsg;
            Intent i = getChooserIntent(getCameraIntent(), getGalleryIntent("image/*"));
            i.addCategory(Intent.CATEGORY_OPENABLE);
            WebActivity.this.startActivityForResult(Intent.createChooser(i, "Selecciona la imagen"), FILECHOOSER_RESULTCODE);
    
        }
    
        public void openFileChooser(ValueCallback uploadMsg, String acceptType) {
            mUploadMessage = uploadMsg;
            Intent i = getChooserIntent(getCameraIntent(), getGalleryIntent("*/*"));
            i.addCategory(Intent.CATEGORY_OPENABLE);
            WebActivity.this.startActivityForResult(
                    Intent.createChooser(i, "Selecciona la imagen"),
                    FILECHOOSER_RESULTCODE);
        }
    
        /**
         * Despite that there is not a Override annotation, this method overrides the open file
         * chooser function present in Android 4.1+
         *
         * @param uploadMsg
         * @author Tito_Leiva
         */
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
            mUploadMessage = uploadMsg;
            Intent i = getChooserIntent(getCameraIntent(), getGalleryIntent("image/*"));
            WebActivity.this.startActivityForResult(Intent.createChooser(i, "Selecciona la imagen"), FILECHOOSER_RESULTCODE);
    
        }
    
        private Intent[] getCameraIntent() {
    
            // Determine Uri of camera image to save.
            Intent takePictureIntent = new Intent(WebActivity.this, CameraActivity.class);
            if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
                // Create the File where the photo should go
                File photoFile = null;
                try {
                    photoFile = createImageFile();
                    takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath);
                } catch (IOException ex) {
                    // Error occurred while creating the File
                    Log.e(TAG, "Unable to create Image File", ex);
                }
    
                // Continue only if the File was successfully created
                if (photoFile != null) {
                    mCameraPhotoPath = "file:" + photoFile.getAbsolutePath();
                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
                            Uri.fromFile(photoFile));
                } else {
                    takePictureIntent = null;
                }
            }
    
            Intent[] intentArray;
            if (takePictureIntent != null) {
                intentArray = new Intent[]{takePictureIntent};
            } else {
                intentArray = new Intent[0];
            }
    
            return intentArray;
    
        }
    
        private Intent getGalleryIntent(String type) {
    
            // Filesystem.
            final Intent galleryIntent = new Intent();
            galleryIntent.setType(type);
            galleryIntent.addCategory(Intent.CATEGORY_OPENABLE);
            galleryIntent.setAction(Intent.ACTION_GET_CONTENT);
    
            return galleryIntent;
        }
    
        private Intent getChooserIntent(Intent[] cameraIntents, Intent galleryIntent) {
    
            // Chooser of filesystem options.
            final Intent chooserIntent = Intent.createChooser(galleryIntent, "Seleccionar Fuente");
    
            // Add the camera options.
            chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents);
    
            return chooserIntent;
        }
    }
    

    One problem that I solved is the uri delivered for the onActivityResult() method does not have extension. To solve this I use this method

    public static Uri savePicture(Context context, Bitmap bitmap, int maxSize) {
    
        int cropWidth = bitmap.getWidth();
        int cropHeight = bitmap.getHeight();
    
        if (cropWidth > maxSize) {
            cropHeight = cropHeight * maxSize / cropWidth;
            cropWidth = maxSize;
    
        }
    
        if (cropHeight > maxSize) {
            cropWidth = cropWidth * maxSize / cropHeight;
            cropHeight = maxSize;
    
        }
    
        bitmap = ThumbnailUtils.extractThumbnail(bitmap, cropWidth, cropHeight, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
    
        File mediaStorageDir = new File(
                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
                context.getString(R.string.app_name)
        );
    
        if (!mediaStorageDir.exists()) {
            if (!mediaStorageDir.mkdirs()) {
                return null;
            }
        }
    
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        File mediaFile = new File(
                mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg"
        );
    
        // Saving the bitmap
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
    
            FileOutputStream stream = new FileOutputStream(mediaFile);
            stream.write(out.toByteArray());
            stream.close();
    
        } catch (IOException exception) {
            exception.printStackTrace();
        }
    
        // Mediascanner need to scan for the image saved
        Intent mediaScannerIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        Uri fileContentUri = Uri.fromFile(mediaFile);
        mediaScannerIntent.setData(fileContentUri);
        context.sendBroadcast(mediaScannerIntent);
    
        return fileContentUri;
    } 
    

    Finally, onActivityResult() method is

    @Override
    protected void onActivityResult(int requestCode, int resultCode,
                                    Intent intent) {
    
        if (resultCode == RESULT_OK) {
    
            // This is for Android 4.4.4- (JellyBean & KitKat)
            if (requestCode == FILECHOOSER_RESULTCODE) {
    
                if (null == mUploadMessage) {
                    super.onActivityResult(requestCode, resultCode, intent);
                    return;
                }
    
                final boolean isCamera;
    
                if (intent == null) {
                    isCamera = true;
                } else {
                    final String action = intent.getAction();
                    if (action == null) {
                        isCamera = false;
                    } else {
                        isCamera = action.equals(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                    }
                }
    
                Uri selectedImageUri;
    
                if (isCamera) {
    
                    selectedImageUri = mOutputFileUri;
                    mUploadMessage.onReceiveValue(selectedImageUri);
                    mUploadMessage = null;
    
                    return;
    
                } else {
    
                    try {
    
                        Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), intent.getData());
                        selectedImageUri = intent == null ? null : ImageUtility.savePicture(this, bitmap, 1400);
    
                        mUploadMessage.onReceiveValue(selectedImageUri);
                        mUploadMessage = null;
    
                        return;
    
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
    
                // And this is for Android 5.0+ (Lollipop)
            } else if (requestCode == INPUT_FILE_REQUEST_CODE) {
    
                Uri[] results = null;
    
                // Check that the response is a good one
                if (resultCode == Activity.RESULT_OK) {
                    if (intent == null) {
                        // If there is not data, then we may have taken a photo
                        if (mCameraPhotoPath != null) {
                            results = new Uri[]{Uri.parse(mCameraPhotoPath)};
                        }
                    } else {
    
                        Bitmap bitmap = null;
    
                        try {
                            bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), intent.getData());
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
    
                        Uri dataUri = ImageUtility.savePicture(this, bitmap, 1400);
    
                        if (dataUri != null) {
                            results = new Uri[]{dataUri};
                        }
                    }
                }
    
                mFilePathCallback.onReceiveValue(results);
                mFilePathCallback = null;
    
                return;
            }
        } else {
    
            super.onActivityResult(requestCode, resultCode, intent);
            return;
        }
    } 
    
    0 讨论(0)
提交回复
热议问题