Android File Chooser not calling from Android Webview - android

Its a simple WebApp with a Webview in it and there is a registration page with upload file option. trying to open file chooser when click on browse button but there is not response. i assume that there is some issue in my gradle files. please help me debug it. Here is my Code.
here is my project gradle
buildscript {
repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
classpath 'com.google.gms:google-services:3.2.1'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
and here is my app gradle
android {
compileSdkVersion 27
defaultConfig {
applicationId "com.androidapp.myApp"
minSdkVersion 15
targetSdkVersion 27
versionCode 2
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
useLibrary 'org.apache.http.legacy'
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:support-v4:27.1.1'
implementation 'com.google.firebase:firebase-invites:16.0.1'
implementation 'com.google.firebase:firebase-messaging:17.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.squareup.okhttp3:okhttp:3.8.0'
implementation 'com.android.support:multidex:1.0.3'
}
apply plugin: 'com.google.gms.google-services'

It is not the gradle file error. You just need to provide custom WebChromeClient like below.
class MyWebChromeClient extends WebChromeClient {
// For 3.0+ Devices (Start)
// onActivityResult attached before constructor
protected void openFileChooser(ValueCallback uploadMsg, String acceptType) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
}
// For Lollipop 5.0+ Devices
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public boolean onShowFileChooser(WebView mWebView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
if (uploadMessage != null) {
uploadMessage.onReceiveValue(null);
uploadMessage = null;
}
uploadMessage = filePathCallback;
Intent intent = fileChooserParams.createIntent();
try {
startActivityForResult(intent, REQUEST_SELECT_FILE);
} catch (ActivityNotFoundException e) {
uploadMessage = null;
Toast.makeText(WebLink.this, "Cannot Open File Chooser", Toast.LENGTH_LONG).show();
return false;
}
return true;
}
//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("image/*");
startActivityForResult(Intent.createChooser(intent, "File Chooser"), 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("image/*");
startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
}
}
and it in your webview like below
webview.setWebChromeClient(new MyWebChromeClient());
some other useful stuff/variables to be declared globally.
public ValueCallback<Uri[]> uploadMessage;
private ValueCallback<Uri> mUploadMessage;
public static final int REQUEST_SELECT_FILE = 100;
private final static int FILECHOOSER_RESULTCODE = 1;
make sure you have all the read/write permissions
UPDATE
Use below lines to provide access to files from storage.
webview.getSettings().setDomStorageEnabled(true);
webview.getSettings().setAllowContentAccess(true);
webview.getSettings().setAllowFileAccess(true);
// EDIT, add this line also
webview.getSettings().setJavaScriptEnabled(true);
UPDATE 2
Get the result in onActivityResult method. You can use the result given like below.
#Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (requestCode == REQUEST_SELECT_FILE) {
if (uploadMessage == null)
return;
uploadMessage.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, intent));
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 = intent == null || resultCode != WebLink.RESULT_OK ? null : intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
} else
Toast.makeText(WebLink.this, "Failed to Upload Image", Toast.LENGTH_LONG).show();
}

