我们做什么?
我们正在为iOS和Android平台构建一个React Native应用程序。该应用程序具有包含摄像机操作的外部网站,通过react-native-webview模块打开。从我们的实验中,我们观察到要使其工作,我们必须两次询问最终用户的摄像头权限:
- (一次) 当用户在设备上首次安装完应用程序并首次打开应用程序时
- (每次) 当React Native Webview组件被加载且getUserMedia方法在其中执行时。
这两个请求都向用户显示文本弹出窗口以允许访问相机:第一个是针对“application_name”,第二个是针对“url_inside_webview”- 图片方案
这对我们来说是一个关键问题,因为:
- 每次用户打开应用程序Webview组件(并且它正在执行)时,在Webview内部请求权限是不好的UX。
- 我们在提交应用程序发布到Apple Store期间遇到了拒绝。评论员的评论指向了这个时刻,“两次请求权限,每次Web组件加载”
复现问题的技术细节
操作系统:Apple iOS 15.1及更高版本
React Native依赖项:
"dependencies": {
"react": "17.0.2",
"react-native": "0.66.0",
"react-native-permissions": "^3.0.6",
"react-native-webview": "^11.14.0"
}
在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);
});
});
在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
更新 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>
启动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}
/>
我们的观察
- 在React Native WebView中,cacheMode属性无法解决明确请求权限的问题。
对于原生iOS应用程序,WKWebView的持久权限出现在iOS 15中:
- Swift的类似功能请求:https://bugs.webkit.org/show_bug.cgi?id=220416
- Apple更新演示了Swift的解决方案(在14:40):https://developer.apple.com/videos/play/wwdc2021/10032/
理想情况下,我们希望:
在React Native应用程序中,对于Webview内部的外部URL具有持久许可
将iOS应用程序级别的权限(例如相机)委托/复制到Webview
我们想知道是否有任何选项可以实现所需的行为? 一个应用程序仅仅请求一次权限是否从根本上可能?
mediaCapturePermissionGrantType={"grant"}
- Philipp Kiselev