Android WebView调用相机权限适配异常求助(Android 6升级后)
Hey there, let's dig into this issue and figure out what's going wrong, plus how to fix it!
Why this is happening on Android 6+
Android 6.0 (API 23) introduced runtime permission requests for "dangerous" permissions like camera and storage—something older Android versions handled automatically at install time. When you swapped the native <input> click behavior for a Java callback, you took on the responsibility of managing these permissions properly, and it sounds like that flow has a gap right now.
Common missteps that cause this issue:
- You're not fully completing the permission request flow (e.g., asking for permissions but not waiting for the user's response before trying to launch the camera/file picker)
- You're requesting the wrong permissions, or forgetting to declare them in your manifest
- After the user grants permissions, you're not re-triggering the original
<input>click that launches the system's picker/camera - Your WebView's
WebChromeClientisn't properly handling the file chooser callback (required for Android 5+ WebView file selection)
Step-by-step fixes
1. Declare required permissions in your AndroidManifest.xml
First, make sure you've listed the permissions your app needs:
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- For Android 10+, add this if needed --> <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
2. Fix the permission request flow in your Java code
Instead of replacing the <input> entirely, use your Java callback to handle permissions first, then trigger the original <input> click once permissions are granted. Here's a concrete example:
// Define a request code for permission checks private static final int REQUEST_IMAGE_PERMISSIONS = 1001; private WebView mWebView; // This is the method your HTML click event calls via @JavascriptInterface @JavascriptInterface public void triggerImagePicker() { // Check if we already have the required permissions boolean hasCameraPerm = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED; boolean hasStoragePerm = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED; if (hasCameraPerm && hasStoragePerm) { // Permissions are good—trigger the hidden input's click mWebView.loadUrl("javascript:document.getElementById('InputImgFileDialog').click()"); } else { // Request missing permissions String[] permissions = {Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}; ActivityCompat.requestPermissions(this, permissions, REQUEST_IMAGE_PERMISSIONS); } } // Handle the permission request result @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_IMAGE_PERMISSIONS) { boolean allPermissionsGranted = true; for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { allPermissionsGranted = false; break; } } if (allPermissionsGranted) { // User said yes—launch the picker mWebView.loadUrl("javascript:document.getElementById('InputImgFileDialog').click()"); } else { // User denied permissions—show a helpful message Toast.makeText(this, "We need camera and storage permissions to select photos", Toast.LENGTH_SHORT).show(); } } }
3. Ensure your WebChromeClient handles file selection
Android 5+ WebViews require you to implement onShowFileChooser in your WebChromeClient to properly handle file picker triggers. Add this to your WebView setup:
mWebView.setWebChromeClient(new WebChromeClient() { @Override public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { // If you're relying on the native <input> behavior, you can use the default implementation // Or customize it here if you need more control over the picker return super.onShowFileChooser(webView, filePathCallback, fileChooserParams); } });
4. Test edge cases
- Make sure you handle the scenario where the user denies permissions and checks "Don't ask again"—you'll need to redirect them to app settings to enable permissions manually.
- Verify that the
<input>tag'scapture="camera"attribute still works as expected once permissions are granted (it should launch the camera directly if the device supports it).
Quick recap
The core issue is that Android 6+ requires explicit runtime permission checks, which the native <input> handled automatically in older versions. By adding the permission request flow in your Java callback and re-triggering the original <input> click after approval, you'll restore the expected behavior while complying with Android's security rules.
内容的提问来源于stack exchange,提问作者Steve Brooker

