2

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.

Coder
  • 31
  • 1
  • 1
  • 3

5 Answers5

4

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.

Tartar
  • 5,149
  • 16
  • 63
  • 104
1

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.

Green Y.
  • 445
  • 1
  • 8
  • 19
1

For Android 10, SDK 30

Add android:requestLegacyExternalStorage="true" in application tag in manifest

https://stackoverflow.com/a/65415381/7775500

this might help you ..

Shah0651
  • 307
  • 3
  • 8
1

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

Mahdi Noori
  • 11
  • 1
  • 6
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/late-answers/31119312) – Abhishek Dutt Feb 25 '22 at 05:41
0

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

Cicker
  • 19
  • 11