fix: initiate OAuth using Custom Tabs on Android, closes #361 (#788)

This commit is contained in:
Huang Xin 2025-04-01 23:04:17 +08:00 committed by GitHub
parent 7ccf3d0632
commit 6131180a31
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 161 additions and 46 deletions

View file

@ -33,9 +33,9 @@ android {
}
dependencies {
implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.appcompat:appcompat:1.6.0")
implementation("androidx.browser:browser:1.8.0")
implementation("com.google.android.material:material:1.7.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")

View file

@ -3,7 +3,4 @@ package com.readest.native_bridge
import android.util.Log
class NativeBridge {
fun auth_with_safari(value: String): String {
return ""
}
}

View file

@ -1,7 +1,10 @@
package com.readest.native_bridge
import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.util.Log
import androidx.browser.customtabs.CustomTabsIntent
import app.tauri.annotation.Command
import app.tauri.annotation.InvokeArg
import app.tauri.annotation.TauriPlugin
@ -11,7 +14,7 @@ import app.tauri.plugin.Invoke
import java.io.*
@InvokeArg
class SafariAuthRequestArgs {
class AuthRequestArgs {
var authUrl: String? = null
}
@ -24,14 +27,25 @@ class CopyURIRequestArgs {
@TauriPlugin
class NativeBridgePlugin(private val activity: Activity): Plugin(activity) {
private val implementation = NativeBridge()
private var redirectScheme = "readest"
private var redirectHost = "auth-callback"
companion object {
var pendingInvoke: Invoke? = null
}
@Command
fun auth_with_safari(invoke: Invoke) {
val args = invoke.parseArgs(SafariAuthRequestArgs::class.java)
fun auth_with_custom_tab(invoke: Invoke) {
val args = invoke.parseArgs(AuthRequestArgs::class.java)
val uri = Uri.parse(args.authUrl)
val ret = JSObject()
ret.put("redirectUrl", implementation.auth_with_safari(args.authUrl ?: ""))
invoke.resolve(ret)
val customTabsIntent = CustomTabsIntent.Builder().build()
customTabsIntent.intent.flags = Intent.FLAG_ACTIVITY_NO_HISTORY
Log.d("NativeBridgePlugin", "Launching OAuth URL: ${args.authUrl}")
customTabsIntent.launchUrl(activity, uri)
pendingInvoke = invoke
}
@Command

View file

@ -1,4 +1,8 @@
const COMMANDS: &[&str] = &["auth_with_safari", "copy_uri_to_path"];
const COMMANDS: &[&str] = &[
"auth_with_safari",
"auth_with_custom_tab",
"copy_uri_to_path",
];
fn main() {
tauri_plugin::Builder::new(COMMANDS)

View file

@ -0,0 +1,13 @@
# Automatically generated - DO NOT EDIT!
"$schema" = "../../schemas/schema.json"
[[permission]]
identifier = "allow-auth-with-custom-tab"
description = "Enables the auth_with_custom_tab command without any pre-configured scope."
commands.allow = ["auth_with_custom_tab"]
[[permission]]
identifier = "deny-auth-with-custom-tab"
description = "Denies the auth_with_custom_tab command without any pre-configured scope."
commands.deny = ["auth_with_custom_tab"]

View file

@ -3,6 +3,7 @@
Default permissions for the plugin
- `allow-auth-with-safari`
- `allow-auth-with-custom-tab`
- `allow-copy-uri-to-path`
## Permission Table
@ -14,6 +15,32 @@ Default permissions for the plugin
</tr>
<tr>
<td>
`native-bridge:allow-auth-with-custom-tab`
</td>
<td>
Enables the auth_with_custom_tab command without any pre-configured scope.
</td>
</tr>
<tr>
<td>
`native-bridge:deny-auth-with-custom-tab`
</td>
<td>
Denies the auth_with_custom_tab command without any pre-configured scope.
</td>
</tr>
<tr>
<td>

View file

@ -1,3 +1,3 @@
[default]
description = "Default permissions for the plugin"
permissions = ["allow-auth-with-safari", "allow-copy-uri-to-path"]
permissions = ["allow-auth-with-safari", "allow-auth-with-custom-tab", "allow-copy-uri-to-path"]

View file

@ -294,6 +294,16 @@
"PermissionKind": {
"type": "string",
"oneOf": [
{
"description": "Enables the auth_with_custom_tab command without any pre-configured scope.",
"type": "string",
"const": "allow-auth-with-custom-tab"
},
{
"description": "Denies the auth_with_custom_tab command without any pre-configured scope.",
"type": "string",
"const": "deny-auth-with-custom-tab"
},
{
"description": "Enables the auth_with_safari command without any pre-configured scope.",
"type": "string",

View file

@ -7,11 +7,19 @@ use crate::Result;
#[command]
pub(crate) async fn auth_with_safari<R: Runtime>(
app: AppHandle<R>,
payload: SafariAuthRequest,
) -> Result<SafariAuthResponse> {
payload: AuthRequest,
) -> Result<AuthResponse> {
app.native_bridge().auth_with_safari(payload)
}
#[command]
pub(crate) async fn auth_with_custom_tab<R: Runtime>(
app: AppHandle<R>,
payload: AuthRequest,
) -> Result<AuthResponse> {
app.native_bridge().auth_with_custom_tab(payload)
}
#[command]
pub(crate) async fn copy_uri_to_path<R: Runtime>(
app: AppHandle<R>,

View file

@ -14,10 +14,11 @@ pub fn init<R: Runtime, C: DeserializeOwned>(
pub struct NativeBridge<R: Runtime>(AppHandle<R>);
impl<R: Runtime> NativeBridge<R> {
pub fn auth_with_safari(
&self,
_payload: SafariAuthRequest,
) -> crate::Result<SafariAuthResponse> {
pub fn auth_with_safari(&self, _payload: AuthRequest) -> crate::Result<AuthResponse> {
Err(crate::Error::UnsupportedPlatformError)
}
pub fn auth_with_custom_tab(&self, _payload: AuthRequest) -> crate::Result<AuthResponse> {
Err(crate::Error::UnsupportedPlatformError)
}

View file

@ -38,6 +38,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
Builder::new("native-bridge")
.invoke_handler(tauri::generate_handler![
commands::auth_with_safari,
commands::auth_with_custom_tab,
commands::copy_uri_to_path,
])
.setup(|app, api| {

View file

@ -25,16 +25,21 @@ pub fn init<R: Runtime, C: DeserializeOwned>(
pub struct NativeBridge<R: Runtime>(PluginHandle<R>);
impl<R: Runtime> NativeBridge<R> {
pub fn auth_with_safari(
&self,
payload: SafariAuthRequest,
) -> crate::Result<SafariAuthResponse> {
pub fn auth_with_safari(&self, payload: AuthRequest) -> crate::Result<AuthResponse> {
self.0
.run_mobile_plugin("auth_with_safari", payload)
.map_err(Into::into)
}
}
impl<R: Runtime> NativeBridge<R> {
pub fn auth_with_custom_tab(&self, payload: AuthRequest) -> crate::Result<AuthResponse> {
self.0
.run_mobile_plugin("auth_with_custom_tab", payload)
.map_err(Into::into)
}
}
impl<R: Runtime> NativeBridge<R> {
pub fn copy_uri_to_path(&self, payload: CopyURIRequest) -> crate::Result<CopyURIResponse> {
self.0

View file

@ -2,13 +2,13 @@ use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SafariAuthRequest {
pub struct AuthRequest {
pub auth_url: String,
}
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SafariAuthResponse {
pub struct AuthResponse {
pub redirect_url: String,
}