What is Android MultiDex? - android

There are many posts about MultiDex. I have experienced, sometimes, errors solved including multiDexEnabled true in the defaultConfig section of my build.gradle.
But, what exactly is this feature? What are the scenarios for using it?

Quoting the documentation:
Android application (APK) files contain executable bytecode files in the form of Dalvik Executable (DEX) files, which contain the compiled code used to run your app. The Dalvik Executable specification limits the total number of methods that can be referenced within a single DEX file to 65,536, including Android framework methods, library methods, and methods in your own code. Getting past this limit requires that you configure your app build process to generate more than one DEX file, known as a multidex configuration.
So, the feature is: it allows your complex app to compile. The scenarios for using it are when your app fails to compile due to hitting the 64K DEX method reference limit. This appears as a build error, such as:
Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536

It's as simple as this
A single .dex file can have 65,536 methods(references) so if the number of references exceeds 65,536, you go with multidex.
More Explanation!
An android application program is compiled into a .dex file which in turn zipped to a single .apk file.
DVM (Dalvik Virtual Machine) uses .dex file/files to execute bytecodes.
What causes the number of references to exceed 65,536 limits?
Methods written by you + Android Framework methods + Third party library(eg Volley,Retrofit, Facebook SDK etc) methods.
I have read "somewhere"
App Compat 24.2.1 contains 16.5k methods
Google Play Services GCM 9.6.1 contains 16.7k methods
So if you have created a simple Hello world application which has App Compat 24.2.1, you are already 1/4 way to cross the single dex methods limit

Accroding Android developer official site.
If your minSdkVersion is set to 21 or higher, multidex is enabled by default and you do not need the multidex support library.

