RevenueCat/purchases-kmp

java.lang.ClassCastException: android.net.Uri$StringUri cannot be cast to java.lang.String

Closed this issue · 4 comments

Similar to #48, I get an exception when trying to use public expect val CustomerInfo.managementURL: String?.

This is with:
Kotlin version 1.9.21
Compose version 1.5.11

See simplified example below:

data class ManagementUrl(val url: String)

PurchasesFactory.sharedInstance.awaitCustomerInfo().let { customerInfo ->
    **val url: String? = customerInfo.managementURL** // This is where the crash happens
    ManagementUrl(url)
}

For whatever reason, adding identical expect/actual implementations with a slightly different name works.

expect val CustomerInfo.managementURLString: String?

actual val CustomerInfo.managementURLString: String?
    get() = managementURL?.toString()

Thanks for flagging this! What kind of exception are you getting? Do you have a stacktrace?

Edit: I just saw the issue title. It's a ClassCastException. Which Android version are you seeing this on? And what is your compileApi? I think that might help with reproduction.

Ah, my bad. val url: String? = customerInfo.managementURL **as String?** crashes on both API 34 and 28.

If I remove as String? I get a compile time error instead saying Type mismatch: inferred type is Uri? but String? was expected. So it seems like it's looking at the RevenueCat SDK Android implementation of CustomerInfo.managementUrl, which is the one returning a URI?.

Thanks, your analysis seems very plausible! I'll have to make sure that the Android implementation returns a String instead of a Uri.

I managed to reproduce it as part of #56, which will be run on CI to prevent regressions once that is merged.

I also have an idea what's going wrong. The extension shadows the official SDK implementation, i.e. has the same name. The compiler seems to be picking that one, which returns a Uri. It then throws a type error because the field is defined as a String. That's also why your workaround of adding identical expect/actual implementations with a slightly different name works. The name is exactly the issue :)

Will see what the most elegant fix is for this. (And see if there's even any other option than simply renaming the extension.)