Skip to content

Commit b9d86ef

Browse files
committed
fix(android): honor permission handler for geolocation
подтверждено
1 parent 47afa95 commit b9d86ef

4 files changed

Lines changed: 89 additions & 9 deletions

File tree

src/android/binding.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,14 @@ macro_rules! android_binding {
9595
[JString, jni::objects::JObjectArray],
9696
jint
9797
);
98+
android_fn!(
99+
$domain,
100+
$package,
101+
RustWebChromeClient,
102+
onGeolocationPermissionRequestNative,
103+
[JString, JString],
104+
jint
105+
);
98106
}};
99107
}
100108

@@ -545,3 +553,27 @@ pub unsafe fn onPermissionRequestNative(
545553
2 // Default
546554
}
547555
}
556+
557+
#[allow(non_snake_case)]
558+
pub unsafe fn onGeolocationPermissionRequestNative(
559+
mut env: JNIEnv,
560+
_: JClass,
561+
webview_id: JString,
562+
_origin: JString,
563+
) -> jint {
564+
let Ok(webview_id) = env.get_string(&webview_id) else {
565+
return 2;
566+
};
567+
let webview_id = webview_id.to_str().ok().unwrap_or_default();
568+
let permission_handlers = PERMISSION_HANDLER.lock().unwrap();
569+
let Some(handler) = permission_handlers.get(webview_id) else {
570+
return 2;
571+
};
572+
573+
match (handler.handler)(PermissionKind::Geolocation) {
574+
PermissionResponse::Allow => 0,
575+
PermissionResponse::Deny => 1,
576+
PermissionResponse::Default => 2,
577+
PermissionResponse::Prompt => 3,
578+
}
579+
}

src/android/kotlin/RustWebChromeClient.kt

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,15 @@ class RustWebChromeClient(appActivity: WryActivity) : WebChromeClient() {
9292
}
9393

