web-dev-qa-db-fra.com

onShowFileChooser () à partir d'Android Webview ne fonctionne qu'une fois

Je dois choisir des images sur l'appareil et les télécharger sur le serveur. Pour la première fois, lorsque je sélectionne les images, onShowFileChooser () est appelée et tout fonctionne. Mais, lorsque j'essaie de cliquer à nouveau sur le téléchargement, onShowFileChooser () n'est jamais appelé. Mais cela fonctionne pour les appareils non Lollypop. openFileChoser () est appelé, chaque fois que je clique sur Télécharger. Y a-t-il quelque chose qui me manque? Voici mon code:

        //Needed for file upload feature
        vWebView.setWebChromeClient(new WebChromeClient() {

            // file upload callback (Android 2.2 (API level 8) -- Android 2.3 (API level 10)) (hidden method)
            public void openFileChooser(ValueCallback<Uri> filePathCallback) {
                showAttachmentDialog(filePathCallback);
            }

            // file upload callback (Android 3.0 (API level 11) -- Android 4.0 (API level 15)) (hidden method)
            public void openFileChooser(ValueCallback filePathCallback, String acceptType) {
                showAttachmentDialog(filePathCallback);
            }

            // file upload callback (Android 4.1 (API level 16) -- Android 4.3 (API level 18)) (hidden method)
            public void openFileChooser(ValueCallback<Uri> filePathCallback, String acceptType, String capture) {
                showAttachmentDialog(filePathCallback);

            }

            // file upload callback (Android 5.0 (API level 21) -- current) (public method)

            // for Lollipop, all in one
            @Override

            public boolean onShowFileChooser(
                    WebView webView, ValueCallback<Uri[]> filePathCallback,
                    WebChromeClient.FileChooserParams fileChooserParams) {
                // Double check that we don't have any existing callbacks
                if (mFilePathCallbackArray != null) {
                    mFilePathCallbackArray.onReceiveValue(null);
                }
                mFilePathCallbackArray = filePathCallback;
                // Set up the take picture intent

                if (mTypeCap == IMAGE) {
                    Intent takePictureIntent = pictureIntentSetup();
                    return showChooserDialog(takePictureIntent);
                }
                //set up video capture intent
                else {
                    Intent takeVideoIntent = videoIntentSetUp();
                    return showChooserDialog(takeVideoIntent);
                }

            }

        });

  //For lollypop
    private Intent pictureIntentSetup() {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (takePictureIntent.resolveActivity(getActivity().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("Failed", "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;
            }
        }
        return takePictureIntent;

    }

    //For lollypop
    private Intent videoIntentSetUp() {
        Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
        if (takeVideoIntent.resolveActivity(getActivity().getPackageManager()) != null) {

            // create the file where the video should go
            File videoFile = null;
            try {
                videoFile = createVideoFile();
                takeVideoIntent.putExtra("PhotoPath", mCameraPhotoPath);
            } catch (IOException ex) {
                // Error occurred while creating the File
                Log.e("Failed", "Unable to create Video File", ex);
            }

            // continue only if the file was successfully created
            if (videoFile != null) {
                mCameraPhotoPath = "file:" + videoFile.getAbsolutePath();
                takeVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT,
                        Uri.fromFile(videoFile));
            } else {
                takeVideoIntent = null;
            }
        }
        return takeVideoIntent;
    }

//For lollypop
    private boolean showChooserDialog(Intent intent) {
        Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
        contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
        if (mTypeCap.equalsIgnoreCase(IMAGE))
            contentSelectionIntent.setType(IMAGE);
        else
            contentSelectionIntent.setType(VIDEO);

        Intent[] intentArray;
        if (intent != null) {
            intentArray = new Intent[]{intent};
        } else {
            intentArray = new Intent[0];
        }

        Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
        chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
        if (mTypeCap.equalsIgnoreCase(IMAGE))
            chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");
        else
            chooserIntent.putExtra(Intent.EXTRA_TITLE, "Video Chooser");
        chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);

        getActivity().startActivityForResult(chooserIntent, FILE_CHOOSER_RESULT_CODE);

        return true;
    }

