Files
upstream-tauri/crates/tauri/mobile/ios-api/Sources/Tauri/Tauri.swift
upstream-mirror feda81bf2f
Some checks failed
Audit / audit-js (push) Failing after 0s
bench / bench (map[os:ubuntu-latest runner:xvfb-run --auto-servernum target:x86_64-unknown-linux-gnu], nightly) (push) Failing after 0s
covector version or publish / run-integration-tests (ubuntu-latest) (push) Failing after 0s
Audit / audit-rust (push) Failing after 0s
test `@tauri-apps/cli` / test (ubuntu-latest) (push) Failing after 0s
test `tauri-cli` / test (map[os:ubuntu-latest target:x86_64-unknown-linux-gnu]) (push) Failing after 0s
test core / test (map[args:--all-features key:all], map[cargo:cargo command:test os:ubuntu-latest target:x86_64-unknown-linux-gnu toolchain:1.90]) (push) Failing after 0s
test core / test (map[args:--no-default-features key:no-default], map[cargo:cargo command:test os:ubuntu-latest target:x86_64-unknown-linux-gnu toolchain:1.90]) (push) Failing after 0s
test core / test (map[args:--no-default-features key:no-default], map[cargo:cross command:build os:ubuntu-latest target:aarch64-linux-android toolchain:1.90]) (push) Failing after 0s
deploy schema worker / deploy (push) Failing after 0s
lint rust / clippy (map[cargo:cargo include: os:ubuntu-latest target:x86_64-unknown-linux-gnu]) (push) Failing after 0s
lint rust / clippy (map[cargo:cross include:--package api os:ubuntu-latest target:aarch64-linux-android]) (push) Failing after 0s
supply chain health status / check rust dependencies with cargo vet (push) Failing after 0s
test `@tauri-apps/api` e2e (mobile) / android (push) Failing after 0s
test `@tauri-apps/api` e2e / test (map[name:Linux os:ubuntu-latest]) (push) Failing after 0s
test core / test (map[args:--all-features key:all], map[cargo:cross command:build os:ubuntu-latest target:aarch64-linux-android toolchain:1.90]) (push) Failing after 0s
Udeps / changes (push) Failing after 0s
Udeps / setup (push) Has been skipped
Udeps / udeps (push) Has been skipped
bench / bench (map[os:macos-latest runner: target:aarch64-apple-darwin], nightly) (push) Has been cancelled
bench / bench (map[os:windows-latest runner: target:x86_64-pc-windows-msvc], nightly) (push) Has been cancelled
covector version or publish / run-integration-tests (macos-latest) (push) Has been cancelled
covector version or publish / run-integration-tests (windows-latest) (push) Has been cancelled
covector version or publish / version-or-publish (push) Has been cancelled
test `@tauri-apps/cli` / test (macos-latest) (push) Has been cancelled
test `tauri-cli` / test (map[args:--no-default-features --features native-tls-vendored os:windows-latest restore-only:true target:aarch64-pc-windows-msvc]) (push) Has been cancelled
test `tauri-cli` / test (map[os:macos-latest target:x86_64-apple-darwin]) (push) Has been cancelled
test `tauri-cli` / test (map[os:windows-latest target:x86_64-pc-windows-msvc]) (push) Has been cancelled
test core / test (map[args:--all-features key:all], map[cargo:cargo command:build os:macos-latest target:aarch64-apple-ios toolchain:1.90]) (push) Has been cancelled
test core / test (map[args:--all-features key:all], map[cargo:cargo command:test os:macos-14 target:aarch64-apple-darwin toolchain:1.90]) (push) Has been cancelled
lint rust / clippy (map[cargo:cargo include: os:macos-latest target:aarch64-apple-darwin]) (push) Has been cancelled
lint rust / clippy (map[cargo:cargo include: os:windows-latest target:x86_64-pc-windows-msvc]) (push) Has been cancelled
lint rust / clippy (map[cargo:cargo include:--package api os:macos-latest target:aarch64-apple-ios]) (push) Has been cancelled
test `@tauri-apps/api` e2e (mobile) / ios (push) Has been cancelled
test `@tauri-apps/api` e2e / test (map[name:Windows os:windows-latest]) (push) Has been cancelled
test `@tauri-apps/api` e2e / test (map[name:macOS os:macos-latest]) (push) Has been cancelled
test `@tauri-apps/cli` / test (windows-latest) (push) Has been cancelled
test core / test (map[args:--all-features key:all], map[cargo:cargo command:test os:windows-latest target:x86_64-pc-windows-msvc toolchain:1.90]) (push) Has been cancelled
test core / test (map[args:--no-default-features key:no-default], map[cargo:cargo command:build os:macos-latest target:aarch64-apple-ios toolchain:1.90]) (push) Has been cancelled
test core / test (map[args:--no-default-features key:no-default], map[cargo:cargo command:test os:macos-14 target:aarch64-apple-darwin toolchain:1.90]) (push) Has been cancelled
test core / test (map[args:--no-default-features key:no-default], map[cargo:cargo command:test os:windows-latest target:x86_64-pc-windows-msvc toolchain:1.90]) (push) Has been cancelled
snapshot of https://github.com/tauri-apps/tauri.git (dev, 2026-09-23; blobs > 131072B omitted)
2026-09-23 17:00:42 +05:00

