How to access the camera from within a Webview?
Asked Answered
T

6

36

In my android app, I am trying to load a webpage (that must access the camera) on WebView. On my laptop, when I load the webpage, I could access the camera.

Everything else on the html page is shown.

Here are the permission I am putting in the Manifest.xml

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.webkit.PermissionRequest" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />

I am setting the SDK as follow:

<uses-sdk
    android:minSdkVersion="18"
    android:targetSdkVersion="21" />

Here is my webview setting:

private void setMyWebviewSettings(WebSettings MyWebviewSettings) {
    MyWebviewSettings.setAllowFileAccessFromFileURLs(true);
    MyWebviewSettings.setAllowUniversalAccessFromFileURLs(true);
    MyWebviewSettings.setJavaScriptCanOpenWindowsAutomatically(true);
    MyWebviewSettings.setJavaScriptEnabled(true);
    MyWebviewSettings.setDomStorageEnabled(true);
    MyWebviewSettings.setJavaScriptCanOpenWindowsAutomatically(true);
    MyWebviewSettings.setBuiltInZoomControls(true);
    MyWebviewSettings.setAllowFileAccess(true);
    MyWebviewSettings.setSupportZoom(true);
}

If I could access the camera from my app directly (using a normal activity), why can't I open it from within the WebView?!

Tanning answered 17/11, 2016 at 15:45 Comment(1)
when you try to open camera from webview then you need to do setting webview.Please see this #29291440Ursala
C
32

I was trying same thing. Below code worked to me.

First in manifest file we have to add camera hardware permission true using uses permission tag.

Then need to accept camera permission to use using below lines in your activity.

webview.setWebChromeClient(new WebChromeClient() {

   @Override
   public void onPermissionRequest(final PermissionRequest request) {
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
         request.grant(request.getResources());
      }
   }

 });
Chrysoprase answered 28/11, 2017 at 7:7 Comment(1)
This answer has the following issue if the Native app does not have the required rights to provide to the user then the webview throws java.lang.SecurityException: validateClientPermissionsLocked:1392: silently and all subsequent requests to getUserMedia just freeze.Hotchpotch
S
18

This is certainly possible with getUserMedia through WebRTC.

Set up your WebView to allow permission and load your HTML with loadUrl():

    WebView myWebView = (WebView) findViewById(R.id.webview);

    myWebView.getSettings().setJavaScriptEnabled(true);
    myWebView.getSettings().setAllowFileAccessFromFileURLs(true);
    myWebView.getSettings().setAllowUniversalAccessFromFileURLs(true);

    myWebView.setWebViewClient(new WebViewClient());
    myWebView.setWebChromeClient(new WebChromeClient() {
        // Grant permissions for cam
        @Override
        public void onPermissionRequest(final PermissionRequest request) {
            Log.d(TAG, "onPermissionRequest");
            MainActivity.this.runOnUiThread(new Runnable() {
                @TargetApi(Build.VERSION_CODES.M)
                @Override
                public void run() {
                    Log.d(TAG, request.getOrigin().toString());
                    if(request.getOrigin().toString().equals("file:///")) {
                        Log.d(TAG, "GRANTED");
                        request.grant(request.getResources());
                    } else {
                        Log.d(TAG, "DENIED");
                        request.deny();
                    }
                }
            });
        }


    });

    myWebView.loadUrl(LOCAL_FILE);

Then use getUserMedia through your JS file, assuming you have a <video> tag in your HTML file:

var constraints = { video: { width: 800, height: 800 } };

navigator.mediaDevices.getUserMedia(constraints)
.then(function(mediaStream) {
  var video = document.querySelector('video');
  video.srcObject = mediaStream;
  video.onloadedmetadata = function(e) {
    video.play();
  };
})
.catch(function(err) { console.log(err.name + ": " + err.message); }); // always check for errors at the end.

Lastly, ensure you have permissions set in your manifest:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
Sheave answered 6/6, 2017 at 19:26 Comment(1)
Can you help me with this issue? #63696205Dup
S
7

Here is what worked for me. I hope it helps someone.

