Эх сурвалжийг харах

feat(mobile): add event APIs for plugins (#6946)

Lucas Fernandes Nogueira 2 жил өмнө
parent
commit
6fb5734d2f

+ 51 - 0
core/tauri/mobile/android/src/main/java/app/tauri/plugin/Plugin.kt

@@ -20,9 +20,11 @@ import app.tauri.annotation.PermissionCallback
 import app.tauri.annotation.TauriPlugin
 import org.json.JSONException
 import java.util.*
+import java.util.concurrent.CopyOnWriteArrayList
 
 abstract class Plugin(private val activity: Activity) {
   var handle: PluginHandle? = null
+  private val listeners: MutableMap<String, MutableList<Channel>> = mutableMapOf()
 
   open fun load(webView: WebView) {}
 
@@ -76,6 +78,55 @@ abstract class Plugin(private val activity: Activity) {
     return "asset://localhost$path"
   }
 
+  fun trigger(event: String, payload: JSObject) {
+    val eventListeners = listeners[event]
+    if (!eventListeners.isNullOrEmpty()) {
+      val listeners = CopyOnWriteArrayList(eventListeners)
+      for (channel in listeners) {
+        channel.send(payload)
+      }
+    }
+  }
+
+  @Command
+  open fun registerListener(invoke: Invoke) {
+    val event = invoke.getString("event")
+    val channel = invoke.getChannel("handler")
+
+    if (event == null || channel == null) {
+      invoke.reject("`event` or `handler` not provided")
+    } else {
+      val eventListeners = listeners[event]
+      if (eventListeners.isNullOrEmpty()) {
+        listeners[event] = mutableListOf(channel)
+      } else {
+        eventListeners.add(channel)
+      }
+    }
+
+    invoke.resolve()
+  }
+
+  @Command
+  open fun removeListener(invoke: Invoke) {
+    val event = invoke.getString("event")
+    val channelId = invoke.getLong("channelId")
+
+    if (event == null || channelId == null) {
+      invoke.reject("`event` or `channelId` not provided")
+    } else {
+      val eventListeners = listeners[event]
+      if (!eventListeners.isNullOrEmpty()) {
+        val c = eventListeners.find { c -> c.id == channelId }
+        if (c != null) {
+          eventListeners.remove(c)
+        }
+      }
+    }
+
+    invoke.resolve()
+  }
+
   /**
    * Exported plugin method for checking the granted status for each permission
    * declared on the plugin. This plugin call responds with a mapping of permissions to

+ 3 - 3
core/tauri/mobile/ios-api/Sources/Tauri/Channel.swift

@@ -3,11 +3,11 @@
 // SPDX-License-Identifier: MIT
 
 public class Channel {
-  var callback: UInt64
-  var handler: (JsonValue) -> Void
+  public let id: UInt64
+  let handler: (JsonValue) -> Void
 
   public init(callback: UInt64, handler: @escaping (JsonValue) -> Void) {
-    self.callback = callback
+    self.id = callback
     self.handler = handler
   }
 

+ 4 - 9
core/tauri/mobile/ios-api/Sources/Tauri/Invoke.swift

@@ -73,16 +73,11 @@ let CHANNEL_PREFIX = "__CHANNEL__:"
 
   public func getChannel(_ key: String) -> Channel? {
     let channelDef = getString(key, "")
-    if channelDef.starts(with: CHANNEL_PREFIX) {
-      let index = channelDef.index(channelDef.startIndex, offsetBy: CHANNEL_PREFIX.count)
-      guard let callback = UInt64(channelDef[index...]) else {
-        return nil
-      }
-      return Channel(callback: callback, handler: { (res: JsonValue) -> Void in
-        self.sendResponse(callback, res)
-      })
-    } else {
+    guard let callback = UInt64(channelDef.components(separatedBy: CHANNEL_PREFIX)[1]) else {
       return nil
     }
+    return Channel(callback: callback, handler: { (res: JsonValue) -> Void in
+      self.sendResponse(callback, res)
+    })
   }
 }

+ 55 - 9
core/tauri/mobile/ios-api/Sources/Tauri/Plugin/Plugin.swift

@@ -6,20 +6,66 @@ import WebKit
 import os.log
 
 open class Plugin: NSObject {
-    public let manager: PluginManager = PluginManager.shared
-    public var config: JSObject = [:]
+  public let manager: PluginManager = PluginManager.shared
+  public var config: JSObject = [:]
+  private var listeners = [String: [Channel]]()
 
-    internal func setConfig(_ config: JSObject) {
-      self.config = config
+  internal func setConfig(_ config: JSObject) {
+    self.config = config
+  }
+
+  @objc open func load(webview: WKWebView) {}
+
+  @objc open func checkPermissions(_ invoke: Invoke) {
+    invoke.resolve()
+  }
+
+  @objc open func requestPermissions(_ invoke: Invoke) {
+    invoke.resolve()
+  }
+
+  public func trigger(_ event: String, data: JSObject) {
+    if let eventListeners = listeners[event] {
+      for channel in eventListeners {
+        channel.send(data)
+      }
     }
+  }
 
-    @objc open func load(webview: WKWebView) {}
+  @objc func registerListener(_ invoke: Invoke) {
+    guard let event = invoke.getString("event") else {
+      invoke.reject("`event` not provided")
+      return
+    }
+    guard let channel = invoke.getChannel("handler") else {
+      invoke.reject("`handler` not provided")
+      return
+    }
 
-    @objc open func checkPermissions(_ invoke: Invoke) {
-        invoke.resolve()
+    if var eventListeners = listeners[event] {
+      eventListeners.append(channel)
+    } else {
+      listeners[event] = [channel]
     }
 
-    @objc open func requestPermissions(_ invoke: Invoke) {
-        invoke.resolve()
+    invoke.resolve()
+  }
+
+  @objc func removeListener(_ invoke: Invoke) {
+    guard let event = invoke.getString("event") else {
+      invoke.reject("`event` not provided")
+      return
     }
+
+    if let eventListeners = listeners[event] {
+      guard let channelId = invoke.getInt("channelId") else {
+        invoke.reject("`channelId` not provided")
+        return
+      }
+
+      listeners[event] = eventListeners.filter { $0.id != channelId }
+    }
+
+    invoke.resolve()
+  }
 }

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
core/tauri/scripts/bundle.global.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
tooling/api/docs/js-api.json


+ 46 - 1
tooling/api/src/tauri.ts

@@ -82,6 +82,44 @@ class Channel<T = unknown> {
   }
 }
 
+class PluginListener {
+  plugin: string
+  event: string
+  channelId: number
+
+  constructor(plugin: string, event: string, channelId: number) {
+    this.plugin = plugin
+    this.event = event
+    this.channelId = channelId
+  }
+
+  async unregister(): Promise<void> {
+    return invoke(`plugin:${this.plugin}|remove_listener`, {
+      event: this.event,
+      channelId: this.channelId
+    })
+  }
+}
+
+/**
+ * Adds a listener to a plugin event.
+ *
+ * @returns The listener object to stop listening to the events.
+ *
+ * @since 2.0.0
+ */
+async function addPluginListener<T>(
+  plugin: string,
+  event: string,
+  cb: (payload: T) => void
+): Promise<PluginListener> {
+  const handler = new Channel<T>()
+  handler.onmessage = cb
+  return invoke(`plugin:${plugin}|register_listener`, { event, handler }).then(
+    () => new PluginListener(plugin, event, handler.id)
+  )
+}
+
 /**
  * Command arguments.
  *
@@ -162,4 +200,11 @@ function convertFileSrc(filePath: string, protocol = 'asset'): string {
 
 export type { InvokeArgs }
 
-export { transformCallback, Channel, invoke, convertFileSrc }
+export {
+  transformCallback,
+  Channel,
+  PluginListener,
+  addPluginListener,
+  invoke,
+  convertFileSrc
+}

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно