optimizely / android-sdk

Android SDK for Optimizely Feature Experimentation and Optimizely Full Stack (legacy)
https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/android-sdk
Apache License 2.0
55 stars 39 forks source link

[BUG] R8 configuration breaks Gson use at runtime #489

Closed jamiesanson closed 1 month ago

jamiesanson commented 2 months ago

Is there an existing issue for this?

SDK Version

4.0.1

Current Behavior

When using the Optimizely SDK in release mode (minified by R8 in full mode), and deserializing a config object which contains JSON arrays, the SDK throws an exception:

java.lang.NoSuchMethodError: No virtual method iterator()Ljava/util/Iterator; in class Lorg/json/JSONArray; or its super classes (declaration of 'org.json.JSONArray' appears in /apex/com.android.art/javalib/core-libart.jar)
                                                                                                        at com.optimizely.ab.config.parser.JsonHelpers.jsonArrayToList(Unknown Source:5)
                                                                                                        at com.optimizely.ab.config.parser.JsonHelpers.jsonObjectToMap(Unknown Source:31)
                                                                                                        at com.optimizely.ab.config.parser.JsonConfigParser.fromJson(Unknown Source:13)
                                                                                                        at H3.a.a(Unknown Source:12)
                                                                                                        at com.optimizely.ab.Optimizely.getDecisionVariableMap(Unknown Source:105)
                                                                                                        at com.optimizely.ab.Optimizely.decide(Unknown Source:212)
                                                                                                        at J1.n.h(Unknown Source:85)
                                                                                                        at s.P.h(Unknown Source:79)
                                                                                                        at J1.n.h(Unknown Source:177)
                                                                                                        at q3.f.a(Unknown Source:14)
                                                                                                        at I.H.b(Unknown Source:94)
                                                                                                        at x2.q.r(Unknown Source:77)
                                                                                                        at x2.q.v(Unknown Source:21)
                                                                                                        at x2.q.d(Unknown Source:15)
                                                                                                        at q4.t.r(Unknown Source:253)
                                                                                                        at V3.a.n(Unknown Source:7)
                                                                                                        at m4.G.run(Unknown Source:114)
                                                                                                        at s4.a.run(Unknown Source:95)
                                                                                                        Suppressed: r4.f: [q0{Cancelling}@38dce49, Dispatchers.Main.immediate]

Expected Behavior

The SDK does not throw an exception.

Steps To Reproduce

  1. Create a config with a JSON value. That value should include a JSON array.
  2. Attempt to load this config in a minified Android app.
  3. Observe the exception.

Link

No response

Logs

No response

Severity

Affecting users

Workaround/Solution

We've done some digging, and realised the issue is arises due to a missing R8 rule.

Optimizely includes Gson as a runtime dependency for the purpose of deserializing Config. R8 keeps the Gson library, but minifies class names. Optimizely only chooses to use Gson if it can find the com.google.gson.Gson class, which is no longer called this. This causes the Optimizely Java SDK to fall back to org.json. Android includes a reimplementation of this dependency which is missing functionality the Java SDK relies on (having an Iterable implementation), causing the Optimizely SDK to crash at runtime.

The fix is to keep the name of the Gson class, such that the Java SDK is able to select the Gson-based config parser:

-keepnames class com.google.gson.Gson

Recent Change

No response

Conflicts

No response

jamiesanson commented 2 months ago

PR open to resolve this here: https://github.com/optimizely/android-sdk/pull/490

jaeopt commented 2 months ago

@jamiesanson Thanks for reporting and submitting a PR for the issue! We'll take a look.

muzahidul-opti commented 1 month ago

@jamiesanson really appreciated your support. Could you please sign in the CLA, so that we can approve your PR.

jamiesanson commented 1 month ago

Sure thing, signed!

muzahidul-opti commented 1 month ago

@jamiesanson the fix has been released with version 4.0.4. Thanks for your efforts.