处理网站权限¶
当网站想要访问用户设备上的某些服务时,它会发送权限请求。本文档将解释如何使用 GeckoView 接收这些请求,并通过授予或拒绝这些权限来响应它们。
权限委托¶
应用程序通过 PermissionDelegate 与 GeckoView 中的网站权限进行交互。 PermissionDelegate
处理三种主要类型的权限:Android 权限、内容权限和媒体权限。GeckoView 处理的所有网站权限都属于这三类之一。
要接收有关权限请求的通知,您需要实现 PermissionDelegate
接口
private class ExamplePermissionDelegate implements GeckoSession.PermissionDelegate {
@Override
public void onAndroidPermissionsRequest(final GeckoSession session,
final String[] permissions,
final Callback callback) { }
@Override
public void onContentPermissionRequest(final GeckoSession session,
final String uri,
final int type, final Callback callback) { }
@Override
public void onMediaPermissionRequest(final GeckoSession session,
final String uri,
final MediaSource[] video,
final MediaSource[] audio,
final MediaCallback callback) { }
}
然后,您需要将委托注册到您的 GeckoSession 实例。
public class GeckoViewActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
final ExamplePermissionDelegate permission = new ExamplePermissionDelegate();
session.setPermissionDelegate(permission);
...
}
}
Android 权限¶
当网站想要访问设备的导航或输入功能时,会请求 Android 权限。
用户通常需要向应用程序授予这些 Android 权限,以及授予内容或媒体网站权限。
当您收到 onAndroidPermissionsRequest 调用时,您还将收到发送请求的 GeckoSession
、包含正在请求的权限的数组以及用于响应请求的 Callback。然后,应用程序需要从设备请求这些权限,这可以使用 requestPermissions 完成。
可能的 permissions
值为:ACCESS_COARSE_LOCATION、ACCESS_FINE_LOCATION、CAMERA 或 RECORD_AUDIO。
private class ExamplePermissionDelegate implements GeckoSession.PermissionDelegate {
private Callback mCallback;
public void onRequestPermissionsResult(final String[] permissions,
final int[] grantResults) {
if (mCallback == null) { return; }
final Callback cb = mCallback;
mCallback = null;
for (final int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
// At least one permission was not granted.
cb.reject();
return;
}
}
cb.grant();
}
@Override
public void onAndroidPermissionsRequest(final GeckoSession session,
final String[] permissions,
final Callback callback) {
mCallback = callback;
requestPermissions(permissions, androidPermissionRequestCode);
}
}
public class GeckoViewActivity extends AppCompatActivity {
@Override
public void onRequestPermissionsResult(final int requestCode,
final String[] permissions,
final int[] grantResults) {
if (requestCode == REQUEST_PERMISSIONS ||
requestCode == REQUEST_WRITE_EXTERNAL_STORAGE) {
final ExamplePermissionDelegate permission = (ExamplePermissionDelegate)
getCurrentSession().getPermissionDelegate();
permission.onRequestPermissionsResult(permissions, grantResults);
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
内容权限¶
当网站想要访问设备上存储的内容时,会请求内容权限。可以通过 GeckoView 请求的内容权限包括:地理位置、网站通知、持久存储、XR、静音自动播放、有声自动播放 和 DRM 媒体访问。此外,跟踪保护例外 被视为一种内容权限。
当您收到 onContentPermissionRequest 调用时,您还将收到发送请求的 GeckoSession
,以及存储在 ContentPermission 中的有关正在请求的权限的所有相关信息。然后,应用程序需要向用户展示 UI 以请求权限,并通过返回的 GeckoResult
通知 GeckoView 响应。
以这种方式设置权限后,GeckoView 会在会话之间持久化它,直到它被清除或修改。加载页面时,与其关联的活动权限(已允许和已拒绝)将在 onLocationChange 中作为 ContentPermission
对象列表报告;此外,可以通过调用 getAllPermissions 检查所有存储的内容权限,并通过调用 getPermissions 检查与给定 URI 关联的内容权限。要修改现有权限,您需要关联的 ContentPermission
(可以从上述任何方法中检索);然后,使用所需的新的值调用 setPermission,或者如果希望取消设置权限并让网站将来再次请求它,则调用 VALUE_PROMPT。
媒体权限¶
当网站想要访问设备的摄像头和麦克风以播放或录制媒体时,会请求媒体权限。
当您收到 onMediaPermissionRequest 调用时,您还将收到发送请求的 GeckoSession
、请求权限的网站的 URI(作为字符串)、可用的视频设备列表(如果请求视频)、可用的音频设备列表(如果请求音频)以及用于响应请求的 MediaCallback。
应用程序需要向用户展示 UI 以请求权限,并通过 MediaCallback
通知 GeckoView 响应。
请注意,如果关联的设备权限已被拒绝,但该类别中仍可以访问的视频或音频源存在,则仍会请求媒体权限。消费者有责任确保在这种情况下不显示媒体权限请求。
private class ExamplePermissionDelegate implements GeckoSession.PermissionDelegate {
@Override
public void onMediaPermissionRequest(final GeckoSession session,
final String uri,
final MediaSource[] video,
final MediaSource[] audio,
final MediaCallback callback) {
// Reject permission if Android permission has been previously denied.
if ((audio != null
&& ContextCompat.checkSelfPermission(GeckoViewActivity.this,
Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED)
|| (video != null
&& ContextCompat.checkSelfPermission(GeckoViewActivity.this,
Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)) {
callback.reject();
return;
}
final String host = Uri.parse(uri).getAuthority();
final String title;
if (audio == null) {
title = getString(R.string.request_video, host);
} else if (video == null) {
title = getString(R.string.request_audio, host);
} else {
title = getString(R.string.request_media, host);
}
// Get the media device name from the `MediaDevice`
String[] videoNames = normalizeMediaName(video);
String[] audioNames = normalizeMediaName(audio);
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
// Create drop down boxes to allow users to select which device to grant permission to
final LinearLayout container = addStandardLayout(builder, title, null);
final Spinner videoSpinner;
if (video != null) {
videoSpinner = addMediaSpinner(builder.getContext(), container, video, videoNames); // create spinner and add to alert UI
} else {
videoSpinner = null;
}
final Spinner audioSpinner;
if (audio != null) {
audioSpinner = addMediaSpinner(builder.getContext(), container, audio, audioNames); // create spinner and add to alert UI
} else {
audioSpinner = null;
}
builder.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int which) {
// gather selected media devices and grant access
final MediaSource video = (videoSpinner != null)
? (MediaSource) videoSpinner.getSelectedItem() : null;
final MediaSource audio = (audioSpinner != null)
? (MediaSource) audioSpinner.getSelectedItem() : null;
callback.grant(video, audio);
}
});
final AlertDialog dialog = builder.create();
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(final DialogInterface dialog) {
callback.reject();
}
});
dialog.show();
}
}
要查看 PermissionsDelegate
的实际应用,您可以在 GeckoView 示例应用程序 中找到完整的示例实现。