I have a problem after adding compile "com.google.firebase:firebase-firestore:11.4.2" to my build.
As soon as I add that, it also adds com.google.common among other things to my dex file, which is around 27k extra references, thus bursting through the 64k dex limit.
Does anyone know why that is or am I doing something wrong?
Try adding these lines to your build.gradle
android {
defaultConfig {
...
minSdkVersion 21
targetSdkVersion 26
multiDexEnabled true
}
...
}
This will enable multidex mode, which will allow you to exceed the 64k limit. (Read more here)
API below 21
If you're using an API level below 21, then you also need to add the support library
gradle.build:
dependencies {
compile 'com.android.support:multidex:1.0.1'
}
android.manafest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application
android:name="android.support.multidex.MultiDexApplication" >
...
</application>
</manifest>
If you use a custom Application class, try using one the of the following
Solution 1
simply override the MultiDexApplication class
public class MyApplication extends MultiDexApplication { ... }
Solution 2
override attachBaseContext and install MultiDex using the install(Application) function
public class MyApplication extends SomeOtherApplication {
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}
You're not doing anything wrong: the Android API for Cloud Firestore is just big. We'll be working on reducing SDK size on the road to GA.
Meanwhile, you need to enable multidex to build if your application is nontrivial.
We actually use very little of com.google.common, so you may be able to say under the 64k method limit by proguarding your application too.
Updating to 11.6.0 fixes this issue
Related
I have a library I use for Espresso tests that when I added to my project I'm not able to compile my tests.
Gradle outputs this error
Caused by: com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536
at com.android.dx.merge.DexMerger$8.updateIndex(DexMerger.java:565)
at com.android.dx.merge.DexMerger$IdMerger.mergeSorted(DexMerger.java:276)
at com.android.dx.merge.DexMerger.mergeMethodIds(DexMerger.java:574)
at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:166)
at com.android.dx.merge.DexMerger.merge(DexMerger.java:198)
Which is really weird because I already have multiDex enabled in my project
My Project build.gradle
defaultConfig {
minSdkVersion 16
targetSdkVersion 21
versionName versionNameFromGitTagVia()
versionCode versionCodeFromJenkins()
multiDexEnabled true
testInstrumentationRunner "app.test.general.InstrumentationRunner" ...
}
dependencies {
...
androidTestImplementation project(':test-utils')
...
implementation 'com.android.support:multidex:1.0.2'
}
My Application Class
public class RiderApplication extends MultiDexApplication implements Application.ActivityLifecycleCallbacks,
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
....
}
AndroidManifest
<application
android:name=".RiderApplication"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:largeHeap="true"
android:theme="#style/MyAppTheme"
tools:replace="android:theme,android:icon">
Removing the library solves the problem
Any suggestions?
EDIT
I tried to fix it in several ways, and I discovered that this only happends when I include the library as
androidTestImplementation
But when used as a regular
implementation
The dex error disappears
Really strange
EDIT
It only happens with gradle 3.0.1, if I go back to gradle 2.3.3 the problem is no more
Solved by updating gradle build tools from version 3.0.1 to 3.1.0-rc02.
So please try:
classpath 'com.android.tools.build:gradle:3.1.0-rc02'
Well, this is a strange one but it has happened before.
I've stumbled upon this thread, whish suggested this addition:
dexOptions {
jumboMode = true
// Avoid the OutOfMemoryError: GC overhead limit exceeded:
incremental true
javaMaxHeapSize "4g"
}
This should handle the issue of the string number being too large, as opposed to the number of methods being too large.
More on jumbo mode vs multidex here: Android: Jumbo Mode vs Multidex
Happy testing.
Well, after many hours of testing I finally got it to run.
I have changed several things in the project, so I can't tell what was the one that caused the problem, but for the greater good I'll write here everything I did and I hope that if someone will ever encounter with such problem at least one solution will help her.
So I changed minSdkVersion to 21. Yes, it wasn't a requirement with Android Studio 2.3.3 but apparently it is now if you're going to use espresso.
But worry not, your application can still support older versions when not testing. To configure it that way I've added this to my build.gradle
def isTest = gradle.startParameter.taskNames.find { it.contains("AndroidTest") }
if (isTest != null) {
println("is test true")
minSdkVersion 21
} else {
println("is not test")
minSdkVersion 16
}
Other than that, I updated multiDex dependency from 1.0.1 to 1.0.2 and I enforced that on all dependencies.
I also updated guava library to com.google.guava:guava:22.0-android, which led to a dependency conflict that I solved by forcing another library (all forcing strategy is posted below).
I then had a dependency conflict with espresso-web that I needed to enforce too.
This is my resolution strategy at the moment
configurations.all {
resolutionStrategy {
force 'com.android.support:multidex:1.0.2'
force 'com.google.guava:guava:22.0-android'
force 'com.google.code.findbugs:jsr305:2.0.1'
force 'com.android.support.test.espresso:espresso-web:3.0.1'
}
}
I hope this helps anyone, thank you so much for all the people who tried to help, you brought many ideas that helped me succeeded with the final resolution
I want to implement 2 name spaces under Application in android Manifest file to implement the firebase offline capabilities but it rejects taking 2 name spaces in the manifest file, see:
I tried to extend multiDexApplication in the MiLibrary Class, see:
public class MiLibrary extends Application {
#Override
public void onCreate() {
super.onCreate();
if (!FirebaseApp.getApps(this).isEmpty()) {
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
Picasso.Builder builder = new Picasso.Builder(this);
builder.downloader(new OkHttpDownloader(this, Integer.MAX_VALUE));
Picasso built = builder.build();
built.setIndicatorsEnabled(false);
built.setLoggingEnabled(true);
Picasso.setSingletonInstance(built);
}
but it gives me an error, see the stackTrace:
I've also tried searching here on stack-overflow and on Google but there are results or answers related to this, does anyone know how I can achieve this?
First of all in application tag you can define only single attribute for:-
android:name=".YourApplication"
Secondly, add the following dependency for okHttpClient:-
compile 'com.squareup.okhttp3:okhttp:3.2.0'
Your app's gradle file should look like this:-
defaultConfig {
...
minSdkVersion 14
targetSdkVersion //Yours
// Enabling multidex support.
multiDexEnabled true
}
dependencies {
compile 'com.android.support:multidex:1.0.0'
compile 'com.squareup.okhttp3:okhttp:3.2.0'
}
Extend your application with MultiDexApplication class:-
public class MiLibrary extends MultiDexApplication { ... }
In your Manifest add name of your application as follows:-
<application
android:name=".MiLibrary"
...>
My app is crashed with following error,
E/dex2oat: Failed to create oat file:/data/dalvik-cache/arm/data#app#com.stvgame.xiaoy.remote-1#split_lib_dependencies_apk.apk#classes.dex: Permission denied
And our app use mutipule dex, does they have relation?
I had a similar problem and my solution was disable the Instant Run, if you're using Android Studio...
I had got a similar error when i used multi dex for the first time,
This guide helped a lot,
My error was i forgot to add this in the application class:
public class MyApplication extends SomeOtherApplication {
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}
in your build gradle, make sure you have included the following lines:
android {
defaultConfig {
...
minSdkVersion 15
targetSdkVersion 25
multiDexEnabled true
}
...
}
dependencies {
compile 'com.android.support:multidex:1.0.1'
}
Even then multi dex has limitations with progaurd, read the guide to find out if that is causing this issue.
I downloaded the SugarORM source to use it as a library module (so I could override the aplication's "attachBaseContext" method.
I have already seen the question SugarORM and multidex, Problem is that I can't figure out how to reference the MultiDex library into my new SugarORM library module.
Can someone help me figuring this out?
Error page screenshot
Create a class java file
public class MultiDex extends SugarApp {
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
android.support.multidex.MultiDex.install(this);
}
#Override
public void onCreate() {
super.onCreate();
SugarContext.init(this);
}
#Override
public void onTerminate() {
SugarContext.terminate();
super.onTerminate();
}
}
In Manifest, call the java class file.
<application
.......
android:name=".MultiDex"
......>
Check the version of sugar library
and make sure you complie the latest version of sugar library . Using version like 1.3 will throw some errors with multidex.
add this in your gradle
compile 'com.github.satyan:sugar:1.5'
If possible, extend the MultiDexApplication yourself:
public class MyApplication extends MultiDexApplication
Also, ensure you have followed all steps required to configure MultiDex.
Particularly build.gradle:
android {
defaultConfig {
...
multiDexEnabled = true
}
And AndroidManifest.xml:
<application
android:name="android.support.multidex.MultiDexApplication"
.. >
..
</application>
Here is a test project: click
I have a test Gradle Android project with three modules: app, library_a, library_b. app depends on library_a, then library_a depends on library_b:
build.gradle (app)
dependencies {
...
compile (project(":library_a")){
transitive = false;
}
}
build.gradle (library_a)
dependencies {
...
compile (project(":library_b")){
transitive = false;
}
}
Note that I set transitive = false because I don't want classes from library_b to be accessed from app
Every module has just one class, code is pretty simple:
app:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
//...
ClassA classA = new ClassA();
classA.doSomething();
}
}
library_a:
public class ClassA
{
public void doSomething(){
Log.i("Test", "Done A!");
ClassB classB = new ClassB();
classB.doSomething();
}
}
library_b:
public class ClassB
{
public void doSomething(){
Log.i("Test", "Done B!");
}
}
Well, here is the problem: I'm building my project with gradlew. Apk is compiling successfully, but when I run it I get NoClassDefFoundError.
I/Test﹕ Done A!
E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.NoClassDefFoundError: ru.pvolan.library_b.ClassB
at ru.pvolan.somelibrary.ClassA.doSomething(ClassA.java:12)
...
If I set transitive = true in both .gradle files, it runs ok, but, as I noted above, I don't want dependency to be transitive, as far as I don't want ClassB can be accessed from MainActivity - only ClassA.
What am I doing wrong?
This is a problem that Gradle has simplified in Gradle v3.4.
If you convert library A to use v3.4 there is a simple fix.
Gradle 3.4 changes the "compile" configuration to a set of configurations "api" and "implementation".
First you should upgrade gradle to 3.4 and use the java-library plugin in lieu of the java plugin.
You should use the "api" configuration on any jar that is explicitly used in the API method calls (return type, input parameters, etc).
For all other jars that you want to "hide" (like Library B) you should use the "implementation" configuration. As Library B is only used within the body of implementation methods there is no need to expose it to any other jars at compile time; however it still needs to be available at runtime so Library A can use it.
To implement this your Library A script should replace
apply plugin: 'java'
dependencies {
...
compile (project(":library_b")){
transitive = false;
}
}
with
apply plugin: 'java-library'
dependencies {
implementation project(":library_b")
}
This change will tell Gradle to include Library B as a runtime dependency of app, so that app cannot compile against it, but Library B still will be available at runtime for Library A to use. If for some reason app ends up needing Library B in the future, it would be forced to explicitly include Library B in it's dependency list to ensure it gets the desired version.
See this description from Gradle itself for more details and examples:
https://blog.gradle.org/incremental-compiler-avoidance
The problem is that library_b is a required dependency. You can't simply exclude it, since you need it to be on the classpath at runtime. You are effectively misrepresenting your actual dependencies in order to enforce a code convention and therefore losing any advantage of leveraging a dependency management system like Gradle. If you want to enforce class or package blacklist I'd suggest using a source analysis tool like PMD. Here's an an example of a rule to blacklist specific classes.
If that is not possible for some reason you can get your above example to "work" by simply adding library_b to the runtime classpath of app.
dependencies {
runtime project(':library_b')
}
Do you use multidex?
When I had a problem like this I used multidex and called class from different module. I could fix it only by turning off multidex and running proguard.
UPD
android {
compileSdkVersion 21
buildToolsVersion "21.1.0"
defaultConfig {
...
minSdkVersion 14
targetSdkVersion 21
...
// Enabling multidex support.
multiDexEnabled true
}
...
}
dependencies {
compile 'com.android.support:multidex:1.0.0'
}
more about multi dex https://developer.android.com/tools/building/multidex.html
and about proguard http://developer.android.com/tools/help/proguard.html