diff --git a/android/src/main/java/app/tauri/notification/CachedKeyManager.kt b/android/src/main/java/app/tauri/notification/CachedKeyManager.kt new file mode 100644 index 0000000..7f9c03b --- /dev/null +++ b/android/src/main/java/app/tauri/notification/CachedKeyManager.kt @@ -0,0 +1,54 @@ +package app.tauri.notification + +import android.content.Context +import org.unifiedpush.android.connector.keys.DefaultKeyManager +import org.unifiedpush.android.connector.keys.KeyManager +import org.unifiedpush.android.connector.data.PublicKeySet + +/** + * Wraps DefaultKeyManager with in-memory caching to avoid repeated + * AndroidKeyStore access for getPublicKeySet/exists calls. + */ +class CachedKeyManager private constructor(context: Context) : KeyManager { + private val delegate = DefaultKeyManager(context) + private val pubkeyCache = mutableMapOf() + private val existsCache = mutableMapOf() + + override fun decrypt(instance: String, sealed: ByteArray): ByteArray? { + return delegate.decrypt(instance, sealed) + } + + override fun generate(instance: String) { + pubkeyCache.remove(instance) + existsCache.remove(instance) + delegate.generate(instance) + } + + override fun getPublicKeySet(instance: String): PublicKeySet? { + pubkeyCache[instance]?.let { return it } + val keys = delegate.getPublicKeySet(instance) + if (keys != null) pubkeyCache[instance] = keys + return keys + } + + override fun exists(instance: String): Boolean { + return existsCache.getOrPut(instance) { delegate.exists(instance) } + } + + override fun delete(instance: String) { + pubkeyCache.remove(instance) + existsCache.remove(instance) + delegate.delete(instance) + } + + companion object { + @Volatile + private var instance: CachedKeyManager? = null + + fun getInstance(context: Context): CachedKeyManager { + return instance ?: synchronized(this) { + instance ?: CachedKeyManager(context.applicationContext).also { instance = it } + } + } + } +} diff --git a/android/src/main/java/app/tauri/notification/UnifiedPushReceiver.kt b/android/src/main/java/app/tauri/notification/UnifiedPushReceiver.kt index 829f687..fa7bdcf 100644 --- a/android/src/main/java/app/tauri/notification/UnifiedPushReceiver.kt +++ b/android/src/main/java/app/tauri/notification/UnifiedPushReceiver.kt @@ -6,8 +6,14 @@ import org.unifiedpush.android.connector.MessagingReceiver import org.unifiedpush.android.connector.UnifiedPush import org.unifiedpush.android.connector.data.PushEndpoint import org.unifiedpush.android.connector.data.PushMessage +import org.unifiedpush.android.connector.keys.KeyManager class UnifiedPushReceiver : MessagingReceiver() { + + override fun getKeyManager(context: Context): KeyManager { + return CachedKeyManager.getInstance(context) + } + override fun onNewEndpoint(context: Context, endpoint: PushEndpoint, instance: String) { NotificationPlugin.instance?.onUnifiedPushNewEndpoint( endpoint.url, diff --git a/android/src/main/java/app/tauri/notification/UnifiedPushStateStore.kt b/android/src/main/java/app/tauri/notification/UnifiedPushStateStore.kt index f8e2daa..56835e7 100644 --- a/android/src/main/java/app/tauri/notification/UnifiedPushStateStore.kt +++ b/android/src/main/java/app/tauri/notification/UnifiedPushStateStore.kt @@ -23,13 +23,16 @@ internal class UnifiedPushStateStore(private val context: Context) { prefs.edit().remove("push-instance").remove("up-endpoint").apply() } fun instanceForRegistration(): String { - activeInstance?.let { return it } - if (activeProvider == "unifiedpush") return INSTANCE - return UUID.randomUUID().toString().also { activeInstance = it } + val current = activeInstance + if (current != null && current != INSTANCE) { + try { UnifiedPush.unregister(context, current) } catch (_: Exception) {} + activeInstance = INSTANCE + } + return INSTANCE } fun ensureExplicitInstance() { if (prefs.getString("push-instance", null) == null) { - activeInstance = UUID.randomUUID().toString() + activeInstance = INSTANCE } } fun setUnifiedPushActive() { activeProvider = "unifiedpush" }