This Kotlin code worked for all versions:
webView.settings.javaScriptEnabled = true
webView.settings.loadWithOverviewMode = true
webView.settings.useWideViewPort = true
webView.settings.domStorageEnabled = true
webView.settings.allowFileAccess=true
webView.settings.allowContentAccess=true
webView.settings.allowUniversalAccessFromFileURLs=true
webView.settings.allowFileAccessFromFileURLs=true
webView.settings.javaScriptCanOpenWindowsAutomatically=true
webView.loadUrl(Constants.URL)
webView.webChromeClient = object : WebChromeClient() {
override fun onShowFileChooser(
webView: WebView,
filePathCallback: ValueCallback<Array<Uri>>,
fileChooserParams: FileChooserParams
): Boolean {
if (mUMA != null) {
mUMA!!.onReceiveValue(null)
}
mUMA = filePathCallback
var takePictureIntent: Intent? = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
if (takePictureIntent!!.resolveActivity(this#MainActivity.getPackageManager()) != null) {
var photoFile: File? = null
try {
photoFile = createImageFile()
takePictureIntent.putExtra("PhotoPath", mCM)
} catch (ex: IOException) {
Log.e("Webview", "Image file creation failed", ex)
}
if (photoFile != null) {
mCM = "file:" + photoFile.getAbsolutePath()
takePictureIntent.putExtra(
MediaStore.EXTRA_OUTPUT,
Uri.fromFile(photoFile)
)
} else {
takePictureIntent = null
}
}
val contentSelectionIntent = Intent(Intent.ACTION_GET_CONTENT)
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE)
contentSelectionIntent.type = "*/*"
val intentArray: Array<Intent>
intentArray = takePictureIntent?.let { arrayOf(it) } ?: arrayOf<Intent>()
val chooserIntent = Intent(Intent.ACTION_CHOOSER)
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent)
chooserIntent.putExtra(Intent.EXTRA_TITLE, "Image Chooser")
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray)
startActivityForResult(chooserIntent, FCR)
return true
}
}
// Create an image file
#Throws(IOException::class)
private fun createImageFile(): File? {
#SuppressLint("SimpleDateFormat") val timeStamp: String =
SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
val imageFileName = "img_" + timeStamp + "_"
val storageDir: File =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
return File.createTempFile(imageFileName, ".jpg", storageDir)
}
fun openFileChooser(uploadMsg: ValueCallback<Uri?>?) {
this.openFileChooser(uploadMsg, "*/*")
}
fun openFileChooser(
uploadMsg: ValueCallback<Uri?>?,
acceptType: String?
) {
this.openFileChooser(uploadMsg, acceptType, null)
}
fun openFileChooser(
uploadMsg: ValueCallback<Uri?>?,
acceptType: String?,
capture: String?
) {
val i = Intent(Intent.ACTION_GET_CONTENT)
i.addCategory(Intent.CATEGORY_OPENABLE)
i.type = "*/*"
this#MainActivity.startActivityForResult(
Intent.createChooser(i, "File Browser"),
FILECHOOSER_RESULTCODE
)
}
override fun onActivityResult(
requestCode: Int,
resultCode: Int,
intent: Intent?
) {
super.onActivityResult(requestCode, resultCode, intent)
if (Build.VERSION.SDK_INT >= 21) {
var results: Array<Uri>? = 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 = arrayOf(Uri.parse(mCM))
}
} else {
val dataString = intent.dataString
if (dataString != null) {
results = arrayOf(Uri.parse(dataString))
}
}
}
}
mUMA!!.onReceiveValue(results)
mUMA = null
} else {
if (requestCode == FCR) {
if (null == mUM) return
val result =
if (intent == null || resultCode != Activity.RESULT_OK) null else intent.data
mUM!!.onReceiveValue(result)
mUM = null
}
}
}
/*needed fileds
private var mCM: String? = null
private var mUM: ValueCallback<Uri>? = null
private var mUMA: ValueCallback<Array<Uri>>? = null
private const val FCR = 1*/

It got so easy in 2022-23 with Kotlin.
class MainActivity : AppCompatActivity() {
private var fileChooserResultLauncher = createFileChooserResultLauncher()
private var fileChooserValueCallback: ValueCallback<Array<Uri>>? = null
webView.webChromeClient = object : WebChromeClient() {
override fun onShowFileChooser(webView: WebView?, filePathCallback: ValueCallback<Array<Uri>>?, fileChooserParams: FileChooserParams?): Boolean {
try {
fileChooserValueCallback = filePathCallback;
fileChooserResultLauncher.launch(fileChooserParams?.createIntent())
} catch (e: ActivityNotFoundException) {
// You may handle "No activity found to handle intent" error
}
return true
}
}
private fun createFileChooserResultLauncher(): ActivityResultLauncher<Intent> {
return registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_OK) {
fileChooserValueCallback?.onReceiveValue(arrayOf(Uri.parse(it?.data?.dataString)));
} else {
fileChooserValueCallback?.onReceiveValue(null)
}
}
}
}

Related

How to take photo or select gallery files in android webview

