diff --git a/android/app/src/main/java/com/PlushLife/MainActivity.java b/android/app/src/main/java/com/PlushLife/MainActivity.java index 4496815..20cae72 100644 --- a/android/app/src/main/java/com/PlushLife/MainActivity.java +++ b/android/app/src/main/java/com/PlushLife/MainActivity.java @@ -29,6 +29,7 @@ public class MainActivity extends BridgeActivity { public void onCreate(Bundle savedInstanceState) { EdgeToEdge.enable(this); registerPlugin(WidgetBridgePlugin.class); + registerPlugin(NotificationPermissionPlugin.class); super.onCreate(savedInstanceState); checkForUpdate(); } diff --git a/android/app/src/main/java/com/PlushLife/NotificationPermissionPlugin.java b/android/app/src/main/java/com/PlushLife/NotificationPermissionPlugin.java new file mode 100644 index 0000000..9f29223 --- /dev/null +++ b/android/app/src/main/java/com/PlushLife/NotificationPermissionPlugin.java @@ -0,0 +1,54 @@ +package com.PlushLife; + +import android.Manifest; +import android.os.Build; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import com.getcapacitor.JSObject; +import com.getcapacitor.Plugin; +import com.getcapacitor.PluginCall; +import com.getcapacitor.PluginMethod; +import com.getcapacitor.annotation.CapacitorPlugin; + +// Requests POST_NOTIFICATIONS directly with Android's own permission API, +// bypassing @capacitor/push-notifications' requestPermissions() — which +// routes through Bridge.getPermissionStates(), a Capacitor core method with +// an open, unfixed upstream bug (ionic-team/capacitor#8400) that throws a +// NullPointerException and crashes the whole app. Confirmed via Crashlytics +// stack traces on real releases, not just suspected. +@CapacitorPlugin(name = "NotificationPermission") +public class NotificationPermissionPlugin extends Plugin { + private PluginCall pendingCall; + private ActivityResultLauncher requestLauncher; + + @Override + protected void load() { + // Runs during the Bridge's own onCreate-time setup, so this is well + // before the activity reaches STARTED — same timing rule as any + // registerForActivityResult call. + requestLauncher = getActivity().registerForActivityResult( + new ActivityResultContracts.RequestPermission(), + granted -> { + if (pendingCall != null) { + JSObject result = new JSObject(); + result.put("granted", granted); + pendingCall.resolve(result); + pendingCall = null; + } + } + ); + } + + @PluginMethod + public void requestPostNotifications(PluginCall call) { + // Not a runtime permission before Android 13 — nothing to request. + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { + JSObject result = new JSObject(); + result.put("granted", true); + call.resolve(result); + return; + } + pendingCall = call; + requestLauncher.launch(Manifest.permission.POST_NOTIFICATIONS); + } +} diff --git a/index.html b/index.html index bdbf2e1..fa6efb2 100644 --- a/index.html +++ b/index.html @@ -20,6 +20,11 @@ PlushLife