Closed green985 closed 9 months ago
Update
I change version to 2.0.5 (first android support) and library worked. I don't know why.
Thanks and have a great day.
Thanks for the issue! As far as I understand, 2.2.4 did not work for you (see above), but 2.0.5 worked? In the background I upgraded the used REST library.
I guess the Android environment needs a different approach.
Yeah, you are right. 2.0.5 work no smoothly (have a different bug) but not bad as 2.2.4
Am I open another issue for this (different bug) or wait you for another release ?
Well, this seems to be a more conceptual problem of the library that needs to be worked out, not a simple bug :-(. I find it important to document the problems, but don't expect a solution (before a major release).
As noted in other issues before, it could be possible to get around the ClassNotFoundException if you take the not-found classes out of the Android-build typical obfuscation (see #13 ).
Take a look here: https://developer.android.com/studio/build/shrink-code#keep-code
Yeah, but I work in debug project and not implement proguard or shrink code etc. But I will try and share result in this thread.
Other bug, just list map bug, duplicated key problem. It's nothing compare with that and also just exception when try to get country list.
I can still use library in 2.0.5 version and It's seem to be fine for me.
"Provider for jakarta.ws.rs.client.ClientBuilder cannot be found" looks like there are some /META-INF/services/
files stripped out by the android packaging. I think the file in question will be a text file in the archive named /META-INF/services/jakarta.ws.rs.client.ClientBuilder
. If you can put it there, we'll proceed one step.
Hi again, I try your advice but I think nothing change.
exclude 'META-INF/services/jakarta.ws.rs.client.ClientBuilder'
or maybe I do wrong way, I am not familiar with packagingOptions blocks. This line affect nothing, some exception still.
Excludes is the opposite you're wanting:
The set of excluded patterns. Java resources matching any of these patterns do not get packaged in the APK.
I am not used to the resources packaging options myself, sorry.
Yeah, I try all tags for packagingOptions and no result.
Maybe, some of people can guide us. Until that day, I will continue with old library I think.
"Provider for jakarta.ws.rs.client.ClientBuilder cannot be found" looks like there are some
/META-INF/services/
files stripped out by the android packaging. I think the file in question will be a text file in the archive named/META-INF/services/jakarta.ws.rs.client.ClientBuilder
. If you can put it there, we'll proceed one step.
I tried to use 2.2.4. Does not work with the same Provider not found problem. And, no, these directory and files are NOT stripped. There is the list of APK META-INF/services directory
com.fasterxml.jackson.core.JsonFactory com.fasterxml.jackson.core.ObjectCodec com.fasterxml.jackson.databind.Module jakarta.ws.rs.client.ClientBuilder jakarta.ws.rs.ext.RuntimeDelegate jakarta.xml.bind.JAXBContext kotlinx.coroutines.CoroutineExceptionHandler kotlinx.coroutines.internal.MainDispatcherFactory org.glassfish.hk2.extension.ServiceLocatorGenerator org.glassfish.jersey.internal.inject.InjectionManagerFactory org.glassfish.jersey.internal.spi.AutoDiscoverable
I am having the same issue. Even with a simple sample application in Android. I am not an expert on gradle, pro-guard, etc. I think best is you download it an try to find out what the problem is.
@mraalex thanks for the archive ... I'm not managing to import it to Android Studio, it is saying "Error: Module not specified". In Android studios "Edit configuration" dialogue I can't select a module, but I'd guess I would need to select "app". The stackoverflow posts dealing with this topic don't help. On command line I can gradle build it, but this I need to debug it in Android Studio to get a clue.
Is there a way to provide a example without another subproject which seems to confuse gradle / android studio?
Anyone having a quick hint?
Tap on "Build Variants" on the left and make sure that Module:app is set on the debug version: playStoreFreeDebug
I am using: Android Studio Electric Eel | 2022.1.1 Patch 1 Runtime version: 11.0.15+0-b2043.56-9505619 amd64
If it still does not work you can also create a new project with your Android Studio, integrate the code and see if it is running on your side. Then send me the project.
The Android mystery is solved, thanks to your help, guys! Thanks @mraalex and all other guys for the suggestions.
There needs to be some tweaking to make it run on Android. I am listing them in the following link:
https://github.com/sfuhrm/radiobrowser4j/blob/master/ANDROID.md
A demo printing radio stations to a full-screen-view is given in the following TAR ball:
Just came across these same issues with de.sfuhrm:radiobrowser4j:2.5.0
The "fix" relies on turning off codee shrink, minifyEnabled false
My app now bloats to over 2x the size :-(
Is there a way to use this library without turning off minify ?
I had no minify enabled. The solution from shuhrm worked for me, even with minify.
Hmm, interesting, as the demo app linked above has minifyEnabled false, and yes it does build (using both 2.2.5 and 2.5.0), however Proguard is doing very little. if you set minifyEnabled true, it will fail to build. Adding the suggested warnings ignores to proguard-rules.pro it will then build, however using signed release builds will result in runtime crashes.
Adding the suggested keep classes, brings in even more warnings to exclude, and at this point, it's quite a away from looking like it can compile.
Wondering if anyone has a working Proguard they can share for someone that's using minifyEnabled true
I have tested my signed release build. It works fine with minifyEnabled.
Pro-Guard: -keep class org.glassfish.hk2.utilities. { *; } -keep class org.glassfish.jersey.* { ; } -keep class org.jvnet.hk2.internal. { *; } -keep class de.sfuhrm.radiobrowser4j.* { ; }
build.gradle:
android.packagingOptions.resources.excludes += "*/.md" android.packagingOptions.resources.excludes += "*/.markdown" dependencies { implementation 'de.sfuhrm:radiobrowser4j:2.3.1'; implementation 'org.osgi:org.osgi.framework:1.10.0'; }
code: don't forget to set System property; System.setProperty("jakarta.ws.rs.client.ClientBuilder", "org.glassfish.jersey.client.JerseyClientBuilder"); browser = new RadioBrowser(5000, "Demo agent/1.0");
Is that the app linked above? https://github.com/sfuhrm/radiobrowser4j/issues/14#issuecomment-1625387804
no. It is from another project. Did you try the official sample project from the readme for Android?
Using the project in comment #14 (which has all the suggested changes in this thread), both the minified and regular builds will compile, however the minified build crashes when launched.
Process: com.changemystyle.gentlewakeup, PID: 26798 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.changemystyle.gentlewakeup/com.changemystyle.gentlewakeup.FullscreenActivity}: java.lang.RuntimeException: java.lang.ClassNotFoundException: Provider for jakarta.ws.rs.client.ClientBuilder cannot be found
The only change I made was to change minifyEnabled true
This is where I am, using the exact same config.
Missing class jakarta.validation.MessageInterpolator$Context (referenced from: void org.glassfish.hk2.utilities.general.internal.MessageInterpolatorImpl$ContextResourceBundle.
You are not using the correct sample project. Package com.changemystyle.gentlewakeup is a non-working sample from me.
The official sample project is here: A demo printing radio stations to a full-screen-view is given in the following TAR ball:
radiobrowser4j-android-demo.tar.gz
You should continue from this project and if any issues, integrate the code lines I posted.
Using the project in comment #14 (which has all the suggested changes in this thread), both the minified and regular builds will compile, however the minified build crashes when launched.
Process: com.changemystyle.gentlewakeup, PID: 26798 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.changemystyle.gentlewakeup/com.changemystyle.gentlewakeup.FullscreenActivity}: java.lang.RuntimeException: java.lang.ClassNotFoundException: Provider for jakarta.ws.rs.client.ClientBuilder cannot be found
The only change I made was to change minifyEnabled true
Perhaps I am missing something obvious here, and that project doesn't build with minifyEnabled true as it's got an empty Proguard file.
Adding the proguard entries you mention (with typos fixes), results in the same errors I am seeing.
-keep class org.glassfish.hk2.utilities.** { *; }
-keep class org.glassfish.jersey.** { *; }
-keep class org.jvnet.hk2.internal.** { *; }
-keep class de.sfuhrm.radiobrowser4j.** { *; }
EDIT; perhaps not typos, but Markdown doing weird things. Added what I am using to a code block.
I am on holidays know for one week. Maybe sfuhrm can help you. I am just a user of the lib. If I come back and you have no solution I can take a look.
Had another look at this today, I got something working, with a less aggressive ruleset, (i have only tested voteForStation, listStations, listStations, listStationsBy API calls), however it's working in a shrunk and obfuscated build.
This is my reasonably optimised, working Proguard config, tested against radiobrowser4j 2.5.2, gradle 8.10, Android Studio Giraffe | 2022.3.1 using Java development and Java 1.8 language level.
-keep class org.glassfish.jersey.** { *; }
-keep class org.glassfish.hk2.** { *; }
-keep class org.jvnet.hk2.** { *; }
-keep class de.sfuhrm.radiobrowser4j.** { *; }
-keep class jakarta.inject** { *; }
-keep class jakarta.ws.rs.core** { *; }
-dontwarn jakarta.validation**
-dontwarn java.awt.image**
-dontwarn java.beans.Introspector**
-dontwarn javax.imageio**
-dontwarn javax.xml.stream**
-dontwarn lombok**
-dontwarn java.lang.Module**
-dontwarn java.lang.reflect**
-dontwarn org.glassfish.jersey.server**
-dontwarn org.hibernate.validator**
-dontwarn com.fasterxml.jackson.module.jaxb**
-dontwarn javax.activation**
-dontwarn org.osgi.annotation.versioning**
-dontwarn sun.misc.Contended*
I found this useful. Upload a regular build that's not been through ProGuard and play around in realtime with the ruleset.
Hi guys,
I'm reopening the issue since there are open questions regarding proguard.
In the background the library is using Jersey Client which is using Jackson and JAXB, just to mention the bigger dependencies. It is failry ok to think that this amount of dependencies is not suited for an embedded target like Android.
I have no ready list of classes that need to be defined as exceptions to proguard so everything is working. One strategy that might work is to turn on verbose class loading (don't know whether Android has that) and then only include the classes from this list. But it is probably a quite time consuming task.
@fourofspades does your definition work for you? Does it make sense to already add it to the Android guide?
Stephan
I have renamed this issue to "Android related questions" since it collects many good pointers for Android.
Yes, done a fair amount of testing today and it's working well for me.
I guess the only open question is why the shorter configuration worked for some but not for me...
On Sun, 16 Jul 2023, 16:44 Stephan Fuhrmann, @.***> wrote:
Hi guys,
I'm reopening the issue since there are open questions regarding proguard.
In the background the library is using Jersey Client which is using Jackson and JAXB, just to mention the bigger dependencies. It is failry ok to think that this amount of dependencies is not suited for an embedded target like Android.
I have no ready list of classes that need to be defined as exceptions to proguard so everything is working. One strategy that might work is to turn on verbose class loading (don't know whether Android has that) and then only include the classes from this list. But it is probably a quite time consuming task.
@fourofspades https://github.com/fourofspades does your definition work for you? Does it make sense to already add it to the Android guide https://github.com/sfuhrm/radiobrowser4j/blob/master/ANDROID.md?
Stephan
— Reply to this email directly, view it on GitHub https://github.com/sfuhrm/radiobrowser4j/issues/14#issuecomment-1637123394, or unsubscribe https://github.com/notifications/unsubscribe-auth/AOVZNJHF4ZGT47GVBYSCKETXQQD4PANCNFSM6AAAAAAR32ACHM . You are receiving this because you were mentioned.Message ID: @.***>
Updated to 2.5.2 and tested the Proguard, tested voting and searching API. it needed a rule tweak, which I changed in the comments above, and I also detailed the exact setup I am using.
Had some crashes from users running my app in the wild, using the radiobrowser code on Android. It's not obfuscation related, as it happens in debug on the android emulator. Reverting to 2.5.0 fixes the issue.
Interesting, it's only older devices that have this issue. Most of my bug reports come from Android 7.0 era.
Stack trace:
`
java.lang.NoSuchMethodError: No virtual method getParameterCount()I in class Ljava/lang/reflect/Constructor; or its super classes (declaration of 'java.lang.reflect.Constructor' appears in /system/framework/core-oj.jar)
at com.fasterxml.jackson.databind.util.ClassUtil$Ctor.getParamCount(ClassUtil.java:1450)
at com.fasterxml.jackson.databind.introspect.AnnotatedCreatorCollector._findPotentialConstructors(AnnotatedCreatorCollector.java:120)
at com.fasterxml.jackson.databind.introspect.AnnotatedCreatorCollector.collect(AnnotatedCreatorCollector.java:70)
at com.fasterxml.jackson.databind.introspect.AnnotatedCreatorCollector.collectCreators(AnnotatedCreatorCollector.java:61)
at com.fasterxml.jackson.databind.introspect.AnnotatedClass._creators(AnnotatedClass.java:403)
at com.fasterxml.jackson.databind.introspect.AnnotatedClass.getConstructors(AnnotatedClass.java:308)
at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector._addCreators(POJOPropertiesCollector.java:613)
at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.collectAll(POJOPropertiesCollector.java:426)
at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getPropertyMap(POJOPropertiesCollector.java:386)
at com.fasterxml.jackson.databind.introspect.POJOPropertiesCollector.getProperties(POJOPropertiesCollector.java:233)
at com.fasterxml.jackson.databind.introspect.BasicBeanDescription._properties(BasicBeanDescription.java:164)
at com.fasterxml.jackson.databind.introspect.BasicBeanDescription.findProperties(BasicBeanDescription.java:239)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._findCreatorsFromProperties(BasicDeserializerFactory.java:328)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._constructDefaultValueInstantiator(BasicDeserializerFactory.java:272)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findValueInstantiator(BasicDeserializerFactory.java:223)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:262)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:151)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:415)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:350)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:648)
at com.fasterxml.jackson.databind.ObjectReader._prefetchRootDeserializer(ObjectReader.java:2430)
at com.fasterxml.jackson.databind.ObjectReader.forType(ObjectReader.java:771)
at org.glassfish.jersey.jackson.internal.jackson.jaxrs.base.ProviderBase.readFrom(ProviderBase.java:819)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.invokeReadFrom(ReaderInterceptorExecutor.java:233)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:212)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:132)
at org.glassfish.jersey.spi.ContentEncoder.aroundReadFrom(ContentEncoder.java:102)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:132)
at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1072)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:919)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:853)
at org.glassfish.jersey.client.ClientResponse.readEntity(ClientResponse.java:298)
at org.glassfish.jersey.client.InboundJaxrsResponse$1.call(InboundJaxrsResponse.java:93)
at org.glassfish.jersey.internal.Errors.process(Errors.java:292)
at org.glassfish.jersey.internal.Errors.process(Errors.java:274)
at org.glassfish.jersey.internal.Errors.process(Errors.java:205)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:365)
at org.glassfish.jersey.client.InboundJaxrsResponse.runInScopeIfPossible(InboundJaxrsResponse.java:244)
at org.glassfish.jersey.client.InboundJaxrsResponse.readEntity(InboundJaxrsResponse.java:90)
at de.sfuhrm.radiobrowser4j.RadioBrowser.voteForStation(RadioBrowser.java:561)
`
Interesting! The Constructor.getParameterCount()
was introduced in JDK 1.8.
Referring to this post, Android 7 had support for JDK 8. I am not sure whether this is correct when I read about your problem, as it would mean the Android is running JDK 7 or older.
I see a dilemma here:
The target of this library is JDK 8 at the moment. Older really feels wrong.
I'd suggest for antique Android support to Maven-exclude the Jackson stuff in your Application's pom/gradle file and depending on jackson libs 2.13.3.
In the long term the approach using the Jersey-JAXRS-client needs to be replaced by something with less footprint to work smooth with Android.
Guess this is the related bug report:
Just for you info, guys. I've refactored the code a bit to go through 1 class. This way it will be easier to replace the fat dependency towards Jersey / JAX-RS / Jackson with something more lightweight like Okhttp and Gson.
That's great news. Was this additional work something you were planning on doing, or are you expecting an android fork?
@fourofspades I am planning an android fork, or a more android-friendly fork. I think reducing the dependency footprint is a good thing anyway.
Thanks, that's great news, I'm still on version 2.50 as it was the last version I was able to persuade to work under Android.
A little teaser: This is the (non test) dependencies of the new library. Left is the current version with Jersey and jackson, right is the new version with only GSon. I'll upload an alpha release soon. The library has changed a lot under the hood.
[INFO] Scanning for projects... [INFO] Scanning for projects...
[INFO] [INFO]
[INFO] ----------------------< de.sfuhrm:radiobrowser4j >---- [INFO] ----------------------< de.sfuhrm:radiobrowser4j >----
[INFO] Building RadioBrowser4j 2.6.2-SNAPSHOT [INFO] Building RadioBrowser4j 2.6.2-SNAPSHOT
[INFO] from pom.xml [INFO] from pom.xml
[INFO] --------------------------------[ jar ]--------------- [INFO] --------------------------------[ jar ]---------------
[INFO] [INFO]
[INFO] --- dependency:3.6.1:tree (default-cli) @ radiobrowser [INFO] --- dependency:3.6.1:tree (default-cli) @ radiobrowser
[INFO] de.sfuhrm:radiobrowser4j:jar:2.6.2-SNAPSHOT [INFO] de.sfuhrm:radiobrowser4j:jar:2.6.2-SNAPSHOT
[INFO] +- org.glassfish.jersey.core:jersey-client:jar:3.0.12: | [INFO] +- com.google.code.gson:gson:jar:2.10.1:compile
[INFO] | +- jakarta.ws.rs:jakarta.ws.rs-api:jar:3.0.0:compil <
[INFO] | +- org.glassfish.jersey.core:jersey-common:jar:3.0. <
[INFO] | | +- jakarta.annotation:jakarta.annotation-api:jar <
[INFO] | | \- org.glassfish.hk2:osgi-resource-locator:jar:1 <
[INFO] | \- jakarta.inject:jakarta.inject-api:jar:2.0.1:comp <
[INFO] +- org.glassfish.jersey.media:jersey-media-json-jackso <
[INFO] | +- org.glassfish.jersey.ext:jersey-entity-filtering <
[INFO] | +- com.fasterxml.jackson.core:jackson-annotations:j <
[INFO] | +- com.fasterxml.jackson.core:jackson-databind:jar: <
[INFO] | +- com.fasterxml.jackson.module:jackson-module-jaka <
[INFO] | \- jakarta.xml.bind:jakarta.xml.bind-api:jar:3.0.1: <
[INFO] | \- com.sun.activation:jakarta.activation:jar:2.0 <
[INFO] +- org.glassfish.jersey.inject:jersey-hk2:jar:3.0.12:c <
[INFO] | +- org.glassfish.hk2:hk2-locator:jar:3.0.3:compile <
[INFO] | | +- org.glassfish.hk2.external:aopalliance-repack <
[INFO] | | +- org.glassfish.hk2:hk2-api:jar:3.0.3:compile <
[INFO] | | \- org.glassfish.hk2:hk2-utils:jar:3.0.3:compile <
[INFO] | \- org.javassist:javassist:jar:3.29.2-GA:compile <
[INFO] +- org.slf4j:slf4j-api:jar:2.0.11:compile [INFO] +- org.slf4j:slf4j-api:jar:2.0.11:compile
[INFO] +- org.slf4j:slf4j-ext:jar:2.0.11:compile [INFO] +- org.slf4j:slf4j-ext:jar:2.0.11:compile
[INFO] +- org.projectlombok:lombok:jar:1.18.30:provided [INFO] +- org.projectlombok:lombok:jar:1.18.30:provided
[INFO] | +- com.fasterxml.jackson.core:jackson-core:jar:2.15 <
[INFO] ------------------------------------------------------ [INFO] ------------------------------------------------------
[INFO] BUILD SUCCESS [INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------ [INFO] ------------------------------------------------------
[INFO] Total time: 0.752 s | [INFO] Total time: 0.779 s
[INFO] Finished at: 2024-01-12T21:03:21+01:00 | [INFO] Finished at: 2024-01-12T21:03:12+01:00
[INFO] ------------------------------------------------------ [INFO] ------------------------------------------------------
I have release a version 3.0.0 with quite some changes under the hood and some breaking changes in the API. It is marked as a pre-release. It is not using the JAX-RS / Jetty dependencies anymore which caused problems for this issue and Android. It is internally using an URLConnection which is also what the Android recommendations are. For JSON serialization it is now using the more lightweight Gson library from Google.
Since the information in this thread only affects the previous versions, I'm closing the issue. If you find problems with the 3.0.0 version feel free to open new issues! Thank you all for your help and support!
Getting excellent results. It's reduced the size of my executable by almost 2Mb, which is great news, the only thing I needed to keep in my Proguard file was:
-dontwarn lombok**
-keep class de.sfuhrm.radiobrowser4j.** { *; }
Tested the following API calls:
Along with endpoint discovery and the the new ConnectionParams.builder. Everything working perfectly.
Many thanks.
@fourofspades thanks for feedback! Let me know if you find bugs.
Feels like the last step might be to embed Proguard configuration , so it works with Android out the box, with no additional changes.
@fourofspades is there something that you could provide for that? May be in the form of a PR?
Hi, did a bit of research online, and it appears this is one of the differences between a generic jar and an android specific aar library, the aar can include proguard configuration of the library itself, and it's not possible with jar.
As it's only 2 lines to include, it's perhaps easier to update the readme, than mess around with an Android specific library.
@fourofspades thanks for your research! Whatever way suits you, feel free to drop me either the passage for the readme or send a PR which updates it.
@fourofspades PR merged. Thanks!
I tried this library and after run example code, application crash and print this log. I sought this problem in web, but can't find any solution.
java.lang.RuntimeException: java.lang.ClassNotFoundException: Provider for jakarta.ws.rs.client.ClientBuilder cannot be found at jakarta.ws.rs.client.ClientBuilder.newBuilder(ClientBuilder.java:77) at de.sfuhrm.radiobrowser4j.RestClientFactory.newClient(RestClientFactory.java:27) at de.sfuhrm.radiobrowser4j.RadioBrowser.(RadioBrowser.java:112)
at de.sfuhrm.radiobrowser4j.RadioBrowser.(RadioBrowser.java:79)
at de.sfuhrm.radiobrowser4j.RadioBrowser.(RadioBrowser.java:131)
Thanks and have a great day.