158 lines
4.8 KiB
Swift

// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import Foundation
import SwiftRs
import UIKit
import WebKit
import os.log
class PluginHandle {
var instance: Plugin
var loaded = false
init(plugin: Plugin) {
instance = plugin
}
}
public class PluginManager {
static let shared: PluginManager = PluginManager()
public var viewController: UIViewController?
var plugins: [String: PluginHandle] = [:]
var ipcDispatchQueue = DispatchQueue(label: "ipc")
public var isSimEnvironment: Bool {
#if targetEnvironment(simulator)
return true
#else
return false
#endif
}
public func assetUrl(fromLocalURL url: URL?) -> URL? {
guard let inputURL = url else {
return nil
}
return URL(string: "asset://localhost")!.appendingPathComponent(inputURL.path)
}
func onWebviewCreated(_ webview: WKWebView) {
for (_, handle) in plugins {
if !handle.loaded {
handle.instance.load(webview: webview)
}
}
}
func load<P: Plugin>(name: String, plugin: P, config: String, webview: WKWebView?) {
plugin.setConfig(config)
let handle = PluginHandle(plugin: plugin)
if let webview = webview {
handle.instance.load(webview: webview)
handle.loaded = true
}
plugins[name] = handle
}
func invoke(name: String, invoke: Invoke) {
if let plugin = plugins[name] {
ipcDispatchQueue.async {
let selectorWithCompletionHandler = Selector(("\(invoke.command):completionHandler:"))
let selectorWithThrows = Selector(("\(invoke.command):error:"))
if plugin.instance.responds(to: selectorWithCompletionHandler) {
let completion: @convention(block) (NSError?) -> Void = { error in
if let error = error {
invoke.reject("\(error)")
}
}
let blockObj: AnyObject = unsafeBitCast(completion, to: AnyObject.self)
let imp = plugin.instance.method(for: selectorWithCompletionHandler)
typealias Fn = @convention(c) (AnyObject, Selector, Invoke, AnyObject) -> Void
let fn = unsafeBitCast(imp, to: Fn.self)
fn(plugin.instance, selectorWithCompletionHandler, invoke, blockObj)
} else if plugin.instance.responds(to: selectorWithThrows) {
var error: NSError? = nil
withUnsafeMutablePointer(to: &error) {
let methodIMP: IMP! = plugin.instance.method(for: selectorWithThrows)
unsafeBitCast(
methodIMP, to: (@convention(c) (Any?, Selector, Invoke, OpaquePointer) -> Void).self)(
plugin.instance, selectorWithThrows, invoke, OpaquePointer($0))
}
if let error = error {
invoke.reject("\(error)")
// TODO: app crashes without this leak
let _ = Unmanaged.passRetained(error)
}
} else {
let selector = Selector(("\(invoke.command):"))
if plugin.instance.responds(to: selector) {
plugin.instance.perform(selector, with: invoke)
} else {
invoke.reject("No command \(invoke.command) found for plugin \(name)")
}
}
}
} else {
invoke.reject("Plugin \(name) not initialized")
}
}
}
extension PluginManager: NSCopying {
public func copy(with zone: NSZone? = nil) -> Any {
return self
}
}
private var stdoutRedirector: StdoutRedirector?
@_cdecl("log_stdout")
func logStdout() {
stdoutRedirector = StdoutRedirector()
stdoutRedirector!.start()
}
@_cdecl("register_plugin")
func registerPlugin(name: SRString, plugin: NSObject, config: SRString, webview: WKWebView?) {
PluginManager.shared.load(
name: name.toString(),
plugin: plugin as! Plugin,
config: config.toString(),
webview: webview
)
}
@_cdecl("on_webview_created")
func onWebviewCreated(webview: WKWebView, viewController: UIViewController) {
PluginManager.shared.viewController = viewController
PluginManager.shared.onWebviewCreated(webview)
}
@_cdecl("run_plugin_command")
func runCommand(
id: Int,
name: SRString,
command: SRString,
data: SRString,
callback: @escaping @convention(c) (Int, Bool, UnsafePointer<CChar>) -> Void,
sendChannelData: @escaping @convention(c) (UInt64, UnsafePointer<CChar>) -> Void
) {
let callbackId: UInt64 = 0
let errorId: UInt64 = 1
let invoke = Invoke(
command: command.toString(), callback: callbackId, error: errorId,
sendResponse: { (fn: UInt64, payload: String?) -> Void in
let success = fn == callbackId
callback(id, success, payload ?? "null")
},
sendChannelData: { (id: UInt64, payload: String) -> Void in
sendChannelData(id, payload)
}, data: data.toString())
PluginManager.shared.invoke(name: name.toString(), invoke: invoke)
}