NoClassDefFound in a multidex'ed apk - android

I have a very strange issue i suspect related to multidexing (but not sure).
I have an app module and a library module. The library is executing some code on app start which, through an interface on the main application class, gets a class name defined in the library.
Now the strange part begins.
The app is multidexed according to the following instructions - Configure Apps with Over 64K Methods - and I have 2 build types - debug and release. On release build im using proguard to obfuscate and shrink the code. On debug build im not.
When running the app on devices with android +21 everything works fine in both build types.
When running the app on devices with pre lollipop version everything works fine in release build type but in debug build type im getting NoClassDefFoundError because of the class the application is trying to return to the library.
Following the suggestion in Declare classes required in the primary DEX file i've used the APK Analyzer in android studio to examine the distribution of classes between the dex files and saw 2 things:
in release build type there is only one dex file.
in debug build type there are 2 dex files but the problematic class (and its parent) is defined in the primary dex file.
Moreover, when im replacing the call from the library to the application (getClassName() in the diagram) with the actual class name everything is working fine in all build types!
As a last attempt to understand whats going on here i've compared the 2 apks, the original one with a one without the call to the application (replaced with actual class name), and the only difference i could see is the library code making the call. In terms of classes distribution between dex files there is absolutly no difference!
Does anyone understand whats the problem here ? Thanks.

eventually it was com/newrelic/agent/android/api/v2/TraceFieldInterface.class that i had to make sure is in the main dex file.
If someone is using newrelic you might want to pay attention to this.

Related

Why does the gradle build process strip out my Application and Activity classes?

I have an application that's written with Unity. It uses a custom Application and Activity class. Previously this has worked just fine but I've recently switched to using gradle to perform the build instead of Unity's deprecated internal build process. My Application and Activity classes are located in a library that's in the form of an aar file. The custom classes are referenced from a the and tags of a custom AndroidManifest.
I can see that the classes are present in the aar. I can see that the generated AndroidManifest references these class. I can see the dependency on this library in the generated build.gradle file. I can tell that the build process is actually referencing this library in some form. However, these classes are not present in the resulting APK, resulting in a crash on launch.
I do not have proguard or anything similar enabled. I can tell that this is a new problem because older versions of the APK do have those classes. What could be causing these classes to not be included in the resulting APK?
The package that contained those classes had the same name as the one generated by Unity. I changed the package name and everything seems to be working now.

Developing Android 9.0 eSIM LPA (system app)

Trying to develop android LPA system app for eSIM with the new Pie API.
The doc says to extend the abstract EuiccService class. But this class is not in the official SDK, and the link in the docs just leads to corresponding file in the android source repo.
I tried using this file/class as a dependency, but it references other internal android classes/annotations and causes build/IDE errors.
Does anyone have an idea how to use this?
Do I really have to pull android src code and somehow reference required class from it?
EDIT: I think I've solved it, found couple of potential solutions, but they were a bit cumbersome. Used the android.jar from here: https://github.com/anggrayudi/android-hidden-api (contains modified android.jar with hidden APIs and internal resources). It didn't work when i replaced the whole file and resulted strange build errors, but i manually transferred the android\service\euicc\ folder to original android.jar of android-28 sdk and it works perfectly (class is available and apk builds without issues). And no need to waste time pulling and building AOSP.
EDIT #2: apparently not fully fixable atm. There's issue with android gradle plugins (at least 3.2.x-3.3.x) where during full sync some build task generates mock classes from android.jar and process fails if it's modified (discussion is here: https://github.com/anggrayudi/android-hidden-api/issues/46). Error looks like this:
Failed to transform file 'android.jar' to match attributes {artifactType=android-mockable-jar, returnDefaultValues=false} using transform MockableJarTransform
There's a workaround for that, though inconvenient:
when you need a full sync for the project, replace the android.jar with original, run sync, restore modified android.jar, the IDE now will run indexing and classes will be available again with build working until next full sync.
Will update this post if/when it's fixed or new solution is found.
EDIT#3: here's probably a final solution for EuiccService case (turned out pretty obvious):
Instead of adding 'android/service/euicc' folder to android.jar, just put it in a separate library and add it as a compileOnly dependency. Since the classes were not in the SDK, the lib should not cause conflict (would be the case if you need to use modified framework or access hidden APIs in already existing classes).
If you are going to create a System APP, you will do it in several ways:
You could call a part of the SystemAPI (a method for example) by reference.
You could make the aplication as a part of the AOSP Project (Downloading the AOSP code, and introducing your app as part of packages/apps/)
You will be able to access system APIs on a rooted device or if you have system permissions (this happens when you flash your app into the device as part of the system image).
However, if you want to be able to call the EuiccService class from Android Studio (for coding purposes), you'll need to add the Android framework jar to your project.
The steps are provided below:
First, you will have to download and build AOSP and generate a framework jar for your target Android version. Check the documentation here to get an idea of how to download and build AOSP.
After a successful build all framework classes are compiled into a jar called classes.jar which can be found at the location out/target/common/obj/JAVA_LIBRARIES/framework_intermediates.
Get this classes.jar and add it to your Android project as a jar file.
Gradle sync the project and start coding.
Please beware that you WILL NOT BE ABLE TO run this app on an Adnroid device where you do not have system permission for this app.