I have a component in angular with the functionality to take picture or select file
The file upload works fine, the problem is that it does not let me take photos, I already tried to adapt the code in various ways but it does not work.
How could I make that adjustment so that both options work, how could I identify which option was selected (take photo, select file)?
Angular code
Html
<input
#inputFile
accept="image/*,application/pdf"
type="file"
(change)="loadFile($event)"
style="display: none;"
onclick="this.value = null"
/>
<input
#cameraFile
accept="image/*"
capture="camera"
type="file"
(change)="loadFile($event)"
style="display: none;"
onclick="this.value = null"
/>
Ts
selectOption(opcion: any) {
if (opcion.tipoArchivo === this.documentType.documento.idDocumento) {
switch (opcion.opcion) {
case MenuBottomSheet.ELEGIR_FOTO:
this.fileChooser.nativeElement.click();
break;
case MenuBottomSheet.TOMAR_FOTO:
this.cameraFile.nativeElement.click();
break;
}
}
}
Código android
web_view?.webChromeClient = object: WebChromeClient() {
override fun onShowFileChooser(webView: WebView?, filePathCallback: ValueCallback<Array<Uri>>?,
fileChooserParams: FileChooserParams): Boolean {
Log.d("onShowFileChooser ======> ", "")
super.onShowFileChooser(webView, filePathCallback, fileChooserParams)
if (uploadMessage != null) {
uploadMessage?.onReceiveValue(null)
uploadMessage = null
}
uploadMessage = filePathCallback
val intent: Intent = fileChooserParams.createIntent()
try {
startActivityForResult(intent, REQUEST_SELECT_FILE)
} catch (e: ActivityNotFoundException) {
uploadMessage = null
return false
}
return true
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK && (requestCode == REQUEST_SELECT_FILE || requestCode == REQUEST_IMAGE_CAPTURE)) {
if (uploadMessage == null) {
return
}
uploadMessage?.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(resultCode, data))
uploadMessage = null
}
}
I put here the code that worked for me
override fun onShowFileChooser(webView: WebView?, filePathCallback: ValueCallback<Array<Uri>>?, fileChooserParams: FileChooserParams): Boolean {
super.onShowFileChooser(webView, filePathCallback, fileChooserParams)
if (uploadMessage != null) {
uploadMessage?.onReceiveValue(null)
uploadMessage = null
}
uploadMessage = filePathCallback
if (fileChooserParams.isCaptureEnabled()) {
takingPhoto = true
var permissions = ArrayList<String>()
if(!existCameraPermission()) {
permissions.add(Manifest.permission.CAMERA);
}
if(!existMemoryWritePermission()) {
permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if(!permissions.isEmpty()) {
requestPermissions(permissions.toTypedArray(), 1);
} else {
takePhoto()
}
} else {
takingPhoto = false
val intent: Intent = fileChooserParams.createIntent()
try {
startActivityForResult(intent, REQUEST_SELECT_FILE)
} catch (e: ActivityNotFoundException) {
uploadMessage = null
return false
}
}
return true
}
fun takePhoto() {
var takePictureIntent: Intent? = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
if (takePictureIntent?.resolveActivity(packageManager) != null) {
var photoFile: File? = null
try {
photoFile = createImageFile()
} catch (ex: IOException) {
Log.d("ocurrio un error ================> ", ex.toString())
}
if (photoFile != null) {
photoFileTmp = photoFile
val uri = FileProvider.getUriForFile(activity, fileProvider, photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
}
startActivityForResult(takePictureIntent, REQUEST_SELECT_FILE)
}
}

Why I am not able to open camera from webview in android?

I am having problem that I am not able to open camera from webview in that I am having php page so I have to open gallery and camera from there but I am not able to do what I got from this link "https://gist.github.com/jhonsore/8a8378c147ec00ac6f3fa53569c82ef8".
I can open gallery but not camera please give me any solution.
A working example in Kotlin for Android 7+
Add camera permissions
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.CAMERA2" />
Configure your WebView
private fun configureWebViewSettings() {
binding.webView.settings.javaScriptEnabled = true
binding.webView.settings.domStorageEnabled = true
binding.webView.settings.setSupportZoom(false)
binding.webView.settings.allowFileAccess = true
binding.webView.settings.allowContentAccess = true
binding.webView.webChromeClient = getCustomWebChromeClient()
}
Add the lines below to your Activity
private var imagePathCallback: ValueCallback<Array<Uri>>? = null
private var cameraImagePath: String? = null
Implement a WebChromeClient and add it to your WebView
private fun getCustomWebChromeClient() = object : WebChromeClient() {
override fun onShowFileChooser(
view: WebView?,
filePath: ValueCallback<Array<Uri>>?,
fileChooserParams: FileChooserParams?
): Boolean {
if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
requestPermissions(arrayOf(Manifest.permission.CAMERA), CAMERA_REQUEST_CODE)
imagePathCallback?.onReceiveValue(null)
imagePathCallback = null
imagePathCallback = filePath
val takePictureIntent = createImageCaptureIntent()
val contentSelectionIntent = Intent(Intent.ACTION_GET_CONTENT)
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE)
contentSelectionIntent.type = INTENT_FILE_TYPE
val intentArray: Array<Intent?>
intentArray = takePictureIntent?.let { arrayOf(it) } ?: arrayOfNulls(0)
val chooserIntent = Intent(Intent.ACTION_CHOOSER)
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent)
chooserIntent.putExtra(Intent.EXTRA_TITLE, getString(R.string.file_chooser_title))
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray)
try {
startActivityForResult(chooserIntent, REQUEST_SELECT_FILE)
} catch (e: ActivityNotFoundException) {
imagePathCallback = null
cameraImagePath = null
Toast.makeText(
this#MainActivity,
getString(R.string.cannot_open_file_chooser_txt),
Toast.LENGTH_LONG
).show()
return false
}
return true
}
private fun createImageCaptureIntent(): Intent? {
var captureImageIntent: Intent? = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
if (captureImageIntent?.resolveActivity(packageManager) != null) {
var imageFile: File? = null
try {
imageFile = createImageFile()
captureImageIntent.putExtra("CameraImagePath", cameraImagePath)
} catch (ex: IOException) {
ex.printStackTrace()
}
if (imageFile != null) {
cameraImagePath = CAMERA_PHOTO_PATH_POSTFIX + imageFile.absolutePath
captureImageIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(imageFile))
} else {
captureImageIntent = null
}
}
return captureImageIntent
}
private fun createImageFile(): File? {
val timeStamp = SimpleDateFormat.getDateInstance().format(Date())
val imageFileName = PHOTO_NAME_POSTFIX + timeStamp + "_"
val storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
return File.createTempFile(imageFileName, PHOTO_FORMAT, storageDir)
}
Implement onRequestPermissionsResult in your Activity
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == CAMERA_REQUEST_CODE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(
this,
getString(R.string.amera_permission_granted_txt),
Toast.LENGTH_LONG
).show()
} else {
Toast.makeText(
this,
getString(R.string.camera_permission_denied_txt),
Toast.LENGTH_LONG
).show()
}
}
}
Implement onActivityResult in your Activity
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode != REQUEST_SELECT_FILE || imagePathCallback == null) return
var results: Array<Uri>? = null
if (resultCode == RESULT_OK) {
if (data == null) {
if (cameraImagePath != null) results = arrayOf(Uri.parse(cameraImagePath))
} else {
val dataString = data.dataString
if (dataString != null) results = arrayOf(Uri.parse(dataString))
}
}
imagePathCallback?.onReceiveValue(results)
imagePathCallback = null
}
Constants
companion object {
private const val CAMERA_REQUEST_CODE = 113
private const val REQUEST_SELECT_FILE = 13
private const val INTENT_FILE_TYPE = "image/*"
private const val CAMERA_PHOTO_PATH_POSTFIX = "file:"
private const val PHOTO_NAME_POSTFIX = "JPEG_"
private const val PHOTO_FORMAT = ".jpg"
}
Try and see, it should work.
Did you grant Camera permission into your WebView's WebChromeClient?
Please add camera permission into your AndroidManifest.xml.
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.CAMERA2" />
Set WebChromeClient into your WebView.
webView.setWebChromeClient(new ChromeClient())
Define the your ChromeClient class.
public class ChromeClient extends WebChromeClient {
#Override
public boolean onShowFileChooser(WebView view, ValueCallback<Uri[]> filePath, WebChromeClient.FileChooserParams fileChooserParams) {
if (!hasPermissions(MainActivity.this, PERMISSIONS)) {
checkStoragePermission();
return false;
}
// Double check that we don't have any existing callbacks
if (mFilePathCallback != null) {
mFilePathCallback.onReceiveValue(null);
}
mFilePathCallback = filePath;
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = createImageFile();
takePictureIntent.putExtra("PhotoPath", mCameraPhotoPath);
// 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 contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
contentSelectionIntent.setType("image/*");
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, "Select Photo");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
startActivityForResult(chooserIntent, Constant.INPUT_FILE_REQUEST_CODE);
return true;
}
}
Here are variables.
String[] PERMISSIONS = {
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
private ValueCallback<Uri[]> mFilePathCallback;
private String mCameraPhotoPath;
Check the storage and camera permission.
private void checkStoragePermission() {
String permission = Manifest.permission.WRITE_EXTERNAL_STORAGE;
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{permission}, Constant.REQUEST_STORAGE_PERMISSION);
} else {
checkCameraPermission();
}
}
private void checkCameraPermission() {
String permission = Manifest.permission.CAMERA;
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{permission}, Constant.REQUEST_CAMERA_PERMISSION);
} else {
onPermissionGranted();
}
}
After that, I can access to camera and gallery.
Hope it to be helpful.
For Android 10, SDK 30
Add android:requestLegacyExternalStorage="true" in application tag in manifest
https://stackoverflow.com/a/65415381/7775500
this might help you ..
Surely you need the permissions to open the camera on android.
Edit the manifest like this:
<uses-permission android:name="android.permission.CAMERA" />
You might also need a library not included
I also had this problem too. I will share it with others who are likely to have this problem in the future.
You must have the camera permission in the manifest and grant it in the onPermissionRequest methode in your WebChromeClient and be sure to set setMediaPlaybackRequiresUserGesture to false in the webView setting.
Add this permission:
<uses-permission android:name="android.permission.CAMERA" />
Add this in webView setting:
binding.webView.getSettings().setMediaPlaybackRequiresUserGesture(false);
And grant the permission in onPermissionRequest methode:
#Override
public void onPermissionRequest(final PermissionRequest request) {
final String[] requestedResources = request.getResources();
request.grant(requestedResources);
}
for more information see this link:
StackOverFlow solution