OnActivityResult de l'activité:

  @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
  //File upload related
            if (requestCode == NewsDetailFragment.FILE_CHOOSER_RESULT_CODE && (resultCode == RESULT_OK || resultCode == RESULT_CANCELED)) {
                Fragment fragment = getSupportFragmentManager()
                        .findFragmentById(R.id.container);
                if (fragment != null && fragment instanceof DetailFragment) {
                    Fragment currentFragment = ((DetailFragment) fragment).getCurrentFragment();
                    if (currentFragment instanceof WebDetailFragment)
                        currentFragment.onActivityResult(requestCode, resultCode, data);
                }
            }

        }
}

onActivityResult of fragment:

 @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intentData) {
        super.onActivityResult(requestCode, resultCode, intentData);
        // code for all versions except of Lollipop
        if (!Utility.isLollypopAndAbove()) {
            Uri result = null;
            // check that the response is a good one
            if (resultCode == Activity.RESULT_OK) {
                if (requestCode == FILE_CHOOSER_RESULT_CODE) {
                    if (null == this.mFilePathCallback) {
                        return;
                    }
                    if (null == mFilePathCallback) return;


                    if (intentData == null) {
                        // if there is not data, then we may have taken a photo
                        if (mCameraPhotoPath != null) {
                            result = Uri.parse(mCameraPhotoPath);
                        }
                    } else {
                        String dataString = intentData.getDataString();
                        if (dataString != null) {
                            result = Uri.parse(dataString);
                        }
                    }
//                Uri result = intentData == null || resultCode != Activity.RESULT_OK ? null
//                        : intentData.getData();

                }

                //  for Lollipop only
            }
            mFilePathCallback.onReceiveValue(result);
            mFilePathCallback = null;
        }
        else  {
            Uri[] results = null;

            // check that the response is a good one
            if(resultCode==Activity.RESULT_OK) {
                if (requestCode == FILE_CHOOSER_RESULT_CODE) {
                    if (null == mFilePathCallbackArray) {
                        return;
                    }
                    if (intentData == null) {
                        // if there is not data, then we may have taken a photo
                        if (mCameraPhotoPath != null) {
                            results = new Uri[]{Uri.parse(mCameraPhotoPath)};
                        }
                    } else {
                        String dataString = intentData.getDataString();
                        if (dataString != null) {
                            results = new Uri[]{Uri.parse(dataString)};
                        }
                    }
                }
            }
            mFilePathCallbackArray.onReceiveValue(results);
            mFilePathCallbackArray = null;
            return;

        }
    }
11
Sangeetha Pinto

tout d'abord, désolé pour mon anglais. vous devez retourner Uri [] {} vide dans le fichier receive

mUploadMessageForAndroid5.onReceiveValue(new Uri[]{});

mon code peut choisir prendre photo ou image locale:

private static final int REQUEST_GET_THE_THUMBNAIL = 4000;
private static final long ANIMATION_DURATION = 200;
public final static int FILECHOOSER_RESULTCODE = 1;
public final static int FILECHOOSER_RESULTCODE_FOR_Android_5 = 2;

//JS
webView.getSettings().setJavaScriptEnabled(true);

//set ChromeClient
webView.setWebChromeClient(getChromeClient());

//ChromeClinet配置
private WebChromeClient getChromeClient() {
    return new WebChromeClient() {

        //3.0++
        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
            openFileChooserImpl(uploadMsg);
        }

        //3.0--
        public void openFileChooser(ValueCallback<Uri> uploadMsg) {
            openFileChooserImpl(uploadMsg);
        }

        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
            openFileChooserImpl(uploadMsg);
        }

        // For Android > 5.0
        public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> uploadMsg, WebChromeClient.FileChooserParams fileChooserParams) {
            openFileChooserImplForAndroid5(uploadMsg);
            return true;
        }

    };
}

