Crash when a release build is run in R8 full mode
mikescamell opened this issue · 8 comments
Describe the problem
When running R8 in full mode (the upcoming default for Android Gradle Plugin 8) the app will crash on startup.
I believe that the SDK is missing some Proguard rules for Gson. See here.
What was the expected behavior?
No issues when running a release build with R8 full mode.
Reproduction
Run a release build with R8 full mode turned on
Caused by: 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.<init>(SourceFile:10)
at com.auth0.android.request.internal.Jwt$mapAdapter$1.<init>(Unknown Source:0)
at com.auth0.android.authentication.AuthenticationAPIClient.<init>(SourceFile:19)
Environment
- v2.9.0
- Gson
Hi @mikescamell Thanks for reporting this!
I can see this recommendation in R8 FAQs as well - https://r8.googlesource.com/r8/+/refs/heads/master/compatibility-faq.md#troubleshooting-gson-gson
But I am not able to reproduce this issue so that I can verify if the solution works. Can you update this sample to reproduce this issue.
Hey @poovamraj thanks for getting back to me :)
I tried my best to recreate this in the sample this morning but no luck, I will try a bit more later.
But I can confirm that without these rules in our proguard file and R8 full mode on, the app will crash with the same exception.
# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
Seeing as R8 full mode is now the default in AGP 8 I imagine you might get more reports in future 😬
And it seems like you had a similar report here already
@mikescamell can you share the snippet that you use that is causing the crash?
I totally agree that current configuration can lead to exception. I just want to understand fully about the issue before fixing it. Reaching out in the other thread as well.
@mikescamell can you also ensure the project is using same Android Studio, AGP and other build tools with the same version as yours? You can share it here and I can check it out as well.
@mikescamell can you also ensure the project is using same Android Studio, AGP and other build tools with the same version as yours? You can share it here and I can check it out as well.
We're using:
- Android Studio Flamingo
- AGP 8.0.0
- JDK 17
I can reproduce it in the Blinkist app but not the Sample app you mentioned, which is kinda strange 🤔 Maybe our implementation using the Auth0 SDK is a bit more involved than the sample app, so R8 can strip the code out of the sample with no issues.
Exactly, that's why I was wondering whether you could share your code snippet on how you use it.
Exactly, that's why I was wondering whether you could share your code snippet on how you use it.
Ok here's our Service class that we use within the app.
class Auth0Service @AssistedInject constructor(
@Assisted private val context: Context,
@ApiEndpoint private val apiEndpoint: String,
) {
interface Callback {
fun onSuccess(email: String, accessToken: String)
fun onFailure(code: String, description: String)
}
@AssistedFactory
interface Factory {
fun create(context: Context): Auth0Service
}
private val auth0Account = Auth0(context)
private val authentication = AuthenticationAPIClient(auth0Account)
private val storage = SharedPreferencesStorage(context)
private val manager = CredentialsManager(authentication, storage)
fun hasCredentials() = storage.retrieveString(ACCESS_TOKEN_KEY)?.isNotBlank() ?: false
fun hasValidCredentials() =
(storage.retrieveLong(EXPIRES_AT_KEY) ?: 0L) > System.currentTimeMillis()
suspend fun getCredentials() =
manager
.awaitCredentials()
.also { manager.saveCredentials(it) }
.accessToken
suspend fun login(): Auth0Credentials {
val customTabsOptions = CustomTabsOptions.newBuilder().showTitle(true).build()
val credentials =
WebAuthProvider
.login(auth0Account)
.withScheme("blkauth")
.withScope("openid email profile offline_access")
.withAudience(apiEndpoint.removeSuffix("/"))
.withCustomTabsOptions(customTabsOptions)
.await(context)
manager.saveCredentials(credentials)
return Auth0Credentials(credentials.user.email!!, credentials.accessToken)
}
fun clearCredentials() {
manager.clearCredentials()
}
}
Hi @mikescamell, we were not able to reproduce this but since it is recommended in the official documentation and wouldn't affect the functionality. We are going ahead with this.
Can you check out this PR and let us know if this fixes your issue - #652
We can follow up on the PR and we can close this issue.