Xamarin Android Web-view File Chooser

I wrote a hybrid app and I want to use file upload HTML (file and camera) page. I use the below code and it works well.
When the user clicks on FileUploader input, the native window opens (to choose between File or Camera) and everything works just fine.
My only problem is that, when user click out of the window, this one will be closed and after no more opened, maybe something to reinitialise or restart.
If someone has some ideas...
On MainActivity:
var chrome = new SmarterWebChromeClient((uploadMsg) =>
{
mUploadMessage = uploadMsg;
mCameraPhotoPath = null;
Intent takePictureIntent = new Intent(Android.Provider.MediaStore.ActionImageCapture);
//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
writeEx(ex.ToString());
}
// Continue only if the File was successfully created
if (photoFile != null)
{
mCameraPhotoPath = "file:" + photoFile.AbsolutePath;
takePictureIntent.PutExtra(Android.Provider.MediaStore.ExtraOutput,
Android.Net.Uri.FromFile(photoFile));
}
else
{
takePictureIntent = null;
}
Intent contentSelectionIntent = new Intent(Intent.ActionGetContent);
contentSelectionIntent.AddCategory(Intent.CategoryOpenable);
contentSelectionIntent.SetType("image/*");
Intent[] intentArray;
if (takePictureIntent != null)
{
intentArray = new Intent[] { takePictureIntent };
}
else
{
intentArray = new Intent[0];
}
Intent chooserIntent = new Intent(Intent.ActionChooser);
chooserIntent.PutExtra(Intent.ExtraIntent, contentSelectionIntent);
chooserIntent.PutExtra(Intent.ExtraTitle, "Choisir une photo");
chooserIntent.PutExtra(Intent.ExtraInitialIntents, intentArray);
StartActivityForResult(chooserIntent, MainActivity.FILECHOOSER_RESULTCODE);
});
mWebView.SetWebViewClient(new MyWebViewClient());
mWebView.SetWebChromeClient(chrome);
...
protected override void OnActivityResult(int requestCode, Result resultCode, Intent intent)
{
if (requestCode == FILECHOOSER_RESULTCODE)
{
if (null == mUploadMessage)
return;
// Check that the response is a good one
if (resultCode == Result.Ok)
{
Android.Net.Uri[] results = null;
if (intent == null)
{
// If there is not data, then we may have taken a photo
if (mCameraPhotoPath != null)
{
results = new Android.Net.Uri[] { Android.Net.Uri.Parse(mCameraPhotoPath) };
}
else
{
}
}
else
{
if (intent.DataString != null)
{
results = new Android.Net.Uri[] { Android.Net.Uri.Parse(intent.DataString) };
}
}
mUploadMessage.OnReceiveValue(results);
mUploadMessage = null;
}
}
}
And my WebChromeClient Class :
partial class SmarterWebChromeClient : WebChromeClient
{
Action<IValueCallback> callback;
public SmarterWebChromeClient(Action<IValueCallback> callback)
{
this.callback = callback;
}
public override bool OnShowFileChooser(WebView webView, IValueCallback filePathCallback, FileChooserParams fileChooserParams)
{
callback(filePathCallback);
return true;
}
}
I solve your problem like below code
Put an else part for result NOT OK
// Check that the response is a good one
if (resultCode == Result.Ok)
{
//...
}
else
{
mUploadMessage.OnReceiveValue(null);
mUploadMessage = null;
}

