React Native Webview (camera, getUserMedia) double request of permissions on iOS 15

3.8k views Asked by At

What we do?

We are building a React Native application for both iOS and Android platforms. The application has an external website with camera manipulations inside, opened via react-native-webview module. From our experiments we observed that to make it work we have to ask end-user the camera permissions twice:

  1. (Once) when user firstly open the application after installation on his/her device
  2. (Every time) when React Native webview component is loaded and the getUserMedia method is executing inside it.

Both requests show to the user popups with text to allow camera access: the first for “application_name” and the second is for “url_inside_webview” - picture scheme

It is a critical issue for us because:

  1. Asking permissions (inside webview) every time user opens the app webview component (and it’s executing) is a bad UX.
  2. We faced a rejection on application release to Apple Store during Apple review. The comment of reviewer pointed to exactly this moment about “asking permissions twice and every time the web component loads”

Technical details to reproduce the issue

OS: Apple iOS 15.1 and newer

React Native Dependencies:

"dependencies": {
  "react": "17.0.2",
  "react-native": "0.66.0",
  "react-native-permissions": "^3.0.6",
  "react-native-webview": "^11.14.0"
}

Setup permissions in react-native:

import { request, PERMISSIONS, RESULTS } from 'react-native-permissions';
// ... //
request(PERMISSIONS.IOS.CAMERA)
    .then((statuses) => {
        if (statuses[PERMISSIONS.IOS.CAMERA] === RESULTS.GRANTED) {
            setWebviewRenderAvailable(true);
        });
    });

Configuring in ios/Podfile:

target 'MyAwesomeProject' do
  # Check permissions for camera

  permissions_path = '../node_modules/react-native-permissions/ios'
  pod 'RNPermissions', :path => '../node_modules/react-native-permissions'
  pod 'Permission-Camera', :path => "#{permissions_path}/Camera"
  pod 'Permission-PhotoLibrary', :path => "#{permissions_path}/PhotoLibrary"

end

Update Info.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>

  <!-- ... -->
  <key>NSCameraUsageDescription</key>
  <string>Camera Access</string>
  <!-- ... -->

</dict>
</plist>

Start webview:

import { WebView } from 'react-native-webview';
// ... //
<WebView
    scalesPageToFit={true}
    startInLoadingState
    useWebKit
    originWhitelist={['*']}
    allowsInlineMediaPlayback
    mediaPlaybackRequiresUserAction={false}
    source={{ uri: '<access link>' }}
    style={{marginTop: 1, width: widthWebview, height: heightWebview }}
    ref={webView}
    javaScriptEnabled={true}
    cacheEnabled={true}
    onMessage={onMessage}
    onLoadEnd={onLoaded}
  />

Our observations

  • cacheMode props (in React Native WebView) doesn't help with explicit permission request issue.

For native iOS application the persistent permissions for WKWebView appeared in iOS 15:

Ideally, we would like to:

  1. have a persistent permissions for external URL inside of webview for React Native application

  2. delegate / copy permissions (to camera) from iOS application level to webview

We would like to know if there any options to achieve the desired behaviour? Is it even fundamentally possible for an app to ask permission only once?

1

There are 1 answers

1
Zeeshan Ali On BEST ANSWER

Step 1: Upgrade the lib version to [email protected]

Step 2: Add the below prop

mediaCapturePermissionGrantType="grantIfSameHostElsePrompt"

This allows iOS to remember the permission decisions and get rid of the initial double-prompt by inheriting the grant from the native layer.

Reference: Github Release