private void openFileChooserImpl(ValueCallback<Uri> uploadMsg) {
    mUploadMessage = uploadMsg;
    new AlertDialog.Builder(mActivity)
            .setItems(items, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    if (items[which].equals(items[0])) {
                        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
                        i.addCategory(Intent.CATEGORY_OPENABLE);
                        i.setType("image/*");
                        startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
                    } else if (items[which].equals(items[1])) {
                        dispatchTakePictureIntent();
                    }
                    dialog.dismiss();
                }
            })
            .setOnCancelListener(new DialogInterface.OnCancelListener() {
                @Override
                public void onCancel(DialogInterface dialog) {
                    Log.v(TAG, TAG + " # onCancel");
                    mUploadMessage = null;
                    dialog.dismiss();
            }})
            .show();
}

private void openFileChooserImplForAndroid5(ValueCallback<Uri[]> uploadMsg) {
    mUploadMessageForAndroid5 = uploadMsg;

    new AlertDialog.Builder(mActivity)
            .setItems(items, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    if (items[which].equals(items[0])) {
                        Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
                        contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
                        contentSelectionIntent.setType("image/*");

                        Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
                        chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
                        chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser");

                        startActivityForResult(chooserIntent, FILECHOOSER_RESULTCODE_FOR_Android_5);
                    } else if (items[which].equals(items[1])) {
                        dispatchTakePictureIntent();
                    }
                    dialog.dismiss();
                }
            })
            .setOnCancelListener(new DialogInterface.OnCancelListener() {
                @Override
                public void onCancel(DialogInterface dialog) {
                    Log.v(TAG, TAG + " # onCancel");
                    //important to return new Uri[]{}, when nothing to do. This can slove input file wrok for once.
                    //InputEventReceiver: Attempted to finish an input event but the input event receiver has already been disposed.
                    mUploadMessageForAndroid5.onReceiveValue(new Uri[]{});
                    mUploadMessageForAndroid5 = null;
                    dialog.dismiss();
            }}).show();
}

private void dispatchTakePictureIntent() {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (takePictureIntent.resolveActivity(mActivity.getPackageManager()) != null) {
//            File file = new File(createImageFile());
        Uri imageUri = null;
        try {
            imageUri = Uri.fromFile(createImageFile());
        } catch (IOException e) {
            e.printStackTrace();
        }
        //temp sd card file
        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        startActivityForResult(takePictureIntent, REQUEST_GET_THE_THUMBNAIL);
    }
}

private File createImageFile() throws IOException {
    // Create an image file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_";
    File storageDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/don_test/");
    if (!storageDir.exists()) {
        storageDir.mkdirs();
    }
    File image = File.createTempFile(
            imageFileName,  /* prefix */
            ".jpg",         /* suffix */
            storageDir      /* directory */
    );

    // Save a file: path for use with ACTION_VIEW intents
    mCurrentPhotoPath = image.getAbsolutePath();
    return image;
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
    Log.v(TAG, TAG + " # onActivityResult # requestCode=" + requestCode + " # resultCode=" + resultCode);
    if (requestCode == FILECHOOSER_RESULTCODE) {
        if (null == mUploadMessage)
            return;
        Uri result = intent == null || resultCode != Activity.RESULT_OK ? null : intent.getData();
        mUploadMessage.onReceiveValue(result);
        mUploadMessage = null;

    } else if (requestCode == FILECHOOSER_RESULTCODE_FOR_Android_5) {
        if (null == mUploadMessageForAndroid5)
            return;
        Uri result;

        if (intent == null || resultCode != Activity.RESULT_OK) {
            result = null;
        } else {
            result = intent.getData();
        }

        if (result != null) {
            Log.v(TAG, TAG + " # result.getPath()=" + result.getPath());
            mUploadMessageForAndroid5.onReceiveValue(new Uri[]{result});
        } else {
            mUploadMessageForAndroid5.onReceiveValue(new Uri[]{});
        }
        mUploadMessageForAndroid5 = null;
    } else if (requestCode == REQUEST_GET_THE_THUMBNAIL) {
        if (resultCode == Activity.RESULT_OK) {
            File file = new File(mCurrentPhotoPath);
            Uri localUri = Uri.fromFile(file);
            Intent localIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, localUri);
            mActivity.sendBroadcast(localIntent);

            Uri result = Uri.fromFile(file);
            mUploadMessageForAndroid5.onReceiveValue(new Uri[]{result});
            mUploadMessageForAndroid5 = null;
        } else {

            File file = new File(mCurrentPhotoPath);
            Log.v(TAG, TAG + " # file=" + file.exists());
            if (file.exists()) {
                file.delete();
            }
        }
    }
}
16
Don Tan Xu Dong

Face à un problème similaire, je retournais une valeur booléenne dans la méthode onShowFileChooser, ce problème a été résolu lorsque j'ai appelé la méthode de la classe super

        @Override
        public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
            //Logic to implement 
            return super.onShowFileChooser(webView, filePathCallback, fileChooserParams);
        }
6
ked

Laissez simplement onShowFIleChooser() return false, fonctionnera la prochaine fois

public boolean onShowFileChooser(){
... 
return **false**;
}
1
趙令文

J'ai eu exactement le même problème, mais mon cas d'utilisation est un peu différent, mais ma vue Web a été chargée sur un fragment tel quel dans votre code. la première fois que le sélecteur de fichier s’affichait correctement sur les périphériques Lollipop et pré Lollipop, mais la prochaine fois, il n’a pas pu l’afficher lui-même. La Raison étant la, je n’ai pas traité onActivityResult de la manière appropriée à la première fois. Mon extrait de code de travail est le suivant pour Lollipop:

 @TargetApi(Build.VERSION_CODES.Lollipop)

 private boolean onActivityResultLolliPop(
      int requestCode, int resultCode, Intent data) {

    if (requestCode != SurveyWebChromeClient.FILE_CHOOSER_REQUEST_CODE 
            || mFilePathCallbackL == null) {
        super.onActivityResult(requestCode, resultCode, data);
        return true;
    }

    Uri[] results = null;
    if (resultCode == Activity.RESULT_OK) {
        if (data == null) {
            if (mCameraPhotoVideoPath != null) {//if there is not data here, then we may have taken a photo/video
                results = new Uri[]{Uri.parse(mCameraPhotoVideoPath)};
            }
        } else {
            String dataString = data.getDataString();
            ClipData clipData = data.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)};
        }
    }
    mFilePathCallbackL.onReceiveValue(results);
    mFilePathCallbackL = null;
    return false;
}
1
MadKavi

Dans la méthode onShowFileChooser (), vous devriez renvoyer true, uniquement si vous utilisez filePathCallback, ce qui est le meilleur moyen:

private ValueCallback<Uri[]> filePathCallback;

@Override
public boolean onShowFileChooser(
        WebView webView, ValueCallback<Uri[]> filePathCallback,
        WebChromeClient.FileChooserParams fileChooserParams) {
    // do whatever you need to do, to show a file chooser/camera intent
    this.filePathCallback = filePathCallback;
    return true;
}

@Override
protected void onActivityResult(int requestCode, int resultCode,
                                Intent intent) {
    // Check for your correct requestCode from your intent here
    if (resultCode == RESULT_CANCELED) {
        // this is important, call the callback with null parameter
        this.filePathCallback.onReceiveValue(null);
    } else if (resultCode == RESULT_OK) {
        // extract the uri(s) you need here
        this.filePathCallback.onReceiveValue(new Uri[]{result});
    }
}
0