Skip to content

Granting device camera access to my websiteΒ #336

@Hassanmir92

Description

@Hassanmir92

Hi πŸ‘‹

I'm having some issues trying to access Camera capabilities in my Android App. I am building an app where one of the functionalities is to use the camera, display it on the page and scan QR codes using html5-qrcode library. This functionality works fine on the Chrome. However, not as an Android app on an Android device.

I believe I am successfully requesting and granting access to my application for the usage of CAMERA, however, I think my external website which is loaded into the TurboWebView also somehow needs access which it is not getting or even requesting.

To help build a picture, here is some of my code:

Here are the permissions and features specified inside AndroidManifest

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.ACTION_IMAGE_CAPTURE" />

    <uses-feature android:name="android.hardware.camera"/>
    <uses-feature android:name="android.hardware.camera2"/>
    <uses-feature android:name="android.hardware.camera.any"/>
    <uses-feature android:name="android.hardware.camera.autofocus"/>

MainActivity

class MainActivity : AppCompatActivity(), TurboActivity {
    override lateinit var delegate: TurboActivityDelegate
    private val CAMERA_PERMISSION_REQUEST_CODE = 1

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.main_activity)

        delegate = TurboActivityDelegate(this, R.id.main_nav_host)

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            this.requestPermissions(arrayOf(Manifest.permission.CAMERA), CAMERA_PERMISSION_REQUEST_CODE)
        }
    }

    // For Debugging purposes, this is always returning "Permission granted" in the logs
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)

        if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
            println("DEBUG -> MainActivity Camera Request: Permission granted")
        } else {
            println("DEBUG -> MainActivity Camera Request: Permission denied")
        }
        return
    }
}

As you can see from my override above, I have implemented onRequestPermissionsResult where I am consistently getting "Camera Request: Permission granted" which means my application definitely has access.

My onSessionCreated() within my MainSessionNavHostFragment (from following demo examples)

    override fun onSessionCreated() {
        super.onSessionCreated()

        val activity = session.webView.context as MainActivity

        // Configure WebView
        session.webView.settings.mediaPlaybackRequiresUserGesture = false;
        session.webView.settings.javaScriptEnabled = true;
        session.webView.settings.domStorageEnabled = true;
        session.webView.settings.allowFileAccess = true;
        session.webView.webChromeClient = NewWebChromeClient(session);
        session.webView.addJavascriptInterface(WebAppInterface(activity), "AndroidApp");
    }

As you can see from the above example, I tried to set my own NewWebChromeClient and additionally a javascript interface which you can see below:

The webapp interface also allows me to simply call AndroidApp.requestCameraPermission() directly from my stimulus JS controller which works, but again it doesn't actually give permission for my actual website to access the camera.

class WebAppInterface(private val mContext: Context) {
    private val CAMERA_PERMISSION_REQUEST_CODE = 1

    @JavascriptInterface
    fun requestCameraPermission() {
        println("DEBUG -> checking permission in Interface")

        val activity = mContext as MainActivity;
        activity.requestPermissions(arrayOf(Manifest.permission.CAMERA), CAMERA_PERMISSION_REQUEST_CODE)
    }
}

Here is also my custom WebChromeClient which based on putting some logging in there, never actually runs.

class NewWebChromeClient(session: TurboSession) : TurboWebChromeClient(session) {
    override fun onPermissionRequest(request: PermissionRequest) {
        println("DEBUG -> checking permission is being granted in ChromeClient");
        request.grant(arrayOf(PermissionRequest.RESOURCE_VIDEO_CAPTURE));
    }
}

Through testing in developer mode using a real device, I can confirm I definitely get the prompt for giving camera permission. Through my debug logs, everything indicates that permission to the app has been granted. However, these lines of logs sadly disagree 😒 :

CameraManagerGlobal  - Connecting to camera service
CameraManagerGlobal  - Camera 0 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client com.sec.android.app.camera API Level 2
CameraManagerGlobal  - Camera 1 facing CAMERA_FACING_FRONT state now CAMERA_STATE_CLOSED for client vendor.client.pid<1235> API Level 2
...
chromium - Uncaught (in promise) Error getting userMedia, error = NotAllowedError: Permission denied

The last line of log comes from where my library is triggering the JS getUserMedia() function.

I may be just missing something obvious here or I'm being delusional in thinking this is supposed to be straight forward πŸ˜‚. I really appreciate any guidance or help πŸ™

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions