Closed Nodalailama closed 2 years ago
I think this solution won't work out of the box, on newer Android versions you would need to request the location permission. And the UI for that is going to differ per-app. Here's roughly what we did to make it work without any custom UI.
// WebFragment.kt
class WebFragment : TurboWebFragment() {
var permissionsCallback: ((Boolean, Boolean) -> Unit)? = null
val locationPermissionRequest = fragment.registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
when {
permissions.getOrDefault(Manifest.permission.ACCESS_FINE_LOCATION, false) -> {
permissionsCallback?.let { it(true, true) }
}
permissions.getOrDefault(Manifest.permission.ACCESS_COARSE_LOCATION, false) -> {
permissionsCallback?.let { it(true, false) }
}
else -> {
permissionsCallback?.let { it(false, false) }
}
}
permissionsCallback = null
}
// ...
override fun createWebChromeClient(): GeolocationPermissionsTurboWebChromeClient {
return GeolocationPermissionsTurboWebChromeClient(this, session)
}
}
class GeolocationPermissionsTurboWebChromeClient(
private val fragment: WebFragment,
s: TurboSession
) : TurboWebChromeClient(s) {
override fun onGeolocationPermissionsShowPrompt(
origin: String?,
callback: GeolocationPermissions.Callback
) {
if (ContextCompat.checkSelfPermission(
App.sharedContext!!,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
callback.invoke(origin, true, true)
} else {
fragment.permissionsCallback = { allow: Boolean, retain: Boolean ->
callback.invoke(origin, allow, retain)
}
fragment.locationPermissionRequest.launch(
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
)
}
}
Hi,
Thank you for sharing.
@ghiculescu, may you would push a PR ?
Let's see what @jayohms thinks.
I'm not sure this is generic enough that it should be included in the library for everyone.
Okay. How are you extending it in your app without touching the library ?
Using the above code - it just subclasses the library code.
The TurboWebChromeClient
is left open
so it can be extended in any app-specific ways necessary. @ghiculescu's approach is the one you should take in your app. For example, in the Basecamp apps we override onJsAlert()
and onJsConfirm()
to display nicer Material dialogs:
WebViewChromeClient.kt
class WebViewChromeClient(session: TurboSession) : TurboWebChromeClient(session) {
override fun onJsAlert(view: WebView?, url: String?, message: String?, result: JsResult?): Boolean {
val context = view?.context ?: return false
MaterialAlertDialogBuilder(context)
.setMessage(message)
.setPositiveButton(context.getString(R.string.button_ok)) { dialog, _ ->
dialog.cancel()
result?.confirm()
}
.setCancelable(false)
.create()
.show()
return true
}
override fun onJsConfirm(view: WebView?, url: String?, message: String?, result: JsResult?): Boolean {
val context = view?.context ?: return false
MaterialAlertDialogBuilder(context)
.setMessage(message)
.setNegativeButton(context.getString(R.string.button_cancel)) { dialog, _ ->
dialog.cancel()
result?.cancel()
}
.setPositiveButton(context.getString(R.string.button_ok)) { dialog, _ ->
dialog.cancel()
result?.confirm()
}
.setCancelable(false)
.create()
.show()
return true
}
WebFragment.kt
class WebFragment : TurboWebFragment() {
// ...
override fun createWebChromeClient(): TurboWebChromeClient {
return WebViewChromeClient(session)
}
}
The Geolocation permission is too app-specific to be included in the library code and any WebChromeClient
features not implemented in the library can be added in your own custom TurboWebChromeClient
.
Further, this PR's approach is too simplistic and needs to prompt the user for the proper permission like @ghiculescu outlined.
@ghiculescu, @jayohms, thank you very much.
By adding this, developper can use the js native function to get the position of a user.
You will need to set the correct permission like _ _ and then request permissions ActivityCompat.requestPermissions
Voilà.