public class MainActivity extends AppCompatActivity implements 
EasyPermissions.PermissionCallbacks{

WebView myWebView;

private String TAG = "TEST";
private PermissionRequest mPermissionRequest;

private static final int REQUEST_CAMERA_PERMISSION = 1;
private static final String[] PERM_CAMERA =
        {Manifest.permission.CAMERA};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    myWebView  = new WebView(this);

    myWebView.getSettings().setJavaScriptEnabled(true);
    myWebView.getSettings().setAllowFileAccessFromFileURLs(true);
    myWebView.getSettings().setAllowUniversalAccessFromFileURLs(true);

    //myWebView.setWebViewClient(new WebViewClient());
    myWebView.setWebChromeClient(new WebChromeClient() {
        // Grant permissions for cam
        @Override
        public void onPermissionRequest(final PermissionRequest request) {
            Log.i(TAG, "onPermissionRequest");
            mPermissionRequest = request;
            final String[] requestedResources = request.getResources();
            for (String r : requestedResources) {
                if (r.equals(PermissionRequest.RESOURCE_VIDEO_CAPTURE)) {
                    // In this sample, we only accept video capture request.
                    AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(MainActivity.this)
                                                        .setTitle("Allow Permission to camera")
                                                        .setPositiveButton("Allow", new DialogInterface.OnClickListener() {
                                                            @Override
                                                            public void onClick(DialogInterface dialog, int which) {
                                                                dialog.dismiss();
                                                                mPermissionRequest.grant(new String[]{PermissionRequest.RESOURCE_VIDEO_CAPTURE});
                                                                Log.d(TAG,"Granted");
                                                            }
                                                        })
                                                        .setNegativeButton("Deny", new DialogInterface.OnClickListener() {
                                                            @Override
                                                            public void onClick(DialogInterface dialog, int which) {
                                                                dialog.dismiss();
                                                                mPermissionRequest.deny();
                                                                Log.d(TAG,"Denied");
                                                            }
                                                        });
                    AlertDialog alertDialog = alertDialogBuilder.create();
                    alertDialog.show();

                    break;
                }
            }
        }

        @Override
        public void onPermissionRequestCanceled(PermissionRequest request) {
            super.onPermissionRequestCanceled(request);
            Toast.makeText(MainActivity.this,"Permission Denied",Toast.LENGTH_SHORT).show();
        }
    });


    if(hasCameraPermission()){
        myWebView.loadUrl("Your URL");
        setContentView(myWebView );
    }else{
        EasyPermissions.requestPermissions(
                this,
                "This app needs access to your camera so you can take pictures.",
                REQUEST_CAMERA_PERMISSION,
                PERM_CAMERA);
    }

}





private boolean hasCameraPermission() {
    return EasyPermissions.hasPermissions(MainActivity.this, PERM_CAMERA);
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}

@Override
public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {

}

@Override
public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {

}
}

I am using easypermission library for camera permission and remember to add uses-permission for camera in Android Manifest

Spangler answered 21/3, 2018 at 10:17 Comment(1)
Can you help me with this issue? #63696205Dup
T
3

If I'm not wrong, you simply want to open your device camera and upload newly captured photo in webview without opening other application then you need WRITE_EXTERNAL_STORAGE permission also and methods to handle file requests and create new files with camera and write it to your device storage.

I hope this helps, Open Source (Android Smart WebView) lets setup things for you.

You need to look for openFileChooser() and onShowFileChooser() methods to understand how to handle file requests from webview input and activate your phone camera to capture and create new image without opening other apps.

Thurgau answered 11/2, 2017 at 10:18 Comment(0)
O
3

Up on meuser07's answer, here is what worked for me. Other than permission in the Manifest.xml, You need to check/grant on run time as well.

I hope it helps.

            override fun onPermissionRequest(request: PermissionRequest) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    if (ContextCompat.checkSelfPermission(this@YourActivity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                                                RxPermissions(this@YourActivity).request(Manifest.permission.CAMERA).subscribe({
                            if (it) request.grant(request.resources)
                        }, {
                            Timber.e(it, "Error requesting camera")
                        }).addSubscription()
                    } else {
                        request.grant(request.resources)
                    }
                }
            }

I am using RxPermission to grant the permissions. Also, you need to add this configuration.

webView.settings.mediaPlaybackRequiresUserGesture = false
Okeefe answered 13/1, 2020 at 4:48 Comment(1)
Can you help me with this issue? #63696205Dup
R
1
  1. Add the necessary permissions to your app's AndroidManifest.xml file. Inside the tag, add the following line:
    <uses-permission android:name="android.permission.CAMERA" />
  1. Check for camera permission before loading the URL in your WebView. Use the ContextCompat.checkSelfPermission method.

In activity:

if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
    // Permission is not granted, so request it
    ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA), REQUEST_CAMERA_PERMISSION)
} else {
    // Permission is already granted, load the URL in WebView
    webView.loadUrl(yourUrl)
}

In fragment:

if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
    // Permission is not granted, so request it
    ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.CAMERA), REQUEST_CAMERA_PERMISSION)
} else {
    // Permission is already granted, load the URL in WebView
    webView.loadUrl(yourUrl)
}

Where REQUEST_CAMERA_PERMISSION can be:

    private val REQUEST_CAMERA_PERMISSION = 123
  1. Override the onRequestPermissionsResult method in your activity or fragment to handle the permission request result.
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
    if (requestCode == REQUEST_CAMERA_PERMISSION) {
        if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // Permission granted, load the URL in WebView
            webView.loadUrl(yourUrl)
        } else {
            // Permission denied, handle accordingly (e.g., show an error message)
            // You may want to disable camera-related features if permission is denied
        }
    }
}

If you do not want to ask permission before, only if the loaded url leads to a page that request permission maybe try this:

  1. Load the url without first requesting permission for camera:
    webView.loadUrl(yourUrl)
  1. onPermissionRequest will look like this:
            override fun onPermissionRequest(request: PermissionRequest?) {
                if (request?.resources?.contains("android.permission.CAMERA") == true || request?.resources?.contains("android.webkit.resource.VIDEO_CAPTURE") == true) {
                    if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                        // Permission is not granted, so request it
                        ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.CAMERA), REQUEST_CAMERA_PERMISSION)
                    } else {
                        request.grant(request.resources)
                    }
                } else {
                    super.onPermissionRequest(request)
                }
            }

All the other steps remain the same...

Rriocard answered 3/7, 2023 at 16:33 Comment(1)
Please suggest how we can access camera with permission handling from WebView in AndroidView with Jetpack Compose.Shavonda

© 2022 - 2024 — McMap. All rights reserved.