devgianlu / librespot-android

A demo app that runs librespot-java on Android
33 stars 13 forks source link

Support for Android below version 8, API 24 #10

Closed funtax closed 3 years ago

funtax commented 3 years ago

Right now, for example java.util.Base64 is available on Android 8+, otherwise there will be an exception like this:

E/AndroidRuntime: FATAL EXCEPTION: Thread-2 Process: xyz.gianlu.librespot.android, PID: 15947 java.lang.NoClassDefFoundError: Failed resolution of: Ljava/util/Base64; at xyz.gianlu.librespot.common.Utils.toBase64(Utils.java:314) at xyz.gianlu.librespot.core.Session.authenticatePartial(Session.java:435) at xyz.gianlu.librespot.core.Session.authenticate(Session.java:333) at xyz.gianlu.librespot.core.Session.access$600(Session.java:75) at xyz.gianlu.librespot.core.Session$Builder.create(Session.java:1021) at xyz.gianlu.librespot.android.LoginActivity$LoginThread.run(LoginActivity.java:96) Caused by: java.lang.ClassNotFoundException: Didn't find class "java.util.Base64" on path: DexPathList[[zip file "/data/app/xyz.gianlu.librespot.android-1/base.apk"],nativeLibraryDirectories=[/data/app/xyz.gianlu.librespot.android-1/lib/arm, /data/app/xyz.gianlu.librespot.android-1/base.apk!/lib/armeabi-v7a, /system/lib, /vendor/lib]] at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)

We might need to find a workaround if we want to support older Android-versions.

https://stackoverflow.com/questions/47431337/base64-support-for-different-api-levels

funtax commented 3 years ago

Maybe we might use a 3rd-party-library in librespot-java, like this one to be compatible with all platforms? http://iharder.sourceforge.net/current/java/base64/

funtax commented 3 years ago

Or we could use a simple workaround inside the Utils-Class like:

try {
        Class.forName("java.util.Base64");
        ...
    } catch(ClassNotFoundException e) {
        Class.forName("android.util.Base64");
...
    }
funtax commented 3 years ago

I will try to send a PR for the Base64-stuff at librespot-java later.

funtax commented 3 years ago

I have changed librespot-java and am using the "Class.forName"-idea to not introduce another non-required dependency. It's now working on my Android 7 with tremolo-decoder. Will flash Android 6 on another device and check if it's working there too.

funtax commented 3 years ago

With the linked PR at librespot-java this is now working fine on my Android 7 with libtremolo. Will try it on even older versions.

funtax commented 3 years ago

Android 6 won't work, it for example crashes here:

public static void registerDecoder(@NotNull SuperAudioFormat format, @NotNull Class<? extends Decoder> clazz) {
      ((HashSet)decoders.computeIfAbsent(format, (key) -> {
          return new HashSet(5);
      })).add(clazz);
  }

Pretty sure it's not worth any effort.

@devgianlu I would leave it up to you if you merge my PR at librespot-java, then we seem to have support for Android 7+. Otherwise you could of course leave it as is and we have support for Android 8+.

devgianlu commented 3 years ago

Supporting Android 6 would require to remove all lambdas which is not something I am willing to do as it would significantly reduce the code quality. I think Android 7+ support is enough.

mitschwimmer commented 3 years ago

@devgianlu I agree that Android 7 is enough. But for the record, it should not be needed to remove lambdas etc. The Android Gradle Plugin >4 can do bytecode transformation for modules and 3rd party libraries. I have to work with Android 6 quite a bit and this feature is a lifesaver. In case you are curious: https://developer.android.com/studio/write/java8-support#library-desugaring

devgianlu commented 3 years ago

Oh wow, didn't know that existed. Is it enough to run everything properly or are there additional changes needed?

mitschwimmer commented 3 years ago

In our case updating the gradle config as in the documentation was all that was needed.

devgianlu commented 3 years ago

Nice, can you push that? Possibly lowering the min SDK if needed.

mitschwimmer commented 3 years ago

Sure, I will push to android-decoder as master is currently non functional due to changes in librespot-java. I will lower the API level to 23 if that works on my test device.

devgianlu commented 3 years ago

You need to tell Gradle to refetch the dependencies. It's a bit of a pain to get Android Studio to understand. You might need to invalidate cache and restart too.

mitschwimmer commented 3 years ago

I pushed to android-decoder. Master is broken due to "Decoders.replaceDecoder()" being changed in librespot-lib. Android Studio is a mess sometimes, but this time it is innocent :smile: API level 23 is now possible java syntax wise but it fails to display the player-controls on my device. Maybe you want to give it a go on your Android 6 device? I will not look further into it without anyone asking, enough Android 6 at work :wink:

devgianlu commented 3 years ago

I pushed to android-decoder. Master is broken due to "Decoders.replaceDecoder()" being changed in librespot-lib. Android Studio is a mess sometimes, but this time it is innocent 😄

Right, will be fixed when I merge #9.

API level 23 is now possible java syntax wise but it fails to display the player-controls on my device. Maybe you want to give it a go on your Android 6 device? I will not look further into it without anyone asking, enough Android 6 at work 😉

Will have a look.