I'm new in Android development. Not very new in ordinary EE Java and Gradle.
So I am trying to build a REST consumer app for Android. I have a (1) .jar file I will need (contains DTOs and api consumers). That (1) .jar has dependencies on other (2) jars from Nexus repo. These (2) do depend on other (3) jars (e.g. apache commons lang3, etc.) from maven repos.
The funny thing is that... The app compiles and install just fine. But on runtime it occasionaly tends to lose some classes from (1) (at least (1) -- dunno about (2) and (3) yet).
I know SO does not like pics in questions, but in this case I believe pics = clarity.
See below. Same runtime, same jar. Except one of the classes is not loaded, and another one, sitting right next to it, is available.
Why is that so? What did I do wrong?
One more thing... If I attempt to instantiate one of the missing classes (there's more than one) in main activity (inside onCreate()), sometimes that class appears in the classpath and creates an object just fine. But as ridiculous as it may sound some other class goes missing! It feels like Classloader has limited number of slots for classes it could possibly handle.
EDIT:
Okay, it gets better. It appears that for some reason gradle decided not to include some files from (1).jar into generated .apk...
Any ideas why?
Gradle 4.1. Linux Mint 18. Android Studio 3.0 Canary 8
Left - decompiled APK structure; right - original jar
Probably, you have ProGuard activated. ProGuard removes from the final .apk the unused classes. ProGuard
Related
As most people familiar with Expo are aware, development has been a breeze thanks to its many layers of abstraction.
However, I've hit a wall and need to break out of my Expo bubble. I don't mean ejecting or re-writing the entire app. What I mean is to start gaining awereness of what's going on under the hood. This question specifically refers to dependency management & bundling.
I'm no expert on Android development, but I do have some basics. As far as I understand, dependencies are managed in a Java-like fashion. With concepts like the Java package, and tools like Gradle.
Expo manages dependencies using a NodeJS fashion. With concepts like the package.json and tools like npm/yarn.
When the time comes to build the android binary, Expo does something with the Javascript code & bundles it along several Andriod dependencies required for the project to run.
Therefore, what I need to get is a full list of all the Android native dependencies the
resulting binary will include. i.e: com.company.example:identifier:x.y.z
I've used JADX to de-compile a resulting .aab from Expo and while the result is quite insightful, it's missing a reliable manifest listing all the bundled packages. Said manifest might not even exist, as all the bundled packages will probably be included along the rest of the source code, so there's no need to list them separetly. A manifest like that would make most sense before building. It does have an Android Manifest, but that one doesn't list dependencies.
What I did though, is to cd into the de-compiled project and run the command:
grep -rh . -e '^package.\+;' | sort -u > packages.log
The output looks promising, but I'm no expert and I need to be 100% sure before telling my boss. Decompiling isn't always 100% reliable due to some code being impossible to decode.
I've also tried expo prebuild but the resulting gradle files will not list all dependencies directly. Instead they require dependencies defined in a package.json using a weird directive like so:
url(new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), "../android"))
Not sure how to manually execute that directive, or how that gets eventually translated to native android dependencies (i.e com.facebook.react.uimanager).
Please, I need help listing all the Android dependencies for an Expo project and being 100% sure about it.
I have a scratch file using guava collections, and I get some weird errors that I have to assume is due to the editor and the actual run environment assuming different versions of the guava collections:
Exception in thread "main" java.lang.IllegalAccessError: tried to access method com.google.common.collect.Range.<init>(Lcom/google/common/collect/Cut;Lcom/google/common/collect/Cut;)V from class
com.google.common.collect.Ranges
at com.google.common.collect.Ranges.create(Ranges.java:80)
at com.google.common.collect.Ranges.closedOpen(Ranges.java:114)
at Scratch.main(scratch_2.java:69)
Not that I can actually know that for sure because I also can't figure out how I'm supposed to see which version the scratch file is pulling in. I've removed guava from my project's deps ENTIRELY and the scratch file still works... WHY? Where is the library coming from??? The scratch run config is completely empty of anything that would dictate this:
And yet it still runs just fine. I discovered that if I delete the guava entries from my local ivy cache, it won't run anymore. If I then add guava back to my project's deps, it ends up in my ivy cache again, and then even if I remove guava from the project deps the scratch file is fine again. So does the scratch file just pick a random version or something? The ivy cache, which is at ~/.ivy2/cache/com.google.guava, looks like this:
But there's also that "jars" folder that has a guava-12.0 for some reason:
And again, I have no idea which version is being used, or why the cache has so many different versions of it. Any ideas?
One way that proved to be the simplest to me was to select "use classpath of an existing project module" (which has dependencies configured) in the run configuration dialog. This is useful if you want to pull out a piece of functionality from your project to play with in isolation but still use the configured dependencies.
I had a similar issue in PyCharm that I just fixed - so your mileage may vary here. It terms out that there was a Python virtual environment attached as the default to the project window (I had had multiple projects open in the same window - but evidently the first one became the default).
I dug into the list of interpreters, found the one I wanted and edited its properties, specifically Associate this virtual environment with current project.
I checked that box for the virtualenv that had the libraries I was looking for and this fixed the compilation errors in the editor itself.
I have a legacy app with 168 modules in it and I would like to break it up into several java packages from:
com.mycompany.ediary
to
com.mycompany.ediary.util
com.mycompany.ediary.data
com.mycompany.ediary.services
...etc.
This would be to better organize the code. I read where it is ideal to have less than 30 files per package and as you can see, this is way over this. What is the best way to do this? I am currently running Android Studio 1.5
As #Antoniossss says "Just do it!".
Following a slight explanation...
In the older Eclipse days there was a link between the Java packages, and the Android manifest package (now referred to as the "application ID") in the app. This was enforced by Eclipse (almost) requiring that you put your code into a Java package that was named the same as the application ID.
Changing the root (Java) package of your code in Eclipse got a bit tricky, and generally you would want to do that by using the Android Tools menu. This made sure that the R class was correctly imported after the change.
Android Studio makes it much easier to separate the 2 concepts. Plus the terminology makes it easier now, since the accepted term "Android manifest package" is now the "application ID".
This gets set in your gradle build file:
applicationId "mobi.glowworm.demo"
How you organise your Java code does not depend on this value at all anymore. You can use any package structure you want to.
So, yes, "Just do it!"
It wasn't as easy as I thought in Android Studio, yet easier than I thought at the same time.
Adding new packages is basically adding new directories to your project structure, by adding new "packages" and letting Android Studio do the work of refactoring it all in your code. I did have some collisions with the manifest-merger-release-report.txt file, but after manually fixing those and updating my manifest as well, I was able to break up the files into a more organized format. I didn't have to touch the gradle files at all.
Right click on the java folder in your app, select New -> package - then enter in the full package name: com.mycompany.ediary.utils. Then cut and paste the files you want to add to the new directory/package, when prompted for reformatting, hit "reformat", then allow Android studio to do its magic.
I downloaded this library and i extracted the rar into my app\libs folder.
Then I added compile 'com.github.lzyzsd:circleprogress:1.1.0#aar' to my build gradle as it says, and clicked on sync.
Then I noticed that the max is set to 100 (in file DonutProgress.java).
I changed it to 5, clicked on sync again but nothing changed.
After few hours of trying I decided to completely remove the extracted folder from my app\libs and sync again to see what happens.
Surprisingly, everything was still working like library was still there.
Can someone explain me what's happening here, I have to edit it but it seems whatever I do to the library doesn't affect the app.
It seems like it's using another library from totally different folder, I don't know, I tried searching for DonutProgress on my computer but didn't find anything that seems useful.
Please help.
When you add compile 'com.github.lzyzsd:circleprogress:1.1.0#aar' to your build.gradle dependencies, you are telling Gradle to go fetch this library from a repository when you build.
For most Android apps, this means that when you do a build, Gradle will go and download the library (in this case a .aar) from jCenter. This is good because it means you no longer need to manage the JARs (or other library files) yourself.
If you want to use a custom version of that library, then you should not add that dependency to your Gradle build script. Instead you should add it as either a module or a local dependency (e.g. compile files('libs/custom_library_name.aar')).
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
NoClassDefFoundError - Eclipse and Android
I'm seeing this question is getting asked a lot in many different contexts. Perhaps we can set some strategies for locating and fixing it? I'm noobish myself so all I can contribute are horror stories and questions, sorry...
It seems this is thrown when a class is visible at compile time but not at run time... how can this happen?
In my case I am developing an app that uses the Google APIs, in Eclipse, for the Android platform. I've configured the Project Properties / Java Build Path / Libraries to include the gdata .jars and all is well. When I execute in the emulator I get a force close and the logcat shows a NoClassDefFoundError on a simple new ContactsService("myApp"); I've also tried a new CalendarService("myApp") with the same results.
Is it possible or desirable to statically bind at compile time to avoid the problem?
How could dynamic binding of an add-on library work in the mobile environment anyway? Either it has to be bound into my .apk or else I need to "install" it? ... hmmm.
Advice much appreciated.
It seems this is thrown when a class
is visible at compile time but not at
run time... how can this happen?
The build classpath may include JARs that are not being packaged into the APK.
Is it possible or desirable to
statically bind at compile time to
avoid the problem?
It is possible, desirable, and necessary.
Outside of Eclipse, you just put the JARs you need in libs/ in your project, compile with Ant, and you are done.
Inside of Eclipse, one pattern I have had students use with success is to put the JARs you need in libs/ in your project, add them as JARs to the build path (note: not external JARs), and they get packaged as part of the APK. Note, though, that I do not personally use Eclipse, and so my experience with it is limited.
For those having problem I was having the same error with my app. what I did to solve that was create a new project and copy my resource and source folders along with my manifest file into the new project (I deleted in advance those within the new project created) and voila.
When I got this, the problem was actually deeper in the queue; Dalvik converter had failed to convert some of the referenced libraries and still Eclipse allowed me to launch the project.
Check the Android SDK console to see if there are any errors reported.
In my case, I'm using my own library (MyLib) shared between 2 apps. App A was closed when I added a new class to the library.
When I opened App A to work on it, Eclipse recognised the new class, and I was able to reference it. However on running I got the error.
It turned out that the imported library folder in App A (named something like MyLib_src) didn't reflect the changes made to my library project (MyLib).
To solve this I refreshed App A, the changes reflected, and Android could build my project correctly.
I have found no reference to this version of the problem, so thought I would add it to this list.