9494
override fun onPermissionRequest(request: PermissionRequest) {
95+
val requestedResources = safePermissionRequestResources(request.resources)
9596
val response = onPermissionRequestNative(activity.currentWebViewId(), request.resources)
9697
when (response) {
9798
0 -> { // Allow
98-
request.grant(request.resources)
99+
if (requestedResources.isNotEmpty()) {
100+
request.grant(requestedResources)
101+
} else {
102+
request.deny()
103+
}
99104
return
100105
}
101106
1 -> { // Deny
@@ -112,31 +117,34 @@ class RustWebChromeClient(appActivity: WryActivity) : WebChromeClient() {
112117

113118
val isRequestPermissionRequired = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
114119
val permissionList: MutableList<String> = ArrayList()
115-
if (listOf(*request.resources).contains("android.webkit.resource.VIDEO_CAPTURE")) {
120+
if (requestedResources.contains(PermissionRequest.RESOURCE_VIDEO_CAPTURE)) {
116121
permissionList.add(Manifest.permission.CAMERA)
117122
}
118-
if (listOf(*request.resources).contains("android.webkit.resource.AUDIO_CAPTURE")) {
123+
if (requestedResources.contains(PermissionRequest.RESOURCE_AUDIO_CAPTURE)) {
119124
permissionList.add(Manifest.permission.MODIFY_AUDIO_SETTINGS)
120125
permissionList.add(Manifest.permission.RECORD_AUDIO)
121126
}
122-
if (permissionList.isNotEmpty() && isRequestPermissionRequired) {
127+
if (requestedResources.isEmpty()) {
128+
request.deny()
129+
} else if (permissionList.isNotEmpty() && isRequestPermissionRequired) {
123130
val permissions = permissionList.toTypedArray()
124131
permissionListener = object : PermissionListener {
125132
override fun onPermissionSelect(isGranted: Boolean?) {
126133
if (isGranted == true) {
127-
request.grant(request.resources)
134+
request.grant(requestedResources)
128135
} else {
129136
request.deny()
130137
}
131138
}
132139
}
133140
permissionLauncher.launch(permissions)
134141
} else {
135-
request.grant(request.resources)
142+
request.grant(requestedResources)
136143
}
137144
}
138145

139146
private external fun onPermissionRequestNative(webviewId: String, resources: Array<String>): Int
147+
private external fun onGeolocationPermissionRequestNative(webviewId: String, origin: String): Int
140148

141149
/**
142150
* Show the browser alert modal
@@ -260,9 +268,20 @@ class RustWebChromeClient(appActivity: WryActivity) : WebChromeClient() {
260268
callback: GeolocationPermissions.Callback
261269
) {
262270
super.onGeolocationPermissionsShowPrompt(origin, callback)
271+
when (onGeolocationPermissionRequestNative(activity.currentWebViewId(), origin)) {
272+
1 -> {
273+
callback.invoke(origin, false, false)
274+
return
275+
}
276+
}
277+
263278
Logger.debug("onGeolocationPermissionsShowPrompt: DOING IT HERE FOR ORIGIN: $origin")
264-
val geoPermissions =
265-
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION)
279+
val geoPermissions = definedGeolocationPermissions()
280+
if (geoPermissions.isEmpty()) {
281+
callback.invoke(origin, false, false)
282+
return
283+
}
284+
266285
if (!PermissionHelper.hasPermissions(activity, geoPermissions)) {
267286
permissionListener = object : PermissionListener {
268287
override fun onPermissionSelect(isGranted: Boolean?) {
@@ -289,6 +308,26 @@ class RustWebChromeClient(appActivity: WryActivity) : WebChromeClient() {
289308
}
290309
}
291310

311+
private fun safePermissionRequestResources(resources: Array<String>): Array<String> {
312+
return resources.filter {
313+
it == PermissionRequest.RESOURCE_AUDIO_CAPTURE ||
314+
it == PermissionRequest.RESOURCE_VIDEO_CAPTURE ||
315+
it == PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID ||
316+
it == PermissionRequest.RESOURCE_MIDI_SYSEX
317+
}.toTypedArray()
318+
}
319+
320+
private fun definedGeolocationPermissions(): Array<String> {
321+
val permissions = ArrayList<String>()
322+
if (PermissionHelper.hasDefinedPermission(activity, Manifest.permission.ACCESS_COARSE_LOCATION)) {
323+
permissions.add(Manifest.permission.ACCESS_COARSE_LOCATION)
324+
}
325+
if (PermissionHelper.hasDefinedPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION)) {
326+
permissions.add(Manifest.permission.ACCESS_FINE_LOCATION)
327+
}
328+
return permissions.toTypedArray()
329+
}
330+
292331
override fun onShowFileChooser(
293332
webView: WebView,
294333
filePathCallback: ValueCallback<Array<Uri?>?>,

src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,9 @@ struct WebViewAttributes<'a> {
808808
/// - **Windows**: Fully supported via WebView2's PermissionRequested event.
809809
/// - **macOS / iOS**: Fully supported via WKUIDelegate's requestMediaCapturePermission.
810810
/// - **Linux**: Fully supported via WebKitGTK's permission-request signal.
811-
/// - **Android**: Supported via JNI bridge with some limitations (WIP).
811+
/// - **Android**: Supported via JNI bridge for geolocation, microphone, camera,
812+
/// protected media, and MIDI requests. Android runtime permissions may still
813+
/// trigger native OS prompts before access is granted.
812814
///
813815
/// ## Example
814816
///

src/permissions.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ pub enum PermissionKind {
99
/// Camera access permission.
1010
Camera,
1111
/// Geolocation access permission.
12+
///
13+
/// ## Platform-specific
14+
///
15+
/// - **Windows**: Supported via `COREWEBVIEW2_PERMISSION_KIND_GEOLOCATION`.
16+
/// - **Linux**: Supported via `GeolocationPermissionRequest`.
17+
/// - **Android**: Supported via `WebChromeClient.onGeolocationPermissionsShowPrompt`.
18+
/// - **macOS / iOS**: Not yet supported by platform backends.
1219
Geolocation,
1320
/// Notifications permission.
1421
///

0 commit comments

Comments
 (0)