A technical guide to implementing HTML5 file inputs, Camera2 hardware integration, WebChromeClient onShowFileChooser, and runtime permissions.
1. Why Standard HTML File Inputs Fail in Plain WebViews
On a desktop web browser, clicking an <input type="file"> element immediately opens the native operating system file explorer. However, in an unconfigured Android WebView, tapping a file upload button does absolutely nothing. The click event is silently swallowed.
To enable file uploads and camera capture in an Android app, the native host Activity must implement the WebChromeClient.onShowFileChooser() callback and declare proper runtime hardware permissions.
2. The onShowFileChooser Native Implementation
FreeWebAPK implements the modern Android file chooser handler in the native Activity:
webView.setWebChromeClient(new WebChromeClient() {
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
if (mUploadMessage != null) {
mUploadMessage.onReceiveValue(null);
}
mUploadMessage = filePathCallback;
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
contentSelectionIntent.setType("*/*");
Intent[] intentArray = takePictureIntent != null ? new Intent[]{takePictureIntent} : new Intent[0];
Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
chooserIntent.putExtra(Intent.EXTRA_TITLE, "Select Document or Photo");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
startActivityForResult(chooserIntent, FILE_CHOOSER_REQUEST_CODE);
return true;
}
});
3. Direct Camera Capture via HTML5 Attributes
You can trigger direct camera or microphone capture from your web page using standard HTML5 input attributes:
<input type="file" accept="image/*" capture="environment">: Launches the rear camera directly for photographing documents, receipts, or products.<input type="file" accept="image/*" capture="user">: Launches the front selfie camera for user avatar uploads or profile verification.<input type="file" accept="application/pdf">: Opens the native Android DocumentsUI picker filtered strictly to PDF files.
4. Android 13 & 14 Runtime Permissions (READ_MEDIA_IMAGES)
Targeting Android 14 (API 34) requires declaring granular media permissions rather than legacy broad storage permissions:
<!-- AndroidManifest.xml Granular Media Permissions --> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
5. Summary: Flawless Media Integration
Supporting camera capture and file uploads is essential for modern social apps, customer service portals, document verification tools, and eCommerce reviews. FreeWebAPK configures all necessary native bridges automatically.
4. The WebChromeClient File Chooser Architecture
In standard Android WebViews, clicking an HTML <input type="file"> element does nothing unless your native code overrides onShowFileChooser inside a custom WebChromeClient:
import android.webkit.ValueCallback
import android.webkit.WebChromeClient
import android.net.Uri
class AppWebChromeClient(private val activity: Activity) : WebChromeClient() {
var filePathCallback: ValueCallback<Array<Uri>>? = null
override fun onShowFileChooser(
webView: WebView?,
filePathCallback: ValueCallback<Array<Uri>>?,
fileChooserParams: FileChooserParams?
): Boolean {
this.filePathCallback?.onReceiveValue(null) // Cancel previous callback
this.filePathCallback = filePathCallback
val intent = fileChooserParams?.createIntent()
try {
activity.startActivityForResult(intent!!, FILE_CHOOSER_REQUEST_CODE)
} catch (e: Exception) {
this.filePathCallback = null
return false
}
return true
}
}
When the user selects an image from Google Photos, Downloads, or camera capture, the file’s content URI is returned to filePathCallback, allowing standard web forms to upload the file seamlessly.
5. Android 13/14 Granular Media Permissions & The Modern Photo Picker
Google has deprecated the broad READ_EXTERNAL_STORAGE permission. In Android 13 and 14, apps must declare granular media permissions (READ_MEDIA_IMAGES, READ_MEDIA_VIDEO) or utilize Android’s secure Photo Picker (ActivityResultContracts.PickVisualMedia). The Photo Picker requires zero runtime permission requests from the user, drastically elevating trust and conversion.
6. Handling Client-Side Image Compression Before Upload
Modern 108-megapixel smartphone cameras capture photos weighing 15 MB to 30 MB. Uploading raw files over mobile cellular connections triggers timeouts. Use client-side JavaScript canvas compression to resize photos to a maximum dimension of 1920px before submitting forms, reducing upload times by up to 90%.
7. Production Diagnostics: Fixing FileUriExposedException & Memory Crashes
Avoid classic Android media capture crashes with these essential architectural solutions:
- FileUriExposedException on Android 7+: Passing raw
file://URIs to camera intents throws a fatal exception. Always wrap file paths in a secureFileProvider(androidx.core.content.FileProvider) to generate securecontent://URIs. - Activity Killed in Background During Photo Capture: When a user launches the high-memory camera app, low-end devices may kill your background activity to free RAM. Ensure your activity saves its WebView state and file callback pointer in
onSaveInstanceState()so it restores cleanly when the camera returns.
8. Optimizing Media Upload Performance
Empower users with progress bars during multi-megabyte image uploads. By providing visual feedback (e.g. ‘Uploading 45%…’), users remain confident in the upload process, virtually eliminating abandoned form submissions.
9. Media Capture & File Upload Checklist
File Upload Verification
- WebChromeClient File Chooser: Verified file inputs trigger Android file picker dialog.
- Camera Intent Integration: Confirmed capture=’environment’ launches native camera cleanly.
- FileProvider Configuration: Verified content:// URIs are used for secure file transfer.
- Multi-File Selection: Tested multi-image uploads on supported file input elements.
10. Case Study: Insurance Claim Photo Processing in 1.8s
Case Study: SwiftClaim Vehicle Insurance
SwiftClaim enabled native camera upload with client-side image compression for vehicle accident claims:
Drivers standing on highway shoulders captured photos of vehicle damage and submitted insurance claims instantly without cellular upload timeouts.
11. Production Kotlin Code: Full WebChromeClient File Chooser
Wire Android’s native file picker and camera intents to web forms:
class AppWebChromeClient(private val activity: Activity) : WebChromeClient() {
var filePathCallback: ValueCallback<Array<Uri>>? = null
override fun onShowFileChooser(
webView: WebView?,
filePathCallback: ValueCallback<Array<Uri>>?,
fileChooserParams: FileChooserParams?
): Boolean {
this.filePathCallback?.onReceiveValue(null)
this.filePathCallback = filePathCallback
val pickIntent = Intent(Intent.ACTION_GET_CONTENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "image/*"
}
val takePhotoIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
val chooserIntent = Intent(Intent.ACTION_CHOOSER).apply {
putExtra(Intent.EXTRA_INTENT, pickIntent)
putExtra(Intent.EXTRA_TITLE, "Select Photo or Camera")
putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf(takePhotoIntent))
}
activity.startActivityForResult(chooserIntent, FILE_CHOOSER_REQUEST_CODE)
return true
}
}
12. Media Upload & Camera Integration Summary
Media Upload Best Practices
- Wire WebChromeClient File Choosers: Standard HTML file inputs require native onShowFileChooser callbacks to function.
- Use Secure FileProvider: Transfer camera photos using content:// URIs to avoid FileUriExposedException on Android 7+.
- Compress Client-Side: Resize multi-megabyte camera photos using HTML5 canvas before uploading to prevent network timeouts.
- Adopt Android Photo Picker: Leverage modern scoped storage pickers to access photos without requesting invasive storage permissions.
13. WebChromeClient File Chooser & FileProvider Resolution Architecture
Connecting web file inputs to native Android media providers requires understanding the underlying URI resolution pipeline:
1. [HTML Form Interaction] ──> User taps <input type=”file” accept=”image/*”>
2. [Chromium Interception] ──> WebView invokes WebChromeClient.onShowFileChooser()
3. [Intent Aggregation] ──> Shell constructs Intent.ACTION_CHOOSER combining:
├──> Gallery Intent: Intent.ACTION_GET_CONTENT (Android Photo Picker)
└──> Camera Intent: MediaStore.ACTION_IMAGE_CAPTURE + FileProvider content:// URI
4. [User Capture/Selection] ──> User photographs scene or selects existing album photo
5. [Callback Resolution] ──> onActivityResult passes selected Uri[] to ValueCallback
6. [HTTP Upload Dispatch] ──> Web JavaScript receives standard File object for FormData upload
This architecture guarantees universal compatibility with camera sensors, Google Photos, Dropbox, and local device downloads without ever violating Android file security boundaries.
For applications handling high-resolution document scans, identity verification, or receipt submissions, combine native file capture with client-side canvas downsampling. Downsampling raw 24-megapixel camera files to 1920×1080 WebP images reduces transfer payloads by over 85%, ensuring rapid uploads even across congested 3G or public hotspot connections.
Always verify that your FileProvider XML configuration (res/xml/file_paths.xml) defines paths strictly scoped to your application’s private cache directory (<cache-path name="camera_photos" path="/" />). This prevents other applications from intercepting sensitive captured receipts or identity photos.
In addition, when handling multi-file uploads (<input type="file" multiple>), ensure your WebChromeClient inspects data.clipData in addition to data.data, allowing users to select and batch-upload up to 10 images simultaneously without resetting form state. Restricting MIME types using fileChooserParams.acceptTypes prevents users from accidentally attempting to upload unsupported binary formats.
Frequently Asked Questions
Why does my file upload button do nothing in standard WebViews?
By default, Android WebView does not handle file selection. You must implement WebChromeClient.onShowFileChooser() in the native host code to connect web inputs to Android’s native file picker.
Can users upload multiple images at once?
Yes! If your HTML input includes the ‘multiple’ attribute (e.g. <input type=’file’ multiple>), Android allows users to select multiple photos simultaneously.
Does FreeWebAPK support high-resolution photos?
Yes. Camera capture creates temporary FileProvider URIs that save photos at full camera resolution without downsampling.
What happens if a user denies the camera permission?
The app gracefully falls back to the native file picker, allowing the user to select an existing photo from their gallery instead.
Are uploads compatible with Amazon S3 and Cloudinary?
Yes! Direct JavaScript S3 multipart uploads, Cloudinary widgets, and standard multipart/form-data POST forms work seamlessly.
Can users capture photos directly from the camera inside the app?
Yes. Specifying ‘accept=”image/*” capture=”environment”‘ on your file input element prompts the Android container to launch the native camera app directly.
Does FreeWebAPK include file chooser support out of the box?
Yes! All APKs generated by FreeWebAPK contain fully wired WebChromeClient file choosers with support for photos, videos, PDFs, and general document uploads.
Can users upload PDF documents through the app?
Yes! Specifying ‘accept=”.pdf,application/pdf”‘ allows users to pick documents from Google Drive or local storage.
What happens if a user cancels the file picker without selecting an image?
The onShowFileChooser callback safely passes null, preventing the WebView from freezing or locking future input taps.
Can users upload multiple photos at once inside the app?
Yes! Adding the ‘multiple’ attribute to your HTML file input allows users to select and upload multiple images simultaneously.