Skip to content

Commit d6d26e5

Browse files
committed
feat: add ios code
1 parent ef89071 commit d6d26e5

File tree

9 files changed

+219
-9
lines changed

9 files changed

+219
-9
lines changed

plugins/deep-link/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ fn main() {
6666
let result = tauri_plugin::Builder::new(COMMANDS)
6767
.global_api_script_path("./api-iife.js")
6868
.android_path("android")
69+
.ios_path("ios")
6970
.try_build();
7071

7172
// when building documentation for Android the plugin build result is always Err() and is irrelevant to the crate documentation build

plugins/deep-link/ios/.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.DS_Store
2+
/.build
3+
/Packages
4+
/*.xcodeproj
5+
xcuserdata/
6+
DerivedData/
7+
.swiftpm/config/registries.json
8+
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
9+
.netrc
10+
Package.resolved
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// swift-tools-version:5.3
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "tauri-plugin-deep-link",
8+
platforms: [
9+
.macOS(.v10_13),
10+
.iOS(.v13),
11+
],
12+
products: [
13+
// Products define the executables and libraries a package produces, and make them visible to other packages.
14+
.library(
15+
name: "tauri-plugin-deep-link",
16+
type: .static,
17+
targets: ["tauri-plugin-deep-link"]),
18+
],
19+
dependencies: [
20+
.package(name: "Tauri", path: "../.tauri/tauri-api")
21+
],
22+
targets: [
23+
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
24+
// Targets can depend on other targets in this package, and on products in packages this package depends on.
25+
.target(
26+
name: "tauri-plugin-deep-link",
27+
dependencies: [
28+
.byName(name: "Tauri")
29+
],
30+
path: "Sources")
31+
]
32+
)

plugins/deep-link/ios/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Tauri Plugin deep-link
2+
3+
A description of this package.
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import SwiftRs
2+
import Tauri
3+
import UIKit
4+
import WebKit
5+
6+
struct SetEventHandlerArgs: Decodable {
7+
let handler: Channel
8+
}
9+
10+
@objc class DeepLinkPlugin: Plugin {
11+
private var webView: WKWebView?
12+
private var currentUrl: String?
13+
private var channel: Channel?
14+
15+
// Called when the plugin is loaded
16+
@objc public override func load(webview: WKWebView) {
17+
super.load(webview: webview)
18+
self.webView = webview
19+
DeepLinkPlugin.instance = self
20+
21+
// Check if app was launched via URL
22+
if let url = DeepLinkPlugin.launchedUrl {
23+
// If so, send to JS
24+
var event = JSObject()
25+
event["url"] = url.absoluteString
26+
self.channel?.send(event)
27+
}
28+
}
29+
30+
// JS command: return current URL
31+
@objc public func getCurrent(_ invoke: Invoke) throws {
32+
var ret = JSObject()
33+
ret["url"] = self.currentUrl
34+
invoke.resolve(ret)
35+
}
36+
37+
// JS command: set the JS callback handler channel
38+
@objc public func setEventHandler(_ invoke: Invoke) throws {
39+
let args = try invoke.parseArgs(SetEventHandlerArgs.self)
40+
self.channel = args.handler
41+
invoke.resolve()
42+
}
43+
44+
// Static helpers to store/dispatch URLs
45+
static var instance: DeepLinkPlugin?
46+
static var launchedUrl: URL?
47+
static func handleOpenUrl(_ url: URL) {
48+
// Called from AppDelegate/SceneDelegate
49+
if let plugin = DeepLinkPlugin.instance {
50+
plugin.currentUrl = url.absoluteString
51+
if let ch = plugin.channel {
52+
var event = JSObject()
53+
event["url"] = url.absoluteString
54+
ch.send(event)
55+
}
56+
} else {
57+
// App not yet initialized; save for load()
58+
DeepLinkPlugin.launchedUrl = url
59+
}
60+
}
61+
}
62+
63+
@UIApplicationMain
64+
class AppDelegate: UIResponder, UIApplicationDelegate {
65+
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
66+
DeepLinkPlugin.handleOpenUrl(url)
67+
return true
68+
}
69+
}
70+
71+
72+
73+
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
74+
75+
var window: UIWindow?
76+
77+
// Called when a scene is being created and connected
78+
func scene(_ scene: UIScene,
79+
willConnectTo session: UISceneSession,
80+
options connectionOptions: UIScene.ConnectionOptions) {
81+
82+
// Handle initial URL if app was launched via a deep link
83+
if let urlContext = connectionOptions.urlContexts.first {
84+
DeepLinkPlugin.handleOpenUrl(urlContext.url)
85+
}
86+
}
87+
88+
// Called when the app receives a deep link while already running
89+
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
90+
guard let url = URLContexts.first?.url else { return }
91+
DeepLinkPlugin.handleOpenUrl(url)
92+
}
93+
}
94+
95+
@_cdecl("init_plugin_deep_link")
96+
func initPlugin() -> Plugin {
97+
return DeepLinkPlugin()
98+
}
99+
100+
// import Tauri
101+
// import UIKit
102+
// import WebKit
103+
104+
// class PingArgs: Decodable {
105+
// let value: String?
106+
// }
107+
108+
// class ExamplePlugin: Plugin {
109+
// @objc public func ping(_ invoke: Invoke) throws {
110+
// let args = try invoke.parseArgs(PingArgs.self)
111+
// invoke.resolve(["value": args.value ?? ""])
112+
// }
113+
// }
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import XCTest
2+
@testable import ExamplePlugin
3+
4+
final class ExamplePluginTests: XCTestCase {
5+
func testExample() throws {
6+
let plugin = ExamplePlugin()
7+
}
8+
}

plugins/deep-link/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,8 @@
2626
],
2727
"dependencies": {
2828
"@tauri-apps/api": "^2.6.0"
29+
},
30+
"devDependencies": {
31+
"@tauri-apps/cli": "2.7.1"
2932
}
3033
}

plugins/deep-link/src/lib.rs

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@ pub use error::{Error, Result};
1616
#[cfg(target_os = "android")]
1717
const PLUGIN_IDENTIFIER: &str = "app.tauri.deep_link";
1818

19+
#[cfg(target_os = "ios")]
20+
tauri::ios_plugin_binding!(init_plugin_deep_link);
21+
1922
fn init_deep_link<R: Runtime>(
2023
app: &AppHandle<R>,
2124
api: PluginApi<R, Option<config::Config>>,
2225
) -> crate::Result<DeepLink<R>> {
23-
#[cfg(target_os = "android")]
26+
#[cfg(mobile)]
2427
{
2528
let _api = api;
2629

@@ -29,8 +32,12 @@ fn init_deep_link<R: Runtime>(
2932
Emitter,
3033
};
3134

35+
#[cfg(target_os = "android")]
3236
let handle = _api.register_android_plugin(PLUGIN_IDENTIFIER, "DeepLinkPlugin")?;
3337

38+
#[cfg(target_os = "ios")]
39+
let handle = _api.register_ios_plugin(init_plugin_deep_link)?;
40+
3441
#[derive(serde::Deserialize)]
3542
struct Event {
3643
url: String,
@@ -56,20 +63,49 @@ fn init_deep_link<R: Runtime>(
5663
}),
5764
},
5865
)?;
66+
67+
#[cfg(target_os = "android")]
68+
{
69+
return Ok(DeepLink {
70+
app: app.clone(),
71+
plugin_handle: handle,
72+
});
73+
}
74+
75+
#[cfg(target_os = "ios")]
76+
{
77+
return Ok(DeepLink {
78+
app: app.clone(),
79+
current: Default::default(),
80+
config: api.config().clone(),
81+
plugin_handle: handle,
82+
})
83+
}
84+
}
5985

86+
#[cfg(target_os = "ios")]
87+
{
88+
89+
let _api = api;
90+
91+
use tauri::{
92+
ipc::{Channel, InvokeResponseBody},
93+
Emitter,
94+
};
95+
96+
#[derive(serde::Deserialize)]
97+
struct Event {
98+
url: String,
99+
}
100+
101+
let handle = _api.register_ios_plugin(init_plugin_deep_link)?;
60102
return Ok(DeepLink {
61103
app: app.clone(),
62-
plugin_handle: handle,
104+
current: Default::default(),
105+
config: api.config().clone(),
63106
});
64107
}
65108

66-
#[cfg(target_os = "ios")]
67-
return Ok(DeepLink {
68-
app: app.clone(),
69-
current: Default::default(),
70-
config: api.config().clone(),
71-
});
72-
73109
#[cfg(desktop)]
74110
{
75111
let args = std::env::args();

pnpm-lock.yaml

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)