Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 9, 2025

Tracked by https://github.com/warting/android-signaturepad/issues (minified build crash)

This PR...

Prevents ClassCastException / NullPointerException crashes in minified builds when restoring SignaturePad state after process death.

Considerations and implementation

The Event Parcelable class gets obfuscated by ProGuard/R8, causing Android's deserialization to fail in onRestoreInstanceState(). The fix adds a keep rule:

-keep class se.warting.signaturecore.Event { *; }

Changes:

  • Created signature-core/consumer-rules.pro with keep rule for Event class
  • Configured consumerProguardFiles("consumer-rules.pro") in signature-core/build.gradle.kts
  • Added matching rule to signature-core/proguard-rules.pro for consistency

The consumerProguardFiles configuration ensures the rule is automatically applied to consuming apps via the library AAR.

How to test

  1. Create a release build with minifyEnabled true
  2. Draw a signature on the pad
  3. Background the app and kill the process: adb shell am kill <package>
  4. Restore the app from recents
  5. Verify signature is restored without crash

Test(s) added

No tests added - this is a build configuration fix for ProGuard. The existing behavior (state restoration) already works in debug builds; this ensures it works in release builds.

Screenshots

Before After
N/A - crash prevented by ProGuard rules N/A - crash prevented by ProGuard rules

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • scans-in.gradle.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -Xmx4096m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant -cp /home/REDACTED/.gradle/wrapper/dists/gradle-8.14.1-bin/baw1sv0jfoi8rxs14qo3h49cs/gradle-8.14.1/lib/gradle-daemon-main-8.14.1.jar (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>App is crashing in minified build</issue_title>
<issue_description>App is crashing in minified build.
In emulator with Android 13 , app is crashing when app brought to foreground after process death.

To Reproduce
Steps to reproduce the behavior:

  1. Create emulator setting android Android 13 (Api 33)
  2. Create a release build setting minifyEnabled true
  3. Put signature
  4. Then put the app background
  5. kill the process by adb command. adb shell am kill your_package_name
  6. now bring back the app fore ground

Expected behavior
App should show restore the signature

Smartphone (please complete the following information):

  • Device: Emulator
  • OS: Android 13

Main cause of crash
java.lang.ClassCastException: Cannot cast [Lse.warting.signaturecore.Event; to android.os.Parcelable at java.lang.Class.cast(Class.java:4183)

Crash log
Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Class.isInterface()' on a null object reference
at java.lang.Class.isAssignableFrom(Class.java:589)
at android.os.Parcel.readParcelableCreatorInternal(Parcel.java:4900)
at android.os.Parcel.readParcelableInternal(Parcel.java:4807)
at android.os.Parcel.readParcelableArrayInternal(Parcel.java:5018)
at android.os.Parcel.readValue(Parcel.java:4645)
at android.os.Parcel.readValue(Parcel.java:4347)
at android.os.Parcel.-$$Nest$mreadValue()
at android.os.Parcel$LazyValue.apply(Parcel.java:4445)
at android.os.Parcel$LazyValue.apply(Parcel.java:4404)
at android.os.BaseBundle.getValueAt(BaseBundle.java:394)
at android.os.BaseBundle.getValue(BaseBundle.java:374)
at android.os.Bundle.getParcelableArray(Bundle.java:1020)
at se.warting.signatureview.views.SignaturePad.onRestoreInstanceState(SignaturePad.kt:66)
at android.view.View.dispatchRestoreInstanceState(View.java:21631)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:4007)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:4007)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:4007)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:4007)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:4007)
at android.view.View.restoreHierarchyState(View.java:21609)
at androidx.fragment.app.Fragment.restoreViewState(Fragment.java:703)
at androidx.fragment.app.Fragment.restoreViewState(Fragment.java:3181)
at androidx.fragment.app.Fragment.performActivityCreated(Fragment.java:3166)
at androidx.fragment.app.FragmentStateManager.activityCreated(FragmentStateManager.java:639)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:289)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:114)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1685)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3319)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3237)
at androidx.fragment.app.Fragment.performActivityCreated(Fragment.java:3167)
at androidx.fragment.app.FragmentStateManager.activityCreated(FragmentStateManager.java:639)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:289)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:114)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1685)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3319)
at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3237)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:263)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:350)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1543)
at android.app.Activity.performStart(Activity.java:8367)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3670)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:224)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:204)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2307)
at...


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI changed the title [WIP] Fix app crash in minified build for Android 13 Fix ProGuard obfuscation crash on state restoration after process death Dec 9, 2025
Copilot AI requested a review from warting December 9, 2025 12:51
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.

App is crashing in minified build

2 participants