Skip to content

Conversation

Copy link

Copilot AI commented Jan 12, 2026

The Android plugin crashes with NullPointerException when calling checkPermissions() in production builds. The root cause was ProGuard obfuscating the Capacitor plugin methods, preventing proper plugin initialization via reflection.

Root Cause

ProGuard was obfuscating methods annotated with @PluginMethod and @PermissionCallback. Since Capacitor uses reflection to invoke these methods, obfuscation caused the plugin to fail initialization, resulting in getPermissionState() returning null and triggering NullPointerException.

Changes

ProGuard Rules (Primary Fix)

Added ProGuard rules to prevent plugin method obfuscation:

# Keep Capacitor plugin classes and their methods
-keep class app.capgo.audiorecorder.** { *; }
-keepclassmembers class * extends com.getcapacitor.Plugin {
    @com.getcapacitor.annotation.PermissionCallback *;
    @com.getcapacitor.PluginMethod *;
}

# Keep plugin annotations
-keepattributes *Annotation*
-keepattributes Signature
-keepattributes Exceptions

Null Safety Checks (Defensive Programming)

Added null safety checks in four methods as a safety net:

  • toPermissionString(): Return "prompt" for null state (aligns with default case)
  • requestPermissions(): Check state is non-null before comparison
  • ensurePermission(): Check state is non-null before comparison
  • microphonePermissionStartCallback(): Check state is non-null before comparison
private String toPermissionString(PermissionState state) {
    if (state == null) {
        return "prompt";
    }
    switch (state) {
        case GRANTED: return "granted";
        // ...
    }
}

Solution Approach

This two-pronged approach ensures robustness:

  1. ProGuard rules fix the root cause by preventing obfuscation
  2. Null safety checks provide resilience even if ProGuard rules are misconfigured

The fix maintains backward compatibility while preventing crashes in production builds with ProGuard enabled.

Original prompt

This section details on the original issue you should resolve

<issue_title>bug: The app craches when calling checkPermissions() function with "java.lang.NullPointerException"</issue_title>
<issue_description>## Bug Report

Capacitor Version

Capacitor Doctor

Latest Dependencies:

@capacitor/cli: 8.0.0
@capacitor/core: 8.0.0
@capacitor/android: 8.0.0
@capacitor/ios: 8.0.0

Installed Dependencies:

@capacitor/ios: not installed
@capacitor/cli: 8.0.0
@capacitor/android: 8.0.0
@capacitor/core: 8.0.0

[success] Android looking great! 👌

Plugin Version

@capgo/[email protected]
Ok to proceed? (y) y


▲ 💊 Capgo Doctor 💊

● App Name: Taqvaylit

● App ID: io.ionic.taqvaylit

● App Version: 4.5

● Web Dir: ./dist

● OS: win32 Windows 10 Pro

● Node: v24.8.0

● Installed Dependencies:

● @capgo/cli: 7.68.1

● @capawesome/capacitor-android-edge-to-edge-support: 7.2.3

● @capgo/capacitor-audio-recorder: 8.0.4

◇ Latest Dependencies:

● @capgo/cli: 7.68.1

● @capawesome/capacitor-android-edge-to-edge-support: 8.0.2

● @capgo/capacitor-audio-recorder: 8.0.5

▲ 🚨 Some dependencies are not up to date
Error:
message: Some dependencies are not up to date
stack:

  • Error: Some dependencies are not up to date
  • at T2 (file:///C:/Users/Utilisateur/AppData/Local/npm-cache/_npx/cbe5d2f7487966de/node_modules/@capgo/cli/dist/index.js:240:11312)
    
  • at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
    
  • at async p$.<anonymous> (file:///C:/Users/Utilisateur/AppData/Local/npm-cache/_npx/cbe5d2f7487966de/node_modules/@capgo/cli/dist/index.js:448:130)
    
  • at async p$.parseAsync (file:///C:/Users/Utilisateur/AppData/Local/npm-cache/_npx/cbe5d2f7487966de/node_modules/@capgo/cli/dist/index.js:17:4255)
    

context(s)

ManualModel: false
AutoMode: false
CapgoCloud: false
OnPremise: false

Platform(s)

Android

Current Behavior

The app craches in production after requesting a record.
The app works well in dev

Expected Behavior

The app shouldn't crache when we start recording

Code Reproduction

here's the code that causes the issue:

const permStatus = await CapacitorAudioRecorder.checkPermissions();
console.log("Permission status:", permStatus);

if (permStatus.recordAudio !== "granted") {
  console.log("Requesting microphone permission...");
  const request = await CapacitorAudioRecorder.requestPermissions();
  console.log("Permission request result:", request);

  if (request.recordAudio !== "granted") {
    console.warn("Microphone permission denied");
   
    return; 
  }

here's the traceStack:

--------- beginning of crash
01-11 23:42:21.786 23661 23725 E AndroidRuntime: FATAL EXCEPTION: CapacitorPlugins
01-11 23:42:21.786 23661 23725 E AndroidRuntime: Process: io.ionic.taqvaylit, PID: 23661
01-11 23:42:21.786 23661 23725 E AndroidRuntime: java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
01-11 23:42:21.786 23661 23725 E AndroidRuntime: at com.getcapacitor.a.run(r8-map-id-3fe3359b78ef5b550c9f1d72a51fef057b0db10015f59f0d32d3352e1af5a31e:62)
01-11 23:42:21.786 23661 23725 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:938)
01-11 23:42:21.786 23661 23725 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:99)
01-11 23:42:21.786 23661 23725 E AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:226)
01-11 23:42:21.786 23661 23725 E AndroidRuntime: at android.os.Looper.loop(Looper.java:313)
01-11 23:42:21.786 23661 23725 E AndroidRuntime: at android.os.HandlerThread.run(HandlerThread.java:67)
01-11 23:42:21.786 23661 23725 E AndroidRuntime: Caused by: java.lang.reflect.InvocationTargetException
01-11 23:42:21.786 23661 23725 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
01-11 23:42:21.786 23661 23725 E AndroidRuntime: at com.getcapacitor.F.a(r8-map-id-3fe3359b78ef5b550c9f1d72a51fef057b0db10015f59f0d32d3352e1af5a31e:26)
01-11 23:42:21.786 23661 23725 E AndroidRuntime: at com.getcapacitor.a.run(r8-map-id-3fe3359b78ef5b550c9f1d72a51fef057b0db1...


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@coderabbitai
Copy link

coderabbitai bot commented Jan 12, 2026

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copilot AI changed the title [WIP] Fix NullPointerException in checkPermissions() function Fix NullPointerException in checkPermissions() on Android Jan 12, 2026
Copilot AI requested a review from riderx January 12, 2026 11:14
@riderx
Copy link
Member

riderx commented Jan 15, 2026

@copilot check the last message it seems jt was proguard issue

Copy link
Author

Copilot AI commented Jan 15, 2026

@copilot check the last message it seems jt was proguard issue

You're right! Added ProGuard rules to prevent plugin method obfuscation in commit dd8049b. The rules keep the plugin classes and annotated methods from being obfuscated, which was causing the NullPointerException when Capacitor tried to call the methods via reflection. The null safety checks remain as defensive programming.

Copilot AI changed the title Fix NullPointerException in checkPermissions() on Android Fix NullPointerException in checkPermissions() caused by ProGuard obfuscation Jan 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: The app craches when calling checkPermissions() function with "java.lang.NullPointerException"

2 participants