diff --git a/plugins/clipboard/android/src/main/java/ClipboardPlugin.kt b/plugins/clipboard/android/src/main/java/ClipboardPlugin.kt index 2384156e..ece3e45e 100644 --- a/plugins/clipboard/android/src/main/java/ClipboardPlugin.kt +++ b/plugins/clipboard/android/src/main/java/ClipboardPlugin.kt @@ -21,8 +21,8 @@ class ClipboardPlugin(private val activity: Activity) : Plugin(activity) { @Command @Suppress("MoveVariableDeclarationIntoWhen") fun write(invoke: Invoke) { - val data = invoke.getObject("options") - if (data == null) { + val options = invoke.getObject("options") + if (options == null) { invoke.reject("Missing `options` input") return } @@ -30,8 +30,8 @@ class ClipboardPlugin(private val activity: Activity) : Plugin(activity) { val clipData = when (kind) { "PlainText" -> { - val label = data.getString("label", "") - val text = data.getString("text", "") + val label = options.getString("label", "") + val text = options.getString("text", "") ClipData.newPlainText(label, text) } @@ -54,10 +54,12 @@ class ClipboardPlugin(private val activity: Activity) : Plugin(activity) { Pair("PlainText", item.text) } else { // TODO + invoke.reject("Clipboard content reader not implemented") return } } else { - Pair("PlainText", "") + invoke.reject("Clipboard is empty") + return } val response = JSObject() diff --git a/plugins/clipboard/build.rs b/plugins/clipboard/build.rs index cc6cf86f..86ac3f0a 100644 --- a/plugins/clipboard/build.rs +++ b/plugins/clipboard/build.rs @@ -3,6 +3,7 @@ use std::process::exit; fn main() { if let Err(error) = tauri_build::mobile::PluginBuilder::new() .android_path("android") + .ios_path("ios") .run() { println!("{error:#}"); diff --git a/plugins/clipboard/ios/.gitignore b/plugins/clipboard/ios/.gitignore new file mode 100644 index 00000000..5922fdaa --- /dev/null +++ b/plugins/clipboard/ios/.gitignore @@ -0,0 +1,10 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/config/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc +Package.resolved diff --git a/plugins/clipboard/ios/Package.swift b/plugins/clipboard/ios/Package.swift new file mode 100644 index 00000000..e38a8bb6 --- /dev/null +++ b/plugins/clipboard/ios/Package.swift @@ -0,0 +1,31 @@ +// swift-tools-version:5.3 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "tauri-plugin-clipboard", + platforms: [ + .iOS(.v13), + ], + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "tauri-plugin-clipboard", + type: .static, + targets: ["tauri-plugin-clipboard"]), + ], + dependencies: [ + .package(name: "Tauri", path: "../.tauri/tauri-api") + ], + targets: [ + // 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-clipboard", + dependencies: [ + .byName(name: "Tauri") + ], + path: "Sources") + ] +) diff --git a/plugins/clipboard/ios/README.md b/plugins/clipboard/ios/README.md new file mode 100644 index 00000000..f4900bdd --- /dev/null +++ b/plugins/clipboard/ios/README.md @@ -0,0 +1,3 @@ +# Tauri Plugin {{ plugin_name_original }} + +A description of this package. diff --git a/plugins/clipboard/ios/Sources/ClipboardPlugin.swift b/plugins/clipboard/ios/Sources/ClipboardPlugin.swift new file mode 100644 index 00000000..cde6fa52 --- /dev/null +++ b/plugins/clipboard/ios/Sources/ClipboardPlugin.swift @@ -0,0 +1,42 @@ +import UIKit +import WebKit +import Tauri +import SwiftRs + +class ClipboardPlugin: Plugin { + @objc public func write(_ invoke: Invoke) throws { + let options = invoke.getObject("options") + if let options = options { + let clipboard = UIPasteboard.general + let kind = invoke.getString("kind", "") + switch kind { + case "PlainText": + let text = options["text"] as? String + clipboard.string = text + default: + invoke.reject("Unknown kind \(kind)") + return + } + invoke.resolve() + } else { + invoke.reject("Missing `options` input") + } + } + + @objc public func read(_ invoke: Invoke) throws { + let clipboard = UIPasteboard.general + if let text = clipboard.string { + invoke.resolve([ + "kind": "PlainText", + "options": text + ]) + } else { + invoke.reject("Clipboard is empty") + } + } +} + +@_cdecl("init_plugin_clipboard") +func initPlugin(name: SRString, webview: WKWebView?) { + Tauri.registerPlugin(webview: webview, name: name.toString(), plugin: ClipboardPlugin()) +} diff --git a/plugins/clipboard/ios/Tests/PluginTests/PluginTests.swift b/plugins/clipboard/ios/Tests/PluginTests/PluginTests.swift new file mode 100644 index 00000000..f1657dea --- /dev/null +++ b/plugins/clipboard/ios/Tests/PluginTests/PluginTests.swift @@ -0,0 +1,8 @@ +import XCTest +@testable import ClipboardPlugin + +final class ClipboardPluginTests: XCTestCase { + func testClipboard() throws { + let plugin = ClipboardPlugin() + } +} diff --git a/plugins/clipboard/src/error.rs b/plugins/clipboard/src/error.rs index 7beff881..bf71802f 100644 --- a/plugins/clipboard/src/error.rs +++ b/plugins/clipboard/src/error.rs @@ -8,10 +8,10 @@ pub type Result = std::result::Result; #[derive(Debug, thiserror::Error)] pub enum Error { - #[cfg(target_os = "android")] + #[cfg(mobile)] #[error(transparent)] PluginInvoke(#[from] tauri::plugin::mobile::PluginInvokeError), - #[cfg(not(target_os = "android"))] + #[cfg(desktop)] #[error("{0}")] Clipboard(String), } @@ -25,7 +25,7 @@ impl Serialize for Error { } } -#[cfg(not(target_os = "android"))] +#[cfg(desktop)] impl From for Error { fn from(error: arboard::Error) -> Self { Self::Clipboard(error.to_string()) diff --git a/plugins/clipboard/src/lib.rs b/plugins/clipboard/src/lib.rs index 98611a37..a655d93e 100644 --- a/plugins/clipboard/src/lib.rs +++ b/plugins/clipboard/src/lib.rs @@ -9,9 +9,9 @@ use tauri::{ pub use models::*; -#[cfg(not(target_os = "android"))] +#[cfg(desktop)] mod desktop; -#[cfg(target_os = "android")] +#[cfg(mobile)] mod mobile; mod commands; @@ -20,9 +20,9 @@ mod models; pub use error::{Error, Result}; -#[cfg(not(target_os = "android"))] +#[cfg(desktop)] use desktop::Clipboard; -#[cfg(target_os = "android")] +#[cfg(mobile)] use mobile::Clipboard; /// Extensions to [`tauri::App`], [`tauri::AppHandle`] and [`tauri::Window`] to access the clipboard APIs. @@ -41,9 +41,9 @@ pub fn init() -> TauriPlugin { Builder::new("clipboard") .invoke_handler(tauri::generate_handler![commands::write, commands::read]) .setup(|app, api| { - #[cfg(target_os = "android")] + #[cfg(mobile)] let clipboard = mobile::init(app, api)?; - #[cfg(not(target_os = "android"))] + #[cfg(desktop)] let clipboard = desktop::init(app, api)?; app.manage(clipboard); Ok(()) diff --git a/plugins/clipboard/src/mobile.rs b/plugins/clipboard/src/mobile.rs index 102e923d..07964711 100644 --- a/plugins/clipboard/src/mobile.rs +++ b/plugins/clipboard/src/mobile.rs @@ -10,14 +10,21 @@ use tauri::{ use crate::models::*; +#[cfg(target_os = "android")] const PLUGIN_IDENTIFIER: &str = "app.tauri.clipboard"; +#[cfg(target_os = "ios")] +tauri::ios_plugin_binding!(init_plugin_clipboard); + // initializes the Kotlin or Swift plugin classes pub fn init( _app: &AppHandle, api: PluginApi, ) -> crate::Result> { + #[cfg(target_os = "android")] let handle = api.register_android_plugin(PLUGIN_IDENTIFIER, "ClipboardPlugin")?; + #[cfg(target_os = "ios")] + let handle = api.register_ios_plugin(init_plugin_clipboard)?; Ok(Clipboard(handle)) }