When I use from setWebChromeClient I can't use from onPageStarted webView - Android

I am using from below code for upload file in webView :
#SuppressLint("SetJavaScriptEnabled")
private void loadWebView(String url) {
if (getActivity() != null) {
if (Build.VERSION.SDK_INT >= 23 && (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)) {
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, 1);
}
WebSettings webSettings = webViewRequest.getSettings();
webSettings.setLoadsImagesAutomatically(true);
webSettings.setJavaScriptEnabled(true);
webViewRequest.clearHistory();
webViewRequest.setHorizontalScrollBarEnabled(false);
webViewRequest.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
webSettings.setAllowFileAccess(true);
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
webSettings.setSupportMultipleWindows(true);
webViewRequest.loadUrl(url);
if (Build.VERSION.SDK_INT >= 21) {
webSettings.setMixedContentMode(0);
webViewRequest.setLayerType(View.LAYER_TYPE_HARDWARE, null);
} else if (Build.VERSION.SDK_INT >= 19) {
webViewRequest.setLayerType(View.LAYER_TYPE_HARDWARE, null);
} else if (Build.VERSION.SDK_INT < 19) {
webViewRequest.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
webViewRequest.setWebViewClient(new Callback());
webViewRequest.setWebChromeClient(new WebChromeClient() {
#Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
if (newProgress == 100) {
if (progressRequestWebView.getVisibility() == View.VISIBLE) {
progressRequestWebView.setVisibility(View.GONE);
}
}
}
//For Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUM = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
WebViewRequestFragment.this.startActivityForResult(Intent.createChooser(i, "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 i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
WebViewRequestFragment.this.startActivityForResult(
Intent.createChooser(i, "File Browser"),
FCR);
}
//For Android 4.1+
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
mUM = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("*/*");
WebViewRequestFragment.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), WebViewRequestFragment.FCR);
}
//For Android 5.0+
#Override
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(getActivity().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, "Image Chooser");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
startActivityForResult(chooserIntent, FCR);
return true;
}
});
}
}
#Override
public 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 != Activity.RESULT_OK ? null : intent.getData();
mUM.onReceiveValue(result);
mUM = null;
}
}
}
public class Callback extends WebViewClient {
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
Toast.makeText(getActivity(), "Failed loading app!", Toast.LENGTH_SHORT).show();
}
}
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);
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
And I need to use below code, when user touch on any link on webView but don't work :
webViewRequest.setWebViewClient(new WebViewClient() {
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
if (url.contains("GetAttachment")) {
cookies = CookieManager.getInstance().getCookie(url);
urlDown = url;
if (checkPermission()) {
startDownload(urlDown, cookies);
} else {
requestPermission();
}
}
}
});
I delete bellow lines and good work now :
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
webSettings.setSupportMultipleWindows(true);

