cc12458 1 місяць тому
батько
коміт
3560e66098

+ 2 - 0
core/build.gradle.kts

@@ -44,4 +44,6 @@ dependencies {
   testImplementation(libs.junit)
   androidTestImplementation(libs.androidx.junit)
   androidTestImplementation(libs.androidx.espresso.core)
+
+  implementation(libs.gson)
 }

+ 7 - 0
core/src/main/java/com/hzliuzhi/applet/core/shared/Event.kt

@@ -0,0 +1,7 @@
+package com.hzliuzhi.applet.core.shared
+
+data class Event<P, C>(
+  val type: String,
+  val payload: P?,
+  val callback: ((C) -> Unit)? = null,
+)

+ 21 - 0
core/src/main/java/com/hzliuzhi/applet/core/shared/Payload.kt

@@ -0,0 +1,21 @@
+package com.hzliuzhi.applet.core.shared
+
+import com.google.gson.Gson
+import com.google.gson.JsonElement
+
+data class Payload<D>(val data: D? = null, val code: Int, val message: String?) {
+
+  companion object {
+    fun <D> error(code: Int = -1, message: String?) = Payload<D>(code = code, message = message)
+
+    fun <D> data(data: D, message: String? = null) = Payload(code = 0, data = data, message = message)
+  }
+
+  fun toEvent(): JsonElement? {
+    return Gson().toJsonTree(this, Payload::class.java)
+  }
+
+  fun <T> copyWith(data: T?, code: Int = this.code, message: String? = this.message): Payload<T> {
+    return Payload(code = code, message = message, data = data)
+  }
+}

+ 35 - 0
core/src/main/java/com/hzliuzhi/applet/core/shared/SharedFlowHub.kt

@@ -0,0 +1,35 @@
+package com.hzliuzhi.applet.core.shared
+
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.asSharedFlow
+
+object SharedFlowHub {
+  const val WEBVIEW_BRIDGE_EVENT = "webview:bridge"
+
+  private val _events = MutableSharedFlow<Event<*, *>>(extraBufferCapacity = 16)
+  val events = _events.asSharedFlow()
+
+  fun emit(event: Event<*, *>) = _events.tryEmit(event)
+
+  @Suppress("UNCHECKED_CAST")
+  inline fun <reified P, reified C> Event<*, *>.cast(): Event<P, C>? {
+    return try {
+      Event(
+        type = this.type,
+        payload = this.payload as? P,
+        callback = this.callback as? ((C) -> Unit)
+      )
+    } catch (e: Exception) {
+      null
+    }
+  }
+
+  @Suppress("UNCHECKED_CAST")
+  inline fun <reified C> Event<*, *>.callbackAs(): ((C) -> Unit)? {
+    return callback as? ((C) -> Unit)
+  }
+
+  inline fun <reified P> Event<*, *>.payloadAs(): P? {
+    return payload as? P
+  }
+}

+ 12 - 0
core/src/main/java/com/hzliuzhi/applet/core/util/Resources.kt

@@ -0,0 +1,12 @@
+package com.hzliuzhi.applet.core.util
+
+import android.content.res.Resources
+import androidx.annotation.ArrayRes
+
+fun Resources.proxy(@ArrayRes id: Int) = getStringArray(id).mapNotNull { item ->
+  item
+    .split("->")
+    .map { it -> it.trim() }
+    .takeIf { it.size == 2 && it[0].isNotEmpty() && it[1].isNotEmpty() }
+    ?.let { it[0] to it[1] }
+}.toMap()

+ 62 - 0
library/browser/src/main/assets/browser/bridge.js

@@ -0,0 +1,62 @@
+class Bridge extends EventTarget {
+  #pool = new Map();
+
+  static getInstance() {
+    return Bridge._instance ?? (Bridge._instance = new Bridge());
+  }
+
+  static get Platform() {
+    return window['AndroidBridge'];
+  }
+
+  static get UUID() {
+    return crypto.randomUUID();
+  }
+
+  static pulse(userId) {
+    const { promise, ...resolvers } = Promise.withResolvers();
+    this.getInstance().#postMessage('pulse', { userId }, resolvers);
+    return promise;
+  }
+
+  static print(payload) {
+    const { promise, ...resolvers } = Promise.withResolvers();
+    this.getInstance().#postMessage('print', payload, resolvers);
+    return promise;
+  }
+
+  dispatch(message) {
+    try {
+      const { type, callbackId, payload }  = JSON.parse(message);
+      if (callbackId) {
+        const { resolve, reject } = this.#pool.get(callbackId) ?? {};
+        this.#pool.delete(callbackId);
+        if (payload.code === 0) resolve(payload.data)
+        else reject(payload.message)
+      } else {
+        event = new CustomEvent(type, { detail: payload });
+        super.dispatchEvent(event);
+      }
+    } catch (e) {
+      console.log('log:bridge:js', `[analysis] 解析消息错误: ${e.message}`);
+      throw e;
+    }
+  }
+
+  addEventListener(type, callback, options) {
+    super.addEventListener(type, callback, options);
+    return () => super.removeEventListener(type, callback);
+  }
+
+  #postMessage(type, payload, resolvers) {
+    const callbackId = `${type}:${Bridge.UUID}`;
+    this.#pool.set(callbackId, resolvers);
+    const message = JSON.stringify({ type, payload, callbackId })
+    Bridge.Platform.postMessage(message);
+  }
+}
+
+window['Bridge'] = Bridge;
+window['bridge'] = Bridge.getInstance();
+
+window.print = Bridge.print.bind(Bridge);