如何在dex中缩码- 65k方法限制

时间:2021-06-22 20:48:23

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.

我有一个相当大的Android应用程序,它依赖于许多库项目。Android编译器对每个.dex文件有65536个方法的限制,我正在超越这个数字。

There are basically two paths you can choose (at least that I know of) when you hit the method limit.

当遇到方法限制时,基本上有两种路径可供选择(至少我知道)。

1) Shrink your code

1)缩小您的代码

2) Build multiple dex files (see this blog post)

2)构建多个dex文件(参见本文)

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!

我研究了这两种方法,试图找出是什么导致我的方法计数如此之高。谷歌驱动器API占据了最大的一块,番石榴依赖项超过12000。驱动API v2的总libs达到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)?

我的问题是,你认为我应该怎么做?我应该删除谷歌驱动器集成作为我的应用的一个特性吗?是否有一种方法可以缩小API(是的,我使用proguard)?我应该走多重dex路线(看起来相当痛苦,尤其是处理第三方api)吗?

12 个解决方案

#1


65  

It looks like Google has finally implementing a workaround/fix for surpassing the 65K method limit of dex files.

看来谷歌终于实现了一个解决方案/修复方案,以超越dex文件的65K方法限制。

About the 65K Reference Limit

关于65K参考极限

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.

Android应用程序(上年)文件包含可执行字节码文件的形式Dalvik可执行文件(敏捷)文件,它包含编译后的代码用于运行您的应用程序。Dalvik可执行规范限制的总数的方法可以在单个DEX文件引用到65536年,包括Android框架方法,在您自己的代码库的方法,和方法。要突破这个限制,需要配置应用程序构建过程以生成多个DEX文件,称为multidex配置。

Multidex support prior to Android 5.0

在Android 5.0之前支持Multidex

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.

Android 5.0之前的版本使用Dalvik运行时执行应用程序代码。默认情况下,Dalvik将应用程序限制为单个类。为了绕过这个限制,您可以使用multidex support库,它成为应用程序的主要DEX文件的一部分,然后管理对其他DEX文件及其包含的代码的访问。

Multidex support for Android 5.0 and higher

支持安卓5.0或更高版本

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.

Android 5.0或更高版本使用了一个叫做ART的运行时,它支持从应用程序APK文件加载多个dex文件。ART在应用程序安装时执行预编译,扫描类(..N).dex文件并将它们编译成一个.oat文件,由Android设备执行。有关Android 5.0运行时的更多信息,请参见介绍ART。

See: Building Apps with Over 65K Methods

参见:使用超过65K的方法构建应用程序


Multidex Support Library

Multidex支持库

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.

该库提供了支持构建具有多个Dalvik可执行文件的应用程序。需要使用超过65536个方法的应用程序需要使用multidex配置。有关使用multidex的更多信息,请参见使用超过65K方法构建应用程序。

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.

这个库位于/extras/android/support/multidex/目录中,然后下载android support库。该库不包含用户界面资源。要将它包含在应用程序项目中,请遵循添加没有资源的库的说明。

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.

com.android.support:multidex:1.0。+此依赖符号指定版本1.0.0或更高版本。


You should still avoid hitting the 65K method limit by actively using proguard and reviewing your dependencies.

您仍然应该通过积极使用proguard并检查您的依赖项来避免达到65K方法的限制。

#2


50  

you can use the multidex support library for that, To enable multidex

您可以使用multidex支持库,以启用multidex

1) include it in dependencies:

1)在依赖项中包含:

dependencies {
  ...
  compile 'com.android.support:multidex:1.0.0'
}

2) Enable it in your app:

2)在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:

3)如果你的应用程序有一个应用程序类,那么你可以用以下方法来覆盖attachBaseContext方法:

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:

如果您的应用程序没有应用程序类,那么注册android.support.multidex。MultiDexApplication是您的清单文件中的应用程序。是这样的:

<application
    ...
    android:name="android.support.multidex.MultiDexApplication">
    ...
</application>

and it should work fine!

它应该能正常工作!

#3


31  

Play Services 6.5+ helps: http://android-developers.blogspot.com/2014/12/google-play-services-and-dex-method.html

Play Services 6.5+帮助: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"

“从谷歌播放服务的6.5版本开始,您可以从许多独立的api中选择,您可以看到”

...

"this will transitively include the ‘base’ libraries, which are used across all APIs."

“这将包括跨所有api使用的‘基本’库。”

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.:

API名称的完整列表如下。更多细节可以在Android开发者网站上找到。

  • com.google.android.gms:play-services-base:6.5.87
  • 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-ads:6.5.87
  • com.google.android.gms:play-services-appindexing: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-maps:6.5.87
  • com.google.android.gms:play-services-location: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-fitness:6.5.87
  • com.google.android.gms:play-services-panorama: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-drive:6.5.87
  • com.google.android.gms:play-services-games: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-wallet:6.5.87
  • com.google.android.gms:play-services-identity: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-cast:6.5.87
  • com.google.android.gms:play-services-plus: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-appstate:6.5.87
  • com.google.android.gms:play-services-wearable:6.5.87
  • com.google.android.gms:play-services-wearable:6.5.87
  • com.google.android.gms:play-services-all-wear:6.5.87
  • com.google.android.gms:play-services-all-wear:6.5.87

#4


8  

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.

在6.5之前版本的谷歌播放服务,你必须编译整个包到您的应用程序的api。在某些情况下,这样做使它更难保持方法的数量在你的应用程序(包括框架api,库方法和自己的代码)根据65536年极限。

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:

从6.5版本开始,你可以选择性地编译谷歌播放服务api到你的应用程序中,例如,只包括谷歌Fit和Android Wear api,在你的构建中替换下面的行。gradle文件:

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

如需更多参考,请点击这里

#5


7  

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) :

使用proguard来减轻您的apk,因为在您的最终构建中没有使用的方法。在您的proguard配置文件中,再次检查您是否使用了与番石榴一起使用的proguard(我很抱歉,如果您已经有了这个,在编写本文时它还不为人知):

# 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 :

此外,如果您正在使用ActionbarSherlock,那么切换到v7 appcompat支持库也将大大减少您的方法计数(基于个人经验)。指令都位于:

#6


7  

You could use Jar Jar Links to shrink huge external libraries like Google Play Services (16K methods!)

您可以使用Jar链接来收缩大型外部库,比如谷歌Play服务(16K方法!)

In your case you will just rip everything from Google Play Services jar except common internal and drive sub-packages.

在您的示例中,您将从谷歌Play Services jar中提取所有内容,除了常见的内部和驱动器子包。

#7


4  

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.

对于不使用Gradle的Eclipse用户,有一些工具可以分解谷歌Play服务jar,并仅用您想要的部分重新构建它。

I use strip_play_services.sh by dextorer.

我使用strip_play_services。由dextorer sh。

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.

很难确切地知道要包含哪些服务,因为存在一些内部依赖关系,但是如果发现需要的东西丢失了,那么您可以启动小的并添加到配置中。

#8


3  

I think that in the long run breaking your app in multiple dex would be the best way.

我认为从长远来看,将你的应用程序分成多个dex是最好的方式。

#9


2  

Multi-dex support is going to be the official solution for this issue. See my answer here for the details.

多食典委的支持将是这个问题的官方解决方案。详情请看我的回答。

#10


2  

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.

如果不使用multidex,会使构建过程非常缓慢。您可以执行以下操作。正如yahska提到的,使用特定的谷歌播放服务库。对于大多数情况,这是必需的。

compile 'com.google.android.gms:play-services-base:6.5.+'

Here is all available packages Selectively compiling APIs into your executable

这里是所有可用的包,有选择地将api编译到您的可执行文件中。

If this will be not enough you can use gradle script. Put this code in file 'strip_play_services.gradle'

如果这还不够的话,你可以使用渐变脚本。将此代码放入文件'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

然后在构建中应用这个脚本。gradle,像这样

apply plugin: 'com.android.application'
apply from: 'strip_play_services.gradle'

#11


1  

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 :(

如果使用谷歌播放服务,您可能知道它添加了20k+方法。如前所述,Android Studio可以选择模块化包含特定的服务,但使用Eclipse的用户必须自己动手进行模块化:

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.

幸运的是,有一个shell脚本使这项工作相当容易。只需提取到谷歌播放服务jar目录,根据需要编辑提供的.conf文件,并执行shell脚本。

An example of its use is here.

这里有一个使用它的例子。

#12


1  

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 :(

如果使用谷歌播放服务,您可能知道它添加了20k+方法。如前所述,Android Studio可以选择模块化包含特定的服务,但使用Eclipse的用户必须自己动手进行模块化:

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.

幸运的是,有一个shell脚本使这项工作相当容易。只需提取到谷歌播放服务jar目录,根据需要编辑提供的.conf文件,并执行shell脚本。

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.

就像他说的,我用我所需要的库来代替编译的com.google.android.gms:play-services:9.0.0。

#1


65  

It looks like Google has finally implementing a workaround/fix for surpassing the 65K method limit of dex files.

看来谷歌终于实现了一个解决方案/修复方案,以超越dex文件的65K方法限制。

About the 65K Reference Limit

关于65K参考极限

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.

Android应用程序(上年)文件包含可执行字节码文件的形式Dalvik可执行文件(敏捷)文件,它包含编译后的代码用于运行您的应用程序。Dalvik可执行规范限制的总数的方法可以在单个DEX文件引用到65536年,包括Android框架方法,在您自己的代码库的方法,和方法。要突破这个限制,需要配置应用程序构建过程以生成多个DEX文件,称为multidex配置。

Multidex support prior to Android 5.0

在Android 5.0之前支持Multidex

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.

Android 5.0之前的版本使用Dalvik运行时执行应用程序代码。默认情况下,Dalvik将应用程序限制为单个类。为了绕过这个限制,您可以使用multidex support库,它成为应用程序的主要DEX文件的一部分,然后管理对其他DEX文件及其包含的代码的访问。

Multidex support for Android 5.0 and higher

支持安卓5.0或更高版本

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.

Android 5.0或更高版本使用了一个叫做ART的运行时,它支持从应用程序APK文件加载多个dex文件。ART在应用程序安装时执行预编译,扫描类(..N).dex文件并将它们编译成一个.oat文件,由Android设备执行。有关Android 5.0运行时的更多信息,请参见介绍ART。

See: Building Apps with Over 65K Methods

参见:使用超过65K的方法构建应用程序


Multidex Support Library

Multidex支持库

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.

该库提供了支持构建具有多个Dalvik可执行文件的应用程序。需要使用超过65536个方法的应用程序需要使用multidex配置。有关使用multidex的更多信息,请参见使用超过65K方法构建应用程序。

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.

这个库位于/extras/android/support/multidex/目录中,然后下载android support库。该库不包含用户界面资源。要将它包含在应用程序项目中,请遵循添加没有资源的库的说明。

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.

com.android.support:multidex:1.0。+此依赖符号指定版本1.0.0或更高版本。


You should still avoid hitting the 65K method limit by actively using proguard and reviewing your dependencies.

您仍然应该通过积极使用proguard并检查您的依赖项来避免达到65K方法的限制。

#2


50  

you can use the multidex support library for that, To enable multidex

您可以使用multidex支持库,以启用multidex

1) include it in dependencies:

1)在依赖项中包含:

dependencies {
  ...
  compile 'com.android.support:multidex:1.0.0'
}

2) Enable it in your app:

2)在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:

3)如果你的应用程序有一个应用程序类,那么你可以用以下方法来覆盖attachBaseContext方法:

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:

如果您的应用程序没有应用程序类,那么注册android.support.multidex。MultiDexApplication是您的清单文件中的应用程序。是这样的:

<application
    ...
    android:name="android.support.multidex.MultiDexApplication">
    ...
</application>

and it should work fine!

它应该能正常工作!

#3


31  

Play Services 6.5+ helps: http://android-developers.blogspot.com/2014/12/google-play-services-and-dex-method.html

Play Services 6.5+帮助: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"

“从谷歌播放服务的6.5版本开始,您可以从许多独立的api中选择,您可以看到”

...

"this will transitively include the ‘base’ libraries, which are used across all APIs."

“这将包括跨所有api使用的‘基本’库。”

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.:

API名称的完整列表如下。更多细节可以在Android开发者网站上找到。

  • com.google.android.gms:play-services-base:6.5.87
  • 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-ads:6.5.87
  • com.google.android.gms:play-services-appindexing: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-maps:6.5.87
  • com.google.android.gms:play-services-location: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-fitness:6.5.87
  • com.google.android.gms:play-services-panorama: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-drive:6.5.87
  • com.google.android.gms:play-services-games: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-wallet:6.5.87
  • com.google.android.gms:play-services-identity: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-cast:6.5.87
  • com.google.android.gms:play-services-plus: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-appstate:6.5.87
  • com.google.android.gms:play-services-wearable:6.5.87
  • com.google.android.gms:play-services-wearable:6.5.87
  • com.google.android.gms:play-services-all-wear:6.5.87
  • com.google.android.gms:play-services-all-wear:6.5.87

#4


8  

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.

在6.5之前版本的谷歌播放服务,你必须编译整个包到您的应用程序的api。在某些情况下,这样做使它更难保持方法的数量在你的应用程序(包括框架api,库方法和自己的代码)根据65536年极限。

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:

从6.5版本开始,你可以选择性地编译谷歌播放服务api到你的应用程序中,例如,只包括谷歌Fit和Android Wear api,在你的构建中替换下面的行。gradle文件:

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

如需更多参考,请点击这里

#5


7  

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) :

使用proguard来减轻您的apk,因为在您的最终构建中没有使用的方法。在您的proguard配置文件中,再次检查您是否使用了与番石榴一起使用的proguard(我很抱歉,如果您已经有了这个,在编写本文时它还不为人知):

# 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 :

此外,如果您正在使用ActionbarSherlock,那么切换到v7 appcompat支持库也将大大减少您的方法计数(基于个人经验)。指令都位于:

#6


7  

You could use Jar Jar Links to shrink huge external libraries like Google Play Services (16K methods!)

您可以使用Jar链接来收缩大型外部库,比如谷歌Play服务(16K方法!)

In your case you will just rip everything from Google Play Services jar except common internal and drive sub-packages.

在您的示例中,您将从谷歌Play Services jar中提取所有内容,除了常见的内部和驱动器子包。

#7


4  

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.

对于不使用Gradle的Eclipse用户,有一些工具可以分解谷歌Play服务jar,并仅用您想要的部分重新构建它。

I use strip_play_services.sh by dextorer.

我使用strip_play_services。由dextorer sh。

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.

很难确切地知道要包含哪些服务,因为存在一些内部依赖关系,但是如果发现需要的东西丢失了,那么您可以启动小的并添加到配置中。

#8


3  

I think that in the long run breaking your app in multiple dex would be the best way.

我认为从长远来看,将你的应用程序分成多个dex是最好的方式。

#9


2  

Multi-dex support is going to be the official solution for this issue. See my answer here for the details.

多食典委的支持将是这个问题的官方解决方案。详情请看我的回答。

#10


2  

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.

如果不使用multidex,会使构建过程非常缓慢。您可以执行以下操作。正如yahska提到的,使用特定的谷歌播放服务库。对于大多数情况,这是必需的。

compile 'com.google.android.gms:play-services-base:6.5.+'

Here is all available packages Selectively compiling APIs into your executable

这里是所有可用的包,有选择地将api编译到您的可执行文件中。

If this will be not enough you can use gradle script. Put this code in file 'strip_play_services.gradle'

如果这还不够的话,你可以使用渐变脚本。将此代码放入文件'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

然后在构建中应用这个脚本。gradle,像这样

apply plugin: 'com.android.application'
apply from: 'strip_play_services.gradle'

#11


1  

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 :(

如果使用谷歌播放服务,您可能知道它添加了20k+方法。如前所述,Android Studio可以选择模块化包含特定的服务,但使用Eclipse的用户必须自己动手进行模块化:

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.

幸运的是,有一个shell脚本使这项工作相当容易。只需提取到谷歌播放服务jar目录,根据需要编辑提供的.conf文件,并执行shell脚本。

An example of its use is here.

这里有一个使用它的例子。

#12


1  

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 :(

如果使用谷歌播放服务,您可能知道它添加了20k+方法。如前所述,Android Studio可以选择模块化包含特定的服务,但使用Eclipse的用户必须自己动手进行模块化:

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.

幸运的是,有一个shell脚本使这项工作相当容易。只需提取到谷歌播放服务jar目录,根据需要编辑提供的.conf文件,并执行shell脚本。

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.

就像他说的,我用我所需要的库来代替编译的com.google.android.gms:play-services:9.0.0。