onShowFileChooser() from android webview works only once

I need to pick images from the device and upload it to the server. For the first time, when I pick the images, onShowFileChooser() gets called and everything works. But, when I try to click upload again, onShowFileChooser() never gets called. But it's working for non-lollypop devices. openFileChoser() gets called, whenever I click upload. Is there anything that I'm missing. Here is my 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 of the activity:
#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;
}
}
firstly, sorry to my english. you should return empty Uri[]{} to file receive
mUploadMessageForAndroid5.onReceiveValue(new Uri[]{});
my code can choose take photo or local image:
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();
}
}
}
}
Faced similar problem i was returning boolean value in method onShowFileChooser, issue was fixed when i called super class method
#Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
//Logic to implement
return super.onShowFileChooser(webView, filePathCallback, fileChooserParams);
}
In the onShowFileChooser() method you should return true, only if you are using the filePathCallback, which is the best way:
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});
}
}
I had the similar issue that onShowFileChooser only works once. After few hours of trail and error and then I figured out using a simple experiment:
Not invoking ValueCallback will result onShowFileChooser only works once. Below code only works once...
override fun onShowFileChooser(
view: WebView?,
filePath: ValueCallback<Array<Uri>>?,
fileChooserParams: FileChooserParams?
): Boolean {
Log.i("blah", "<== onShowFileChooser ==>")
// filePath?.onReceiveValue(null)
return true
}
Properly invoking ValueCallback will make onShowFileChooser work every time:
override fun onShowFileChooser(
view: WebView?,
filePath: ValueCallback<Array<Uri>>?,
fileChooserParams: FileChooserParams?
): Boolean {
Log.i("blah", "<== onShowFileChooser ==>")
filePath?.onReceiveValue(null)
return true
}
so I just check all branches and make sure all properly invoking ValueCallback then the webview works as expected.
I had the same issue, the problem was I was expecting an OnActivityResult, but when you press the back button, this was not triggered.
The solution was implementing on onResume the following code, to tell the callback the answer was empty and being able to reuse it:
#Override
protected void onResume() {
super.onResume();
if (mFilePathCallbackArray == null)
return;
mFilePathCallbackArray.onReceiveValue(new Uri[]{});
mFilePathCallbackArray = null;
}
Just set a null value:
if (resultCode == Activity.RESULT_OK) {
handleImageRequest(data)
} else {
mValueCallbackArray?.onReceiveValue(null)
mValueCallbackArray = null
}
I had exactly same issue, But my use case is little different but my webview was loaded on a fragment as is in your code. first time the file chooser displayed fine on both Lollipop & pre Lollipop devices, but next time onwards it failed to display file chooser it self. The Reason being the I was not handled the onActivityResult in proper way at first time. My working code snippet is as follows for 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;
}
Just let onShowFIleChooser() return false, will work next time
public boolean onShowFileChooser(){
...
return **false**;
}
This is working for me (Kotlin, Jetpack compose)->
override fun onShowFileChooser(
webView: WebView?,
filePathCb: ValueCallback<Array<Uri>>?,
fileChooserParams: FileChooserParams?,
): Boolean {
if (filePathCallback != null) {
filePathCallback!!.onReceiveValue(null)
}
filePathCallback = filePathCb
return true
}
In future I can upload or reject the file upload->
if(onCloseCameraClick){
filePathCallback?.onReceiveValue(null)
filePathCallback = null
showMediaPicker = false
}
else{
filePathCallback?.onReceiveValue(arrayOf(uri))
filePathCallback = null
showMediaPicker = false
}

Categories

Resources