When your app and the libraries it references exceed 65,536 methods, you encounter a build error that indicates your app has reached the limit of the Android build architecture
How to enable MultiDex in your project
Bulid.gradle
defaultConfig {
applicationId "******"
minSdkVersion 21
targetSdkVersion 30
versionCode 8
versionName "05.15.21.8"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
dependencies {
implementation 'com.android.support:multidex:1.0.3'
}
inherit MultiDexApplication
public class App extends MultiDexApplication {
private static App instance;
#Override
public void onCreate() {
MultiDex.install(this);
super.onCreate();
instance = this;
}
public static App getInstance ()
{
return instance;
}
#Override
public void onTerminate() {
super.onTerminate();
}
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}
In your Manifest
<application
android:name=".App"
</application>
Thank You

Related

Error: Cannot fit requested classes in a single dex file (# methods: 67593 > 65536)

How to solve this error I'm getting in Android Studio:
Error: Cannot fit requested classes in a single dex file (# methods: 67593 > 65536)
cant build my project now
Do this 4 step
1: Add this library in dependencies of the app build.gradle :
implementation 'com.android.support:multidex:1.0.3'
2: Add in the defaultConfig of the app build.gradle :
defaultConfig {
//other configs
multiDexEnabled true //add this line
}
3: Create new Java class like this :
public class ApplicationClass extends MultiDexApplication {
#Override
public void onCreate() {
super.onCreate();
}
}
4: Add this to your manifest (in application tag):
<application
android:name=".ApplicationClass"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name">
Same situation happened in my Visual Studio 2019 Xamarin project, and the way to solve this problem is just like what mentioned in the link:
Error:Cannot fit requested classes in a single dex file.Try supplying a main-dex list. # methods: 72477 > 65536
multiDexEnabled true
By checking the Enable multiDex checkbox in the option page of the ***.Droid project solves the problem.
Before you take any decision, as said in Google documentation :
Before configuring your app to enable use of 64K or more method
references, you should take steps to reduce the total number of
references called by your app code, including methods defined by your
app code or included libraries.
So try to remove useless importation in your app gradle and do a nice clean project or do multidex
Source : https://developer.android.com/studio/build/multidex

Can I enable multidex in Android debug build only?

Dears,
I read in many blog posts that multidex apps startup is slower than normal apps.
My app uses a lot of libraries that exceed 64k methods so I use multidex. But when I use proguard in release build, the final apk becomes less than 64k methods
So My question is: Can I enable multidex in Android debug build only so I don't have runtime error? and disable multi dex in release build as I don't need it?
If yes, how ?
If No, Is Android smart enough to speedup startup as it should recognize that app didn't exceed 64k even if it is multi dex app ?
Yes, you can. When you declare your buildTypes include multidex only for debug:
buildTypes {
release {
multiDexEnabled false
    }
debug {
multiDexEnabled true
}
}
Instead of enabling multidex only for debug, you can change your min sdk version to 21 only for debug so gradle can speed up dexing with ART:
android {
productFlavors {
// Define separate dev and prod product flavors.
dev {
// dev utilizes minSDKVersion = 21 to allow the Android gradle plugin
// to pre-dex each module and produce an APK that can be tested on
// Android Lollipop without time consuming dex merging processes.
minSdkVersion 21
}
prod {
// The actual minSdkVersion for the application.
minSdkVersion 14
}
}
...
buildTypes {
release {
runProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
}
dependencies {
compile 'com.android.support:multidex:1.0.0'
}
http://developer.android.com/tools/building/multidex.html
suggested methods are not needed anymore as android studio became "smart enough".
In fact, it will now give you a warning when you use minSdkVersion 21 (the old way) to speed up build time with dex:
You no longer need a dev mode to enable multi-dexing during
development, and this can break API version checks less...
In the past, our documentation recommended creating a dev product
flavor with has a minSdkVersion of 21, in order to enable multidexing
to speed up builds significantly during development. That workaround
is no longer necessary, and it has some serious downsides, such as
breaking API access checking (since the true minSdkVersion is no
longer known.) In recent versions of the IDE and the Gradle plugin,
the IDE automatically passes the API level of the connected device
used for deployment, and if that device is at least API 21, then
multidexing is automatically turned on, meaning that you get the same
speed benefits as the dev product flavor but without the downsides.
Yes, it even works with the multidex support library for Android versions prior to Lollipop with a little trick.
First specify multiDexEnabled for the debug build in build.gradle:
buildTypes {
...
debug {
...
multiDexEnabled true
}
}
Then create an AndroidManifest.xml file under src/debug.
src/debug/AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:name="android.support.multidex.MultiDexApplication"
tools:replace="android:name"/>
</manifest>
That should do the trick. If your app uses a custom application class then you have to create a subclass of your application class and specify the name of that subclass in the manifest.
The application subclass should look like this:
public class MyDebugApplication extends MyApplication {
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}

gradle - Android Studio build too slow multidex application

When I add to my project the multidex:true, and make an Application class that extends from the MultiDexApplication, my project build time passed from 20 sec to around 90 sec.How to do some faster?
If you are like me who already tried Vic Vu's solution but still can't avoid enabling multiDex then you can try this (as long as your are using a device that has Android 5.0 and above).
Note This will only speed up your development build. Your production build will still be slow.
Basically you need to introduce 2 product flavors one for dev and one for prod.
Add multiDexEnabled true
android {
productFlavors {
// Define separate dev and prod product flavors.
dev {
// dev utilizes minSDKVersion = 21 to allow the Android gradle plugin
// to pre-dex each module and produce an APK that can be tested on
// Android Lollipop without time consuming dex merging processes.
minSdkVersion 21
}
prod {
// The actual minSdkVersion for the application.
minSdkVersion 14
}
}
...
buildTypes {
release {
runProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
defaultConfig {
applicationId "com.something.something"
targetSdkVersion 23
versionCode 1
versionName "1.0.0"
multiDexEnabled true
}
}
dependencies {
compile 'com.android.support:multidex:1.0.1'
}
And I have a class which extends Application so I had to override attachBaseContext()
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
If you are not extending Application simply use MultiDexApplication in your AndroidManifest.xml application tag.
Ensure that in your Android Studio Build Variants you are pointing to devDebug.
Read the complete instructions here https://developer.android.com/studio/build/multidex.html#dev-build
Supplying as an answer because this is better fit with the formatting.
To simply answer your question: No, there is no way. Multidex is a process meant to help lift the burden of the 65k method limit. This process is complicated and will simply make your build times longer.
The best you can can do is lower your method count.
In your build.gradle (supplied here) you're using:
`compile 'com.google.android.gms:play-services:8.3.0'`
But if you look at the most recent play services api you can pick and choose what services you actually need.
Look at Table 1 on this page.
Only use the ones you need. Google play services as a whole is somewhere around 30k methods.
That should help.
Multidexing uses more memory. As you get closer to your max heap size in Java you'll find Java spends more time doing GC than it does doing any real work, this can slow things down a lot.
I'd strongly recommend increasing the max heap size when using multidex. Add the following to the android closure in your build.gradle file to make the max heap size 4GB (Make it larger/smaller if you wish):
dexOptions {
javaMaxHeapSize "4g"
}
It depends.
You haven't specified it in your question, but if you just want to speed-up your development builds - then you can avoid the extra work. Official documentation includes a whole section about that.

DexIndexOverflowException with build tool 21.0.0 [duplicate]

I have seen various versions of the dex erros before, but this one is new. clean/restart etc won't help. Library projects seems intact and dependency seems to be linked correctly.
Unable to execute dex: method ID not in [0, 0xffff]: 65536
Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536
or
Cannot merge new index 65950 into a non-jumbo instruction
or
java.util.concurrent.ExecutionException: com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536
tl;dr: Official solution from Google is finally here!
http://developer.android.com/tools/building/multidex.html
Only one small tip, you will likely need to do this to prevent out of memory when doing dex-ing.
dexOptions {
javaMaxHeapSize "4g"
}
There's also a jumbo mode that can fix this in a less reliable way:
dexOptions {
jumboMode true
}
Update: If your app is fat and you have too many methods inside your main app, you may need to re-org your app as per
http://blog.osom.info/2014/12/too-many-methods-in-main-dex.html
Update 3 (11/3/2014)
Google finally released official description.
Update 2 (10/31/2014)
Gradle plugin v0.14.0 for Android adds support for multi-dex. To enable, you just have to declare it in build.gradle:
android {
defaultConfig {
...
multiDexEnabled true
}
}
If your application supports Android prior to 5.0 (that is, if your minSdkVersion is 20 or below) you also have to dynamically patch the application ClassLoader, so it will be able to load classes from secondary dexes. Fortunately, there's a library that does that for you. Add it to your app's dependencies:
dependencies {
...
compile 'com.android.support:multidex:1.0.0'
}
You need to call the ClassLoader patch code as soon as possible. MultiDexApplication class's documentation suggests three ways to do that (pick one of them, one that's most convenient for you):
1 - Declare MultiDexApplication class as the application in your AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.multidex.myapplication">
<application
...
android:name="android.support.multidex.MultiDexApplication">
...
</application>
</manifest>
2 - Have your Application class extend MultiDexApplication class:
public class MyApplication extends MultiDexApplication { .. }
3 - Call MultiDex#install from your Application#attachBaseContext method:
public class MyApplication {
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
....
}
....
}
Update 1 (10/17/2014):
As anticipated, multidex support is shipped in revision 21 of Android Support Library. You can find the android-support-multidex.jar in /sdk/extras/android/support/multidex/library/libs folder.
Multi-dex support solves this problem. dx 1.8 already allows generating several dex files.
Android L will support multi-dex natively, and next revision of support library is going to cover older releases back to API 4.
It was stated in this Android Developers Backstage podcast episode by Anwar Ghuloum. I've posted a transcript (and general multi-dex explanation) of the relevant part.
As already stated, you have too many methods (more than 65k) in your project and libs.
Prevent the Problem: Reduce the number of methods with Play Services 6.5+ and support-v4 24.2+
Since often the Google Play services is one of the main suspects in "wasting" methods with its 20k+ methods. Google Play services version 6.5 or later, it is possible for you to include Google Play services in your application using a number of smaller client libraries. For example, if you only need GCM and maps you can choose to use these dependencies only:
dependencies {
compile 'com.google.android.gms:play-services-base:6.5.+'
compile 'com.google.android.gms:play-services-maps:6.5.+'
}
The full list of sub libraries and it's responsibilities can be found in the official google doc.
Update: Since Support Library v4 v24.2.0 it was split up into the following modules:
support-compat, support-core-utils, support-core-ui, support-media-compat and support-fragment
dependencies {
compile 'com.android.support:support-fragment:24.2.+'
}
Do note however, if you use support-fragment, it will have dependencies to all the other modules (ie. if you use android.support.v4.app.Fragment there is no benefit)
See here the official release notes for support-v4 lib
Enable MultiDexing
Since Lollipop (aka build tools 21+) it is very easy to handle. The approach is to work around the 65k methods per dex file problem to create multiple dex files for your app. Add the following to your gradle build file (this is taken from the official google doc on applications with more than 65k methods):
android {
compileSdkVersion 21
buildToolsVersion "21.1.0"
defaultConfig {
...
// Enabling multidex support.
multiDexEnabled true
}
...
}
dependencies {
compile 'com.android.support:multidex:1.0.1'
}
The second step is to either prepare your Application class or if you don't extend Application use the MultiDexApplication in your Android Manifest:
Either add this to your Application.java
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
or use the provided application from the mutlidex lib
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.myapplication">
<application
...
android:name="android.support.multidex.MultiDexApplication">
...
</application>
</manifest>
Prevent OutOfMemory with MultiDex
As further tip, if you run into OutOfMemory exceptions during the build phase you could enlarge the heap with
android {
...
dexOptions {
javaMaxHeapSize "4g"
}
}
which would set the heap to 4 gigabytes.
See this question for more detail on the dex heap memory issue.
Analyze the source of the Problem
To analyze the source of the methods the gradle plugin https://github.com/KeepSafe/dexcount-gradle-plugin can help in combination with the dependency tree provided by gradle with e.g.
.\gradlew app:dependencies
See this answer and question for more information on method count in android
Your project is too large. You have too many methods. There can only be 65536 methods per application. see here https://code.google.com/p/android/issues/detail?id=7147#c6
The below code helps, if you use Gradle. Allows you to easily remove unneeded Google services (presuming you're using them) to get back below the 65k threshold. All credit to this post: https://gist.github.com/dmarcato/d7c91b94214acd936e42
Edit 2014-10-22: There's been a lot of interesting discussion on the gist referenced above. TLDR? look at this one: https://gist.github.com/Takhion/10a37046b9e6d259bb31
Paste this code at the bottom of your build.gradle file and adjust the list of google services you do not need:
def toCamelCase(String string) {
String result = ""
string.findAll("[^\\W]+") { String word ->
result += word.capitalize()
}
return result
}
afterEvaluate { project ->
Configuration runtimeConfiguration = project.configurations.getByName('compile')
ResolutionResult resolution = runtimeConfiguration.incoming.resolutionResult
// Forces resolve of configuration
ModuleVersionIdentifier module = resolution.getAllComponents().find { it.moduleVersion.name.equals("play-services") }.moduleVersion
String prepareTaskName = "prepare${toCamelCase("${module.group} ${module.name} ${module.version}")}Library"
File playServiceRootFolder = project.tasks.find { it.name.equals(prepareTaskName) }.explodedDir
Task stripPlayServices = project.tasks.create(name: 'stripPlayServices', group: "Strip") {
inputs.files new File(playServiceRootFolder, "classes.jar")
outputs.dir playServiceRootFolder
description 'Strip useless packages from Google Play Services library to avoid reaching dex limit'
doLast {
copy {
from(file(new File(playServiceRootFolder, "classes.jar")))
into(file(playServiceRootFolder))
rename { fileName ->
fileName = "classes_orig.jar"
}
}
tasks.create(name: "stripPlayServices" + module.version, type: Jar) {
destinationDir = playServiceRootFolder
archiveName = "classes.jar"
from(zipTree(new File(playServiceRootFolder, "classes_orig.jar"))) {
exclude "com/google/ads/**"
exclude "com/google/android/gms/analytics/**"
exclude "com/google/android/gms/games/**"
exclude "com/google/android/gms/plus/**"
exclude "com/google/android/gms/drive/**"
exclude "com/google/android/gms/ads/**"
}
}.execute()
delete file(new File(playServiceRootFolder, "classes_orig.jar"))
}
}
project.tasks.findAll { it.name.startsWith('prepare') && it.name.endsWith('Dependencies') }.each { Task task ->
task.dependsOn stripPlayServices
}
}
I've shared a sample project which solve this problem using custom_rules.xml build script and a few lines of code.
I used it on my own project and it is runs flawless on 1M+ devices (from android-8 to the latest android-19). Hope it helps.
https://github.com/mmin18/Dex65536
Faced the same problem and solved it by editing my build.gradle file on the dependencies section, removing:
compile 'com.google.android.gms:play-services:7.8.0'
And replacing it with:
compile 'com.google.android.gms:play-services-location:7.8.0'
compile 'com.google.android.gms:play-services-analytics:7.8.0'
Try adding below code in build.gradle, it worked for me -
compileSdkVersion 23
buildToolsVersion '23.0.1'
defaultConfig {
multiDexEnabled true
}
The perfect solution for this would be to work with Proguard. as aleb mentioned in the comment.
It will decrease the size of the dex file by half.
You can analyse problem (dex file references) using Android Studio:
Build -> Analyse APK ..
On the result panel click on classes.dex file
And you'll see:
gradle + proguard solution:
afterEvaluate {
tasks.each {
if (it.name.startsWith('proguard')) {
it.getInJarFilters().each { filter ->
if (filter && filter['filter']) {
filter['filter'] = filter['filter'] +
',!.readme' +
',!META-INF/LICENSE' +
',!META-INF/LICENSE.txt' +
',!META-INF/NOTICE' +
',!META-INF/NOTICE.txt' +
',!com/google/android/gms/ads/**' +
',!com/google/android/gms/cast/**' +
',!com/google/android/gms/games/**' +
',!com/google/android/gms/drive/**' +
',!com/google/android/gms/wallet/**' +
',!com/google/android/gms/wearable/**' +
',!com/google/android/gms/plus/**' +
',!com/google/android/gms/topmanager/**'
}
}
}
}
}
Remove some jar file from Libs folder and copy to some other folder, And Go to _Project Properties > Select Java Build Path, Select Libraries, Select Add External Jar, Select the Removed jar to your project, Click save, this will be added under Referenced Library instead of Libs folder. Now clean and Run your project. You dont need to add Any code for MultDex. Its simply worked for me.
I was facing the same issue today what worked for is below down
For ANDROID STUDIO... Enable Instant Run
In File->Preferences->Build, Execution, Deployment->Instant Run-> Check Enable Instant run for hot swap...
Hope it helps

How to shrink code - 65k method limit in dex

I have a rather large Android app that relies on many library projects. The Android compiler has a limitation of 65536 methods per .dex file and I am surpassing that number.
There are basically two paths you can choose (at least that I know of) when you hit the method limit.
1) Shrink your code
2) Build multiple dex files (see this blog post)
I looked into both and tried to find out what was causing my method count to go so high. The Google Drive API takes the biggest chunk with the Guava dependency at over 12,000. Total libs for Drive API v2 reach over 23,000!
My question I guess is, what do you think I should do? Should I remove Google Drive integration as a feature of my app? Is there a way to shrink the API down (yes, I use proguard)? Should I go the multiple dex route (which looks rather painful, especially dealing with third party APIs)?
It looks like Google has finally implementing a workaround/fix for surpassing the 65K method limit of dex files.
About the 65K Reference Limit
Android application (APK) files contain
executable bytecode files in the form of Dalvik Executable (DEX)
files, which contain the compiled code used to run your app. The
Dalvik Executable specification limits the total number of methods
that can be referenced within a single DEX file to 65,536, including
Android framework methods, library methods, and methods in your own
code. Getting past this limit requires that you configure your app
build process to generate more than one DEX file, known as a multidex
configuration.
Multidex support prior to Android 5.0
Versions of the platform prior to Android 5.0 use the Dalvik runtime
for executing app code. By default, Dalvik limits apps to a single
classes.dex bytecode file per APK. In order to get around this
limitation, you can use the multidex support library, which becomes
part of the primary DEX file of your app and then manages access to
the additional DEX files and the code they contain.
Multidex support for Android 5.0 and higher
Android 5.0 and higher uses a runtime called ART which natively
supports loading multiple dex files from application APK files. ART
performs pre-compilation at application install time which scans for
classes(..N).dex files and compiles them into a single .oat file for
execution by the Android device. For more information on the Android
5.0 runtime, see Introducing ART.
See: Building Apps with Over 65K Methods
Multidex Support Library
This library provides support for building
apps with multiple Dalvik Executable (DEX) files. Apps that reference
more than 65536 methods are required to use multidex configurations.
For more information about using multidex, see Building Apps with Over
65K Methods.
This library is located in the /extras/android/support/multidex/
directory after you download the Android Support Libraries. The
library does not contain user interface resources. To include it in
your application project, follow the instructions for Adding libraries
without resources.
The Gradle build script dependency identifier for this library is as
follows:
com.android.support:multidex:1.0.+ This dependency notation specifies
the release version 1.0.0 or higher.
You should still avoid hitting the 65K method limit by actively using proguard and reviewing your dependencies.
you can use the multidex support library for that, To enable multidex
1) include it in dependencies:
dependencies {
...
compile 'com.android.support:multidex:1.0.0'
}
2) Enable it in your app:
defaultConfig {
...
minSdkVersion 14
targetSdkVersion 21
....
multiDexEnabled true
}
3) if you have a application class for your app then Override the attachBaseContext method like this:
package ....;
...
import android.support.multidex.MultiDex;
public class MyApplication extends Application {
....
#Override
protected void attachBaseContext(Context context) {
super.attachBaseContext(context);
MultiDex.install(this);
}
}
4) if you don't have a application class for your application then register android.support.multidex.MultiDexApplication as your application in your manifest file. like this:
<application
...
android:name="android.support.multidex.MultiDexApplication">
...
</application>
and it should work fine!
Play Services 6.5+ helps:
http://android-developers.blogspot.com/2014/12/google-play-services-and-dex-method.html
"Starting with version 6.5, of Google Play services, you’ll be able to
pick from a number of individual APIs, and you can see"
...
"this will transitively include the ‘base’ libraries, which are used
across all APIs."
This is good news, for a simple game for example you probably only need the base, games and maybe drive.
"The complete list of API names is below. More details can be found on
the Android Developer site.:
com.google.android.gms:play-services-base:6.5.87
com.google.android.gms:play-services-ads:6.5.87
com.google.android.gms:play-services-appindexing:6.5.87
com.google.android.gms:play-services-maps:6.5.87
com.google.android.gms:play-services-location:6.5.87
com.google.android.gms:play-services-fitness:6.5.87
com.google.android.gms:play-services-panorama:6.5.87
com.google.android.gms:play-services-drive:6.5.87
com.google.android.gms:play-services-games:6.5.87
com.google.android.gms:play-services-wallet:6.5.87
com.google.android.gms:play-services-identity:6.5.87
com.google.android.gms:play-services-cast:6.5.87
com.google.android.gms:play-services-plus:6.5.87
com.google.android.gms:play-services-appstate:6.5.87
com.google.android.gms:play-services-wearable:6.5.87
com.google.android.gms:play-services-all-wear:6.5.87
In versions of Google Play services prior to 6.5, you had to compile the entire package of APIs into your app. In some cases, doing so made it more difficult to keep the number of methods in your app (including framework APIs, library methods, and your own code) under the 65,536 limit.
From version 6.5, you can instead selectively compile Google Play service APIs into your app. For example, to include only the Google Fit and Android Wear APIs, replace the following line in your build.gradle file:
compile 'com.google.android.gms:play-services:6.5.87'
with these lines:
compile 'com.google.android.gms:play-services-fitness:6.5.87'
compile 'com.google.android.gms:play-services-wearable:6.5.87'
for more reference, you can click here
Use proguard to lighten your apk as methods that are unused will not be in your final build. Double check you have following in your proguard config file to use proguard with guava (my apologies if you already have this, it wasn't known at time of writing) :
# Guava exclusions (http://code.google.com/p/guava-libraries/wiki/UsingProGuardWithGuava)
-dontwarn sun.misc.Unsafe
-dontwarn com.google.common.collect.MinMaxPriorityQueue
-keepclasseswithmembers public class * {
public static void main(java.lang.String[]);
}
# Guava depends on the annotation and inject packages for its annotations, keep them both
-keep public class javax.annotation.**
-keep public class javax.inject.**
In addition, if you are using ActionbarSherlock, switching to the v7 appcompat support library will also reduce your method count by a lot (based on personal experience). Instructions are located :
http://developer.android.com/tools/support-library/features.html#v7-appcompat Actionbar
http://developer.android.com/tools/support-library/setup.html#libs-with-res
You could use Jar Jar Links to shrink huge external libraries like Google Play Services (16K methods!)
In your case you will just rip everything from Google Play Services jar except common internal and drive sub-packages.
For Eclipse users not using Gradle, there are tools that will break down the Google Play Services jar and rebuild it with only the parts you want.
I use strip_play_services.sh by dextorer.
It can be difficult to know exactly which services to include because there are some internal dependencies but you can start small and add to the configuration if it turns out that needed things are missing.
I think that in the long run breaking your app in multiple dex would be the best way.
Multi-dex support is going to be the official solution for this issue. See my answer here for the details.
If not to use multidex which making build process very slow.
You can do the following.
As yahska mentioned use specific google play service library.
For most cases only this is needed.
compile 'com.google.android.gms:play-services-base:6.5.+'
Here is all available packages Selectively compiling APIs into your executable
If this will be not enough you can use gradle script. Put this code in file 'strip_play_services.gradle'
def toCamelCase(String string) {
String result = ""
string.findAll("[^\\W]+") { String word ->
result += word.capitalize()
}
return result
}
afterEvaluate { project ->
Configuration runtimeConfiguration = project.configurations.getByName('compile')
println runtimeConfiguration
ResolutionResult resolution = runtimeConfiguration.incoming.resolutionResult
// Forces resolve of configuration
ModuleVersionIdentifier module = resolution.getAllComponents().find {
it.moduleVersion.name.equals("play-services")
}.moduleVersion
def playServicesLibName = toCamelCase("${module.group} ${module.name} ${module.version}")
String prepareTaskName = "prepare${playServicesLibName}Library"
File playServiceRootFolder = project.tasks.find { it.name.equals(prepareTaskName) }.explodedDir
def tmpDir = new File(project.buildDir, 'intermediates/tmp')
tmpDir.mkdirs()
def libFile = new File(tmpDir, "${playServicesLibName}.marker")
def strippedClassFileName = "${playServicesLibName}.jar"
def classesStrippedJar = new File(tmpDir, strippedClassFileName)
def packageToExclude = ["com/google/ads/**",
"com/google/android/gms/actions/**",
"com/google/android/gms/ads/**",
// "com/google/android/gms/analytics/**",
"com/google/android/gms/appindexing/**",
"com/google/android/gms/appstate/**",
"com/google/android/gms/auth/**",
"com/google/android/gms/cast/**",
"com/google/android/gms/drive/**",
"com/google/android/gms/fitness/**",
"com/google/android/gms/games/**",
"com/google/android/gms/gcm/**",
"com/google/android/gms/identity/**",
"com/google/android/gms/location/**",
"com/google/android/gms/maps/**",
"com/google/android/gms/panorama/**",
"com/google/android/gms/plus/**",
"com/google/android/gms/security/**",
"com/google/android/gms/tagmanager/**",
"com/google/android/gms/wallet/**",
"com/google/android/gms/wearable/**"]
Task stripPlayServices = project.tasks.create(name: 'stripPlayServices', group: "Strip") {
inputs.files new File(playServiceRootFolder, "classes.jar")
outputs.dir playServiceRootFolder
description 'Strip useless packages from Google Play Services library to avoid reaching dex limit'
doLast {
def packageExcludesAsString = packageToExclude.join(",")
if (libFile.exists()
&& libFile.text == packageExcludesAsString
&& classesStrippedJar.exists()) {
println "Play services already stripped"
copy {
from(file(classesStrippedJar))
into(file(playServiceRootFolder))
rename { fileName ->
fileName = "classes.jar"
}
}
} else {
copy {
from(file(new File(playServiceRootFolder, "classes.jar")))
into(file(playServiceRootFolder))
rename { fileName ->
fileName = "classes_orig.jar"
}
}
tasks.create(name: "stripPlayServices" + module.version, type: Jar) {
destinationDir = playServiceRootFolder
archiveName = "classes.jar"
from(zipTree(new File(playServiceRootFolder, "classes_orig.jar"))) {
exclude packageToExclude
}
}.execute()
delete file(new File(playServiceRootFolder, "classes_orig.jar"))
copy {
from(file(new File(playServiceRootFolder, "classes.jar")))
into(file(tmpDir))
rename { fileName ->
fileName = strippedClassFileName
}
}
libFile.text = packageExcludesAsString
}
}
}
project.tasks.findAll {
it.name.startsWith('prepare') && it.name.endsWith('Dependencies')
}.each { Task task ->
task.dependsOn stripPlayServices
}
project.tasks.findAll { it.name.contains(prepareTaskName) }.each { Task task ->
stripPlayServices.mustRunAfter task
}
}
Then apply this script in your build.gradle, like this
apply plugin: 'com.android.application'
apply from: 'strip_play_services.gradle'
If using Google Play Services, you may know that it adds 20k+ methods. As already mentioned, Android Studio has the option for modular inclusion of specific services, but users stuck with Eclipse have to take modularisation into their own hands :(
Fortunately there's a shell script that makes the job fairly easy. Just extract to the google play services jar directory, edit the supplied .conf file as needed and execute the shell script.
An example of its use is here.
If using Google Play Services, you may know that it adds 20k+ methods. As already mentioned, Android Studio has the option for modular inclusion of specific services, but users stuck with Eclipse have to take modularisation into their own hands :(
Fortunately there's a shell script that makes the job fairly easy. Just extract to the google play services jar directory, edit the supplied .conf file as needed and execute the shell script.
An example of its use is here.
Just like he said, I replaces compile 'com.google.android.gms:play-services:9.0.0' just with the libraries that I needed and it worked.

Categories

Resources