adaptyteam / AdaptySDK-React-Native

React Native SDK for growing in-app subscriptions
https://docs.adapty.io/docs/quickstart
MIT License
128 stars 12 forks source link

TypeToken must be created with a type argument: new TypeToken<...>() {}; When using code shrinkers (ProGuard, R8, ...) make sure that generic signatures are preserved. #117

Closed SergiOnGit closed 5 months ago

SergiOnGit commented 7 months ago

Description

App crashes on production and firebase logs this error:

Fatal Exception: java.lang.IllegalStateException: TypeToken must be created with a type argument: new TypeToken<...>() {}; When using code shrinkers (ProGuard, R8, ...) make sure that generic signatures are preserved. at com.google.gson.reflect.TypeToken.getTypeTokenTypeArgument(TypeToken.java:100) at com.google.gson.reflect.TypeToken.<init>(TypeToken.java:70) at com.adapty.internal.di.Dependencies$init$1$1.<init>(Dependencies.kt:137) at com.adapty.internal.di.Dependencies$init$1.invoke(Dependencies.kt:137) at com.adapty.internal.di.Dependencies$init$1.invoke(Dependencies.kt:56) at com.adapty.internal.di.DIObject.provide(DIObject.kt:19) at com.adapty.internal.di.Dependencies.injectInternal$default(Dependencies.java:35) at com.adapty.internal.di.Dependencies$init$17.invoke(Dependencies.kt:287) at com.adapty.internal.di.Dependencies$init$17.invoke(Dependencies.kt:286) at com.adapty.internal.di.DIObject.provide(DIObject.kt:19) at com.adapty.internal.di.Dependencies.injectInternal$default(Dependencies.java:35) at com.adapty.internal.di.Dependencies$init$15.invoke(Dependencies.kt:272) at com.adapty.internal.di.Dependencies$init$15.invoke(Dependencies.kt:270) at com.adapty.internal.di.DIObject.provide(DIObject.kt:19) at com.adapty.internal.di.Dependencies.injectInternal$default(Dependencies.java:35) at com.adapty.internal.di.Dependencies$init$7.invoke(Dependencies.kt:217) at com.adapty.internal.di.Dependencies$init$7.invoke(Dependencies.kt:214) at com.adapty.internal.di.DIObject.provide(DIObject.kt:19) at com.adapty.internal.di.Dependencies.injectInternal$default(Dependencies.java:35) at com.adapty.internal.di.Dependencies$init$5.invoke(Dependencies.kt:200) at com.adapty.internal.di.Dependencies$init$5.invoke(Dependencies.kt:198) at com.adapty.internal.di.DIObject.provide(DIObject.kt:19) at com.adapty.internal.di.Dependencies.injectInternal$default(Dependencies.java:35) at com.adapty.internal.di.Dependencies$init$47.invoke(Dependencies.kt:446) at com.adapty.internal.di.Dependencies$init$47.invoke(Dependencies.kt:444) at com.adapty.internal.di.DIObject.provide(DIObject.kt:19) at com.adapty.internal.di.Dependencies.injectInternal$default(Dependencies.java:35) at com.adapty.internal.di.Dependencies$init$48.invoke(Dependencies.kt:458) at com.adapty.internal.di.Dependencies$init$48.invoke(Dependencies.kt:456) at com.adapty.internal.di.DIObject.provide(DIObject.kt:19) at com.adapty.internal.di.Dependencies.injectInternal$default(Dependencies.java:35) at com.adapty.Adapty$special$$inlined$inject$adapty_release$default$1.invoke(Dependencies.kt:31) at kotlin.UnsafeLazyImpl.getValue(Lazy.kt:81) at com.adapty.Adapty.<clinit>(Adapty.kt:500) at com.adapty.Adapty.getAdaptyInternal(Adapty.kt:500) at com.adapty.Adapty.init(Adapty.kt:520) at com.adapty.Adapty.activate(Adapty.kt:64) at com.adapty.react.AdaptyCallHandler.handleActivate$lambda$1(AdaptyCallHandler.kt:64) at android.os.Handler.handleCallback(Handler.java:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7680) at java.lang.reflect.Method.invokeNative(Method.java) at java.lang.reflect.Method.invoke(Method.java:423) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