Android export apk throws ActivityNotFoundException

I've created a project that have 3 dependencies for 3 different android projects marked as libraries. I managed to run the application from eclipse and everything works fine.
The problem: I've exported the project as a signed apk. The apk was created and I was able to run it on my device but when it tries to access an activity that resides in one of the android library my app crashes with ActivityNoFoundException. It seems that the android library projects were not added in the final apk, but why?
All the manifest files are merged into the main manifest file.
What can be the problem? Thank you!
Does your project use proguard obfuscation? it's possible the activity names are being obfuscated and therefore would not match up with what's in your manifest. Usually obfuscation isn't run when you run the app from an IDE so could also explain why it works there. You could also try unzipping the apk and looking inside to see what is actually making it in

Gradle release build with proguard: java.lang.IncompatibleClassChangeError and java.lang.NoSuchMethodError

I recently migrated a project from Eclipse/Ant to Android Studio/Gradle. I am able to successfully build a signed release version of the project with proguard enabled. However, while testing the release version, I'm getting crashes from certain library projects and jars (which work fine when building a debug version).
For example, when attempting to upload a file to Dropbox (a jar dependency), I get the following error:
java.lang.IncompatibleClassChangeError: interface not implemented
at com.dropbox.client2.session.AbstractSession.sign(SourceFile:238)
at com.dropbox.client2.DropboxAPI.putFileRequest(SourceFile:2199)
at com.dropbox.client2.DropboxAPI.putFileOverwriteRequest(SourceFile:1571)
at com.dropbox.client2.DropboxAPI.putFileOverwrite(SourceFile:1537)
Also, when attempting to sign into Box (a library project dependency), I get the following error:
java.lang.NoSuchMethodError: org.apache.http.conn.params.ConnManagerParams.setMaxTotalConnections
at com.box.restclientv2.BoxBasicRestClient.()
at com.box.boxjavalibv2.BoxRESTClient.()
at com.box.boxjavalibv2.BoxClient.createRestClient()
at com.box.boxjavalibv2.BoxClient.()
at com.box.boxandroidlibv2.BoxAndroidClient.(SourceFile:49)
at com.box.boxandroidlibv2.activities.OAuthActivity.startOAuth(SourceFile:71)
at com.box.boxandroidlibv2.activities.OAuthActivity.onCreate(SourceFile:52)
I have other jars and library projects that work just fine...
Again, there are no issues with either of these when building a gradle debug build (no proguard). I was also able to create a release build with proguard enabled using ant without any issues (able to sign into both Dropbox and Box).
Any ideas?
You appear to be including a version of the org.apache.http library. In principle, this library is already part of the Android runtime android.jar, so you shouldn't add it to your project. ProGuard is probably printing warnings about these duplicate classes.
In practice, it may be a newer version of the library, and some of your code may be using additional classes from this version. You then probably should leave the names of the classes, fields, and methods untouched, to avoid introducing (additional) conflicts:
-keep class org.apache.http.** { *; }
A build process may filter out the classes, or it may be adding the above line, but I don't think the default Android builds currently do either.
You need to -keep Proguard from removing or renaming all the class and method names that it can't determine are referenced from code that it doesn't processes, that are referenced via reflection (e.g. XML references), etc.
Keeping all apache classes may keep more than necessary (which is OK) but it may not be enough to fix all the Proguard issues.
It's good to ask why it worked from your ant build without this -keep. Maybe the ant build didn't actually call Proguard (ant is tricky), maybe it used a different Proguard data file, or maybe the relevant libraries changed in the meantime. You can debug that by listing hypotheses and testing them. E.g. if you put a malformed command in the Proguard data file then run the ant build, you can tell whether it actually runs Proguard or not.

Optimize the project code

I have been working on one project which is too complex and contain very much space with so many images and Java files as well.
Somewhere I have read about the proguard which optimizes the code.
I have used it, but it's still does not have an effect on my final APK file.
It might be I have made a mistake somewhere. I have the following this like http://developer.android.com/guide/developing/tools/proguard.html.
How can I optimize my code?
You can add it to the default.properties. I've been adding manually without having a problem so far.
If you add the line:
proguard.config=proguard.cfg
As said it will only use ProGuard when exporting signed application (Android Tools => Export Signed Application)
If you start the project with the SDK before Android 2.3 the proguard.cfg file will not be created (next to default.properties as in 2.3>).
To enable automatic creation of it, just simply update to the SDK of Android 2.3 and create a new project with existing sources (which are the sources of the project you currently have).
Automagically the proguard.cfg fill will be created.
Without optimizations the compiler produces very dumb code - each command is compiled in a very straightforward manner, so that it does the intended thing.
The Debug builds have optimizations disabled by default, because without the optimizations the produced executable matches the source code in a straightforward manner.
Please refer this one
From documentation:
ProGuard is integrated into the Android build system, so you do not have to invoke it manually. ProGuard runs only when you build your application in release mode, so you do not have to deal with obfuscated code when you build your application in debug mode.

Categories

Resources