7ab832471271

feat: android — AutofillPlugin + BiometricPlugin + src/shared/biometric.ts (v2.13.0)

time
2026-04-29 19:39 UTC · 6 months ago
machine
koh2
parent
96ed311ac197
3 files android/app/src/main/java/com/peachpasswords/app/AutofillPlugin.kt+36 −0android/app/src/main/java/com/peachpasswords/app/BiometricPlugin.kt+52 −0src/shared/biometric.ts+22 −0
android/app/src/main/java/com/peachpasswords/app/AutofillPlugin.kt+36 −0
@@ -0,0 +1,36 @@1+package com.peachpasswords.app2+3+import com.getcapacitor.*4+import com.getcapacitor.annotation.CapacitorPlugin5+6+@CapacitorPlugin(name = "Autofill")7+class AutofillPlugin : Plugin() {8+9+    @PluginMethod10+    fun checkPendingSave(call: PluginCall) {11+        val prefs = context.getSharedPreferences("CapacitorStorage", Context.MODE_PRIVATE)12+        val pending = prefs.getString("peach_pending_save", null)13+        if (pending != null) {14+            prefs.edit().remove("peach_pending_save").apply()15+            call.resolve(JSObject().put("pending", pending))16+        } else {17+            call.resolve(JSObject().put("pending", null))18+        }19+    }20+21+    @PluginMethod22+    fun openAutofillSettings(call: PluginCall) {23+        val intent = android.content.Intent(24+            android.provider.Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE,25+            android.net.Uri.parse("package:${context.packageName}")26+        )27+        activity.startActivity(intent)28+        call.resolve()29+    }30+31+    @PluginMethod32+    fun isEnabledAsAutofillService(call: PluginCall) {33+        val afm = context.getSystemService(android.view.autofill.AutofillManager::class.java)34+        call.resolve(JSObject().put("enabled", afm?.hasEnabledAutofillServices() == true))35+    }36+}

view file

android/app/src/main/java/com/peachpasswords/app/BiometricPlugin.kt+52 −0
@@ -0,0 +1,52 @@1+package com.peachpasswords.app2+3+import androidx.biometric.BiometricPrompt4+import androidx.core.content.ContextCompat5+import com.getcapacitor.*6+import com.getcapacitor.annotation.CapacitorPlugin7+8+@CapacitorPlugin(name = "Biometric")9+class BiometricPlugin : Plugin() {10+11+    @PluginMethod12+    fun authenticate(call: PluginCall) {13+        val executor = ContextCompat.getMainExecutor(context)14+        val prompt = BiometricPrompt(activity, executor,15+            object : BiometricPrompt.AuthenticationCallback() {16+                override fun onAuthenticationSucceeded(17+                    result: BiometricPrompt.AuthenticationResult18+                ) {19+                    call.resolve(JSObject().put("verified", true))20+                }21+                override fun onAuthenticationError(code: Int, message: CharSequence) {22+                    call.reject("Biometric authentication failed: $message")23+                }24+                override fun onAuthenticationFailed() {25+                    call.reject("Biometric authentication failed")26+                }27+            }28+        )29+30+        val promptInfo = BiometricPrompt.PromptInfo.Builder()31+            .setTitle("Unlock Peach")32+            .setSubtitle("Use biometrics to access your vault")33+            .setNegativeButtonText("Use password instead")34+            .build()35+36+        prompt.authenticate(promptInfo)37+    }38+39+    @PluginMethod40+    fun isAvailable(call: PluginCall) {41+        val manager = androidx.biometric.BiometricManager.from(context)42+        val canAuthenticate = manager.canAuthenticate(43+            androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG44+        )45+        call.resolve(46+            JSObject().put(47+                "available",48+                canAuthenticate == androidx.biometric.BiometricManager.BIOMETRIC_SUCCESS49+            )50+        )51+    }52+}

view file

src/shared/biometric.ts+22 −0
@@ -0,0 +1,22 @@1+import { registerPlugin, Capacitor } from "@capacitor/core";2+3+const Biometric = registerPlugin<{4+  authenticate(): Promise<{ verified: boolean }>;5+  isAvailable(): Promise<{ available: boolean }>;6+}>("Biometric");7+8+export async function biometricUnlock(): Promise<boolean> {9+  if (!Capacitor.isNativePlatform()) return false;10+  try {11+    const result = await Biometric.authenticate();12+    return result.verified;13+  } catch {14+    return false;15+  }16+}17+18+export async function biometricAvailable(): Promise<boolean> {19+  if (!Capacitor.isNativePlatform()) return false;20+  const result = await Biometric.isAvailable();21+  return result.available;22+}

view file