At first, I could even build in production mode, I tried playing with proguard rules but no luck, then installed @adapty/react-native-ui lib and build went soccessfully, It is really bad that we have to install @adapty/react-native-ui even if we don't use it. Also docs doesn't say anything about it. After this I tried to open app, but crashed at startup.

Version

v2.10.0

What platforms are you seeing the problem on?

Android

System info

System:
  OS: macOS 14.4.1
  CPU: (11) arm64 Apple M3 Pro
  Memory: 102.56 MB / 18.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 20.11.0
    path: ~/.nvm/versions/node/v20.11.0/bin/node
  Yarn:
    version: 1.22.21
    path: ~/.nvm/versions/node/v20.11.0/bin/yarn
  npm:
    version: 10.2.4
    path: ~/.nvm/versions/node/v20.11.0/bin/npm
  Watchman:
    version: 2024.01.22.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods:
    version: 1.15.2
    path: /Users/warlock/.rbenv/shims/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 23.4
      - iOS 17.4
      - macOS 14.4
      - tvOS 17.4
      - visionOS 1.1
      - watchOS 10.4
  Android SDK:
    API Levels:
      - "33"
      - "34"
    Build Tools:
      - 30.0.3
      - 33.0.0
      - 33.0.1
      - 34.0.0
    System Images:
      - android-33 | Google APIs ARM 64 v8a
      - android-34 | Google APIs ARM 64 v8a
      - android-34 | Google Play ARM 64 v8a
    Android NDK: Not Found
IDEs:
  Android Studio: 2023.1 AI-231.9392.1.2311.11330709
  Xcode:
    version: 15.3/15E204a
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.10
    path: /usr/bin/javac
  Ruby:
    version: 2.7.6
    path: /Users/warlock/.rbenv/shims/ruby
npmPackages:
  "@react-native-community/cli": Not Found
  react:
    installed: 18.2.0
    wanted: 18.2.0
  react-native:
    installed: 0.73.6
    wanted: 0.73.6
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: false
iOS:
  hermesEnabled: true
  newArchEnabled: false
vladd-g commented 7 months ago

hi @SergiOnGit!

It is really bad that we have to install @adapty/react-native-ui even if we don't use it

No, you don't have to.

vladd-g commented 7 months ago

@SergiOnGit what rules do you currently have in the proguard config?

SergiOnGit commented 7 months ago

@vladd-g I had -keep class com.adapty.* { ; } in proguard, Then I removed it and fixed with android.enableR8.fullMode=false in gradle.properties. But what is correct solution? I don't want to have ui lib installed. Also you don't mention anything in docs about proguard. Guide me please.

vladd-g commented 7 months ago

@SergiOnGit

Then I removed it and fixed with android.enableR8.fullMode=false

Do you mean it works well now?

I don't want to have ui lib installed

You can simply remove the @adapty/react-native-ui dependency if you don't use the Paywall Builder feature

I don't want to have ui lib installed. Also you don't mention anything in docs about proguard.

Actually, only -keep class com.adapty.** { *; } is sufficient in most cases. If disabling full mode prevented obfuscation-related crashes, that's okay too. We'll check and add all the necessary info to the docs if anything is missing. Thank you!

SergiOnGit commented 7 months ago

Yes it works now. So I can remove ui module and should add -keep class com.adapty.* { ; } rule to proguard. And should leave full mode disabled right? Would be great if you add all the necessary info in docs. Also cases where app may still crash with possible fix.

vladd-g commented 7 months ago

Yes it works now. So I can remove ui module and should add -keep class com.adapty.* { ; } rule to proguard. And should leave full mode disabled right?

If everything works fine, why not

SergiOnGit commented 7 months ago

@vladd-g I added -keep class com.adapty.* { ; } and removed ui lib. Also leave full mode disabled and now build fails. See the log:

ERROR: Missing classes detected while running R8. Please add the missing classes or apply additional keep rules that are generated in /Users/warlock/Desktop/Mobile/movebody/android/app/build/outputs/mapping/release/missing_rules.txt. ERROR: R8: Missing class com.adapty.ui.AdaptyUI$Action$Close (referenced from: void com.adapty.internal.crossplatform.AdaptyUIActionTypeAdapterFactory$create$result$1.write(com.google.gson.stream.JsonWriter, com.adapty.ui.AdaptyUI$Action)) Missing class com.adapty.ui.AdaptyUI$Action$Custom (referenced from: void com.adapty.internal.crossplatform.AdaptyUIActionTypeAdapterFactory$create$result$1.write(com.google.gson.stream.JsonWriter, com.adapty.ui.AdaptyUI$Action)) Missing class com.adapty.ui.AdaptyUI$Action$OpenUrl (referenced from: void com.adapty.internal.crossplatform.AdaptyUIActionTypeAdapterFactory$create$result$1.write(com.google.gson.stream.JsonWriter, com.adapty.ui.AdaptyUI$Action)) Missing class com.adapty.ui.AdaptyUI$Action (referenced from: com.adapty.ui.AdaptyUI$Action com.adapty.internal.crossplatform.AdaptyUIActionTypeAdapterFactory$create$result$1.read(com.google.gson.stream.JsonReader) and 3 other contexts)

vladd-g commented 7 months ago

@SergiOnGit please try adding -dontwarn com.adapty.ui.** to the proguard rules

SergiOnGit commented 7 months ago

-dontwarn com.adapty.ui. made it work, But only after I removed -keep class com.adapty. { *; }

Also, I know you have mentioned in docs to add multidex true but I removed it and it still works. Should I expect errors on some stage with disabled multidex?

vladd-g commented 7 months ago

But only after I removed -keep class com.adapty.* { ; }

What was the error before you removed it?

Should I expect errors on some stage with disabled multidex?

If it compiled with success, you don't need it

Unlike obfuscation issues that can occur at runtime, so I'd try keeping -keep class com.adapty.** { *; }

SergiOnGit commented 7 months ago

I managed to figure it out. This two rule together

-keep class com.adapty.** { *; } -dontwarn com.adapty.ui.**

Works when I removed android.enableR8.fullMode=false No matter if you enable multidex or not.

Also no need to install ui lib. Looks like, it just needed correct proguard rules. App builds and starts.

SergiOnGit commented 7 months ago

Looks like I made a mistake, android.enableR8.fullMode=false is still needed, without it app startup ends with error:

Fatal Exception: java.lang.IllegalStateException: TypeToken must be created with a type argument: new TypeToken<...>() {}; When using code shrinkers (ProGuard, R8, ...) make sure that generic signatures are preserved. at com.google.gson.reflect.TypeToken.getTypeTokenTypeArgument(TypeToken.java:100) at com.google.gson.reflect.TypeToken.<init>(TypeToken.java:70)...

vladd-g commented 7 months ago

This two rule together

-keep class com.adapty.** { *; } -dontwarn com.adapty.ui.**

Works when I removed android.enableR8.fullMode=false

What error did you see before removing android.enableR8.fullMode=false?

SergiOnGit commented 7 months ago

This two rule together -keep class com.adapty.** { *; } -dontwarn com.adapty.ui.** Works when I removed android.enableR8.fullMode=false

What error did you see before removing android.enableR8.fullMode=false?

I don't clearly understand what you mean before removing, I I don't remove it, there is no error app works with this configs:

-keep class com.adapty.** { *; }
-dontwarn com.adapty.ui.**
android.enableR8.fullMode=false

But I noticed that disabling full mode increases app size dramatically, 21mb app download size is 56mb on play store. Can you fix it for full mode? Without it, app starts at startup with this log:

Fatal Exception: java.lang.IllegalStateException: TypeToken must be created with a type argument: new TypeToken<...>() {}; When using code shrinkers (ProGuard, R8, ...) make sure that generic signatures are preserved. at com.google.gson.reflect.TypeToken.getTypeTokenTypeArgument(TypeToken.java:100) at com.google.gson.reflect.TypeToken.<init>(TypeToken.java:70)...

Let me know if you need any additional info.

vladd-g commented 7 months ago

Could you please try adding these rules? (If they are not sufficient for correct functioning, also add these)

SergiOnGit commented 7 months ago

@vladd-g Checked. These rules made it work without disabling full mode

-keep class com.adapty.** { *; }
-dontwarn com.adapty.ui.**
-keepattributes Signature
-keep class com.google.gson.reflect.TypeToken { *; }
-keep class * extends com.google.gson.reflect.TypeToken
vladd-g commented 6 months ago

@SergiOnGit, so now everything works fine?

SergiOnGit commented 5 months ago

@vladd-g Sorry for late reply. Yes, everything works fine.