refactor: rename plugin safari-auth to native-bridge (#749)

* fix: layout tweaks for mobile

* refactor: rename plugin safari-auth to native-bridge
This commit is contained in:
Huang Xin
2025-03-29 14:27:18 +08:00
committed by GitHub
parent f90177713a
commit a72c8f2391
46 changed files with 145 additions and 144 deletions
Generated
+12 -11
View File
@@ -26,11 +26,11 @@ dependencies = [
"tauri-plugin-haptics",
"tauri-plugin-http",
"tauri-plugin-log",
"tauri-plugin-native-bridge",
"tauri-plugin-oauth",
"tauri-plugin-opener",
"tauri-plugin-os",
"tauri-plugin-process",
"tauri-plugin-safari-auth",
"tauri-plugin-shell",
"tauri-plugin-sign-in-with-apple",
"tauri-plugin-single-instance",
@@ -5316,6 +5316,17 @@ dependencies = [
"time",
]
[[package]]
name = "tauri-plugin-native-bridge"
version = "0.1.0"
dependencies = [
"schemars",
"serde",
"tauri",
"tauri-plugin",
"thiserror 2.0.12",
]
[[package]]
name = "tauri-plugin-oauth"
version = "2.0.0"
@@ -5381,16 +5392,6 @@ dependencies = [
"tauri-plugin",
]
[[package]]
name = "tauri-plugin-safari-auth"
version = "0.1.0"
dependencies = [
"serde",
"tauri",
"tauri-plugin",
"thiserror 2.0.12",
]
[[package]]
name = "tauri-plugin-shell"
version = "2.2.0"
+1 -1
View File
@@ -46,7 +46,7 @@ tauri-plugin-opener = "2.2.2"
tauri-plugin-deep-link = "2"
tauri-plugin-sign-in-with-apple = "1.0.2"
tauri-plugin-haptics = "2.2.3"
tauri-plugin-safari-auth = { path = "./plugins/tauri-plugin-safari-auth" }
tauri-plugin-native-bridge = { path = "./plugins/tauri-plugin-native-bridge" }
[patch.crates-io]
tauri = { path = "../../../packages/tauri/crates/tauri" }
@@ -75,7 +75,7 @@
"haptics:allow-impact-feedback",
"haptics:allow-notification-feedback",
"haptics:allow-selection-feedback",
"safari-auth:default",
"native-bridge:default",
"deep-link:default"
]
}
@@ -0,0 +1,19 @@
[package]
name = "tauri-plugin-native-bridge"
version = "0.1.0"
authors = [ "You" ]
description = "a bridge between tauri app and native OS functionality"
edition = "2021"
rust-version = "1.77.2"
exclude = ["/examples", "/dist-js", "/guest-js", "/node_modules"]
links = "tauri-plugin-native-bridge"
[dependencies]
tauri = { version = "2.3.1" }
serde = "1.0"
thiserror = "2"
schemars = "0.8"
[build-dependencies]
tauri-plugin = { version = "2.0.4", features = ["build"] }
schemars = "0.8"
@@ -0,0 +1 @@
# Tauri Plugin native-bridge
@@ -4,7 +4,7 @@ plugins {
}
android {
namespace = "com.plugin.safari_auth"
namespace = "com.readest.native_bridge"
compileSdk = 34
defaultConfig {
@@ -1,4 +1,4 @@
package com.plugin.safari_auth
package com.readest.native_bridge
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -19,6 +19,6 @@ class ExampleInstrumentedTest {
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.plugin.safari_auth", appContext.packageName)
assertEquals("com.readest.native_bridge", appContext.packageName)
}
}
@@ -0,0 +1,9 @@
package com.readest.native_bridge
import android.util.Log
class NativeBridge {
fun auth_with_safari(value: String): String {
return ""
}
}
@@ -0,0 +1,28 @@
package com.readest.native_bridge
import android.app.Activity
import app.tauri.annotation.Command
import app.tauri.annotation.InvokeArg
import app.tauri.annotation.TauriPlugin
import app.tauri.plugin.JSObject
import app.tauri.plugin.Plugin
import app.tauri.plugin.Invoke
@InvokeArg
class SafariAuthRequestArgs {
var authUrl: String? = null
}
@TauriPlugin
class NativeBridgePlugin(private val activity: Activity): Plugin(activity) {
private val implementation = NativeBridge()
@Command
fun auth_with_safari(invoke: Invoke) {
val args = invoke.parseArgs(SafariAuthRequestArgs::class.java)
val ret = JSObject()
ret.put("redirectUrl", implementation.auth_with_safari(args.authUrl ?: ""))
invoke.resolve(ret)
}
}
@@ -0,0 +1,8 @@
const COMMANDS: &[&str] = &["auth_with_safari"];
fn main() {
tauri_plugin::Builder::new(COMMANDS)
.android_path("android")
.ios_path("ios")
.build();
}
@@ -4,7 +4,7 @@
import PackageDescription
let package = Package(
name: "tauri-plugin-safari-auth",
name: "tauri-plugin-native-bridge",
platforms: [
.macOS(.v10_13),
.iOS(.v13),
@@ -12,9 +12,9 @@ let package = Package(
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "tauri-plugin-safari-auth",
name: "tauri-plugin-native-bridge",
type: .static,
targets: ["tauri-plugin-safari-auth"]),
targets: ["tauri-plugin-native-bridge"]),
],
dependencies: [
.package(name: "Tauri", path: "../.tauri/tauri-api")
@@ -23,7 +23,7 @@ let package = Package(
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "tauri-plugin-safari-auth",
name: "tauri-plugin-native-bridge",
dependencies: [
.byName(name: "Tauri")
],
@@ -1,3 +1,3 @@
# Tauri Plugin safari-auth
# Tauri Plugin native-bridge
A description of this package.
@@ -4,19 +4,15 @@ import Tauri
import UIKit
import WebKit
class RequestArgs: Decodable {
class SafariAuthRequestArgs: Decodable {
let authUrl: String
}
struct Response: Encodable {
let redirectUrl: String
}
class SafariAuthPlugin: Plugin {
class NativeBridgePlugin: Plugin {
private var authSession: ASWebAuthenticationSession?
@objc public func auth_with_safari(_ invoke: Invoke) throws {
let args = try invoke.parseArgs(RequestArgs.self)
let args = try invoke.parseArgs(SafariAuthRequestArgs.self)
let authUrl = URL(string: args.authUrl)!
authSession = ASWebAuthenticationSession(url: authUrl, callbackURLScheme: "readest") {
@@ -46,14 +42,14 @@ class SafariAuthPlugin: Plugin {
}
}
@_cdecl("init_plugin_safari_auth")
@_cdecl("init_plugin_native_bridge")
func initPlugin() -> Plugin {
return SafariAuthPlugin()
return NativeBridgePlugin()
}
@available(iOS 13.0, *)
extension SafariAuthPlugin: ASWebAuthenticationPresentationContextProviding {
extension NativeBridgePlugin: ASWebAuthenticationPresentationContextProviding {
func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
return UIApplication.shared.windows.first ?? UIWindow()
}
}
}
@@ -0,0 +1,8 @@
import XCTest
@testable import NativeBridgePlugin
final class NativeBridgePluginTests: XCTestCase {
func testNativeBridge() throws {
let plugin = NativeBridgePlugin()
}
}
@@ -16,7 +16,7 @@ Default permissions for the plugin
<tr>
<td>
`safari-auth:allow-auth-with-safari`
`native-bridge:allow-auth-with-safari`
</td>
<td>
@@ -29,7 +29,7 @@ Enables the auth_with_safari command without any pre-configured scope.
<tr>
<td>
`safari-auth:deny-auth-with-safari`
`native-bridge:deny-auth-with-safari`
</td>
<td>
@@ -1,13 +1,13 @@
use tauri::{command, AppHandle, Runtime};
use crate::models::*;
use crate::NativeBridgeExt;
use crate::Result;
use crate::SafariAuthExt;
#[command]
pub(crate) async fn auth_with_safari<R: Runtime>(
app: AppHandle<R>,
payload: SafariAuthRequest,
) -> Result<SafariAuthResponse> {
app.safari_auth().auth_with_safari(payload)
app.native_bridge().auth_with_safari(payload)
}
@@ -6,14 +6,14 @@ use crate::models::*;
pub fn init<R: Runtime, C: DeserializeOwned>(
app: &AppHandle<R>,
_api: PluginApi<R, C>,
) -> crate::Result<SafariAuth<R>> {
Ok(SafariAuth(app.clone()))
) -> crate::Result<NativeBridge<R>> {
Ok(NativeBridge(app.clone()))
}
/// Access to the safari-auth APIs.
pub struct SafariAuth<R: Runtime>(AppHandle<R>);
/// Access to the native-bridge APIs.
pub struct NativeBridge<R: Runtime>(AppHandle<R>);
impl<R: Runtime> SafariAuth<R> {
impl<R: Runtime> NativeBridge<R> {
pub fn auth_with_safari(
&self,
_payload: SafariAuthRequest,
@@ -6,6 +6,8 @@ pub type Result<T> = std::result::Result<T, Error>;
pub enum Error {
#[error("Unsupported platform for this plugin")]
UnsupportedPlatformError,
#[error("Native bridge error: {0}")]
NativeBridgeError(String),
#[error(transparent)]
Io(#[from] std::io::Error),
#[cfg(mobile)]
@@ -13,35 +13,36 @@ mod mobile;
mod commands;
mod error;
mod models;
mod platform;
pub use error::{Error, Result};
#[cfg(desktop)]
use desktop::SafariAuth;
use desktop::NativeBridge;
#[cfg(mobile)]
use mobile::SafariAuth;
use mobile::NativeBridge;
/// Extensions to [`tauri::App`], [`tauri::AppHandle`] and [`tauri::Window`] to access the safari-auth APIs.
pub trait SafariAuthExt<R: Runtime> {
fn safari_auth(&self) -> &SafariAuth<R>;
/// Extensions to [`tauri::App`], [`tauri::AppHandle`] and [`tauri::Window`] to access the native-bridge APIs.
pub trait NativeBridgeExt<R: Runtime> {
fn native_bridge(&self) -> &NativeBridge<R>;
}
impl<R: Runtime, T: Manager<R>> crate::SafariAuthExt<R> for T {
fn safari_auth(&self) -> &SafariAuth<R> {
self.state::<SafariAuth<R>>().inner()
impl<R: Runtime, T: Manager<R>> crate::NativeBridgeExt<R> for T {
fn native_bridge(&self) -> &NativeBridge<R> {
self.state::<NativeBridge<R>>().inner()
}
}
/// Initializes the plugin.
pub fn init<R: Runtime>() -> TauriPlugin<R> {
Builder::new("safari-auth")
Builder::new("native-bridge")
.invoke_handler(tauri::generate_handler![commands::auth_with_safari])
.setup(|app, api| {
#[cfg(mobile)]
let safari_auth = mobile::init(app, api)?;
let native_bridge = mobile::init(app, api)?;
#[cfg(desktop)]
let safari_auth = desktop::init(app, api)?;
app.manage(safari_auth);
let native_bridge = desktop::init(app, api)?;
app.manage(native_bridge);
Ok(())
})
.build()
@@ -7,25 +7,24 @@ use tauri::{
use crate::models::*;
#[cfg(target_os = "ios")]
tauri::ios_plugin_binding!(init_plugin_safari_auth);
tauri::ios_plugin_binding!(init_plugin_native_bridge);
// initializes the Kotlin or Swift plugin classes
pub fn init<R: Runtime, C: DeserializeOwned>(
_app: &AppHandle<R>,
api: PluginApi<R, C>,
) -> crate::Result<SafariAuth<R>> {
) -> crate::Result<NativeBridge<R>> {
#[cfg(target_os = "android")]
let handle = api.register_android_plugin("com.bilingify.safari_auth", "ExamplePlugin")?;
let handle = api.register_android_plugin("com.readest.native_bridge", "NativeBridgePlugin")?;
#[cfg(target_os = "ios")]
let handle = api.register_ios_plugin(init_plugin_safari_auth)?;
Ok(SafariAuth(handle))
let handle = api.register_ios_plugin(init_plugin_native_bridge)?;
Ok(NativeBridge(handle))
}
/// Access to the safari-auth APIs.
pub struct SafariAuth<R: Runtime>(PluginHandle<R>);
/// Access to the native-bridge APIs.
pub struct NativeBridge<R: Runtime>(PluginHandle<R>);
impl<R: Runtime> SafariAuth<R> {
impl<R: Runtime> NativeBridge<R> {
pub fn auth_with_safari(
&self,
payload: SafariAuthRequest,
@@ -0,0 +1,2 @@
#[cfg(target_os = "macos")]
pub mod macos;
@@ -1,17 +0,0 @@
[package]
name = "tauri-plugin-safari-auth"
version = "0.1.0"
authors = [ "chrox" ]
description = "OAuth with ASWebAuthenticationSession on iOS"
edition = "2021"
rust-version = "1.77.2"
exclude = ["/examples", "/dist-js", "/guest-js", "/node_modules"]
links = "tauri-plugin-safari-auth"
[dependencies]
tauri = { version = "2.2.4" }
serde = "1.0"
thiserror = "2"
[build-dependencies]
tauri-plugin = { version = "2.0.3", features = ["build"] }
@@ -1 +0,0 @@
# Tauri Plugin safari-auth
@@ -1,10 +0,0 @@
package com.plugin.safari_auth
import android.util.Log
class Example {
fun pong(value: String): String {
Log.i("Pong", value)
return value
}
}
@@ -1,28 +0,0 @@
package com.plugin.safari_auth
import android.app.Activity
import app.tauri.annotation.Command
import app.tauri.annotation.InvokeArg
import app.tauri.annotation.TauriPlugin
import app.tauri.plugin.JSObject
import app.tauri.plugin.Plugin
import app.tauri.plugin.Invoke
@InvokeArg
class PingArgs {
var value: String? = null
}
@TauriPlugin
class ExamplePlugin(private val activity: Activity): Plugin(activity) {
private val implementation = Example()
@Command
fun ping(invoke: Invoke) {
val args = invoke.parseArgs(PingArgs::class.java)
val ret = JSObject()
ret.put("value", implementation.pong(args.value ?: "default value :("))
invoke.resolve(ret)
}
}
@@ -1,8 +0,0 @@
const COMMANDS: &[&str] = &["auth_with_safari"];
fn main() {
tauri_plugin::Builder::new(COMMANDS)
.android_path("android")
.ios_path("ios")
.build();
}
@@ -1,8 +0,0 @@
import XCTest
@testable import SafariAuthPlugin
final class SafariAuthPluginTests: XCTestCase {
func testExample() throws {
let plugin = SafariAuthPlugin()
}
}
+2 -3
View File
@@ -46,6 +46,7 @@ fn allow_file_in_scopes(app: &AppHandle, files: Vec<PathBuf>) {
}
}
#[cfg(desktop)]
fn get_files_from_argv(argv: Vec<String>) -> Vec<PathBuf> {
let mut files = Vec::new();
// NOTICE: `args` may include URL protocol (`your-app-protocol://`)
@@ -143,6 +144,7 @@ pub fn run() {
.plugin(tauri_plugin_http::init())
.plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_native_bridge::init())
.plugin(tauri_plugin_fs::init());
#[cfg(desktop)]
@@ -173,9 +175,6 @@ pub fn run() {
#[cfg(target_os = "ios")]
let builder = builder.plugin(tauri_plugin_sign_in_with_apple::init());
#[cfg(target_os = "ios")]
let builder = builder.plugin(tauri_plugin_safari_auth::init());
#[cfg(any(target_os = "ios", target_os = "android"))]
let builder = builder.plugin(tauri_plugin_haptics::init());
-1
View File
@@ -312,7 +312,6 @@ export default function AuthPage() {
ref={headerRef}
className={clsx(
'fixed flex w-full items-center justify-between py-2 pe-6 ps-4',
appService?.hasSafeAreaInset && 'mt-[env(safe-area-inset-top)]',
appService?.hasTrafficLight && 'pt-11',
)}
>
@@ -9,7 +9,7 @@ export interface SafariAuthResponse {
}
export async function authWithSafari(request: SafariAuthRequest): Promise<SafariAuthResponse> {
const result = await invoke<SafariAuthResponse>('plugin:safari-auth|auth_with_safari', {
const result = await invoke<SafariAuthResponse>('plugin:native-bridge|auth_with_safari', {
payload: request,
});
@@ -68,7 +68,7 @@ const LibraryHeader: React.FC<LibraryHeaderProps> = ({
<div
ref={headerRef}
className={clsx(
'titlebar z-10 flex h-[52px] w-full items-center py-2 pr-4 sm:pr-6',
'titlebar z-10 flex h-[52px] w-full items-center py-2 pr-4 sm:h-[48px] sm:pr-6',
appService?.hasSafeAreaInset && 'mt-[env(safe-area-inset-top)]',
isTrafficLightVisible ? 'pl-16' : 'pl-0 sm:pl-2',
)}
+1 -1
View File
@@ -510,7 +510,7 @@ const LibraryPageContent = ({ searchParams }: { searchParams: ReadonlyURLSearchP
<div
ref={containerRef}
className={clsx(
'scroll-container drop-zone mt-[52px] flex-grow overflow-y-auto px-4 sm:px-2',
'scroll-container drop-zone mt-[48px] flex-grow overflow-y-auto px-4 sm:px-2',
appService?.hasSafeAreaInset && 'mt-[calc(52px+env(safe-area-inset-top))]',
appService?.hasSafeAreaInset && 'pb-[calc(env(safe-area-inset-bottom))]',
isDragging && 'drag-over',
@@ -351,7 +351,9 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
saveConfig(envConfig, bookKey, updatedConfig, settings);
}
handleDismissPopupAndSelection();
setNotebookVisible(true);
if (!appService?.isMobile) {
setNotebookVisible(true);
}
};
const handleHighlight = (update = false) => {
-1
View File
@@ -167,7 +167,6 @@ const ProfilePage = () => {
ref={headerRef}
className={clsx(
'fixed flex w-full items-center justify-between py-2 pe-6 ps-4',
appService?.hasSafeAreaInset && 'mt-[env(safe-area-inset-top)]',
appService?.hasTrafficLight && 'pt-11',
)}
>