Longer build times will slow down project development, especially for large projects where the app is built for a long time of more than 10 minutes, short minutes, long build times have become a bottleneck for development, and this article is based on Google's official documentation, plus some of its own understanding to provide some optimization suggestions to improve the speed of the app build.
1, create a variant for the development environment
There are many configurations you need to prepare the release version of the app, but when you're developing the app you don't need it, turning on an unnecessary build process makes your incremental build or clean build slow, so you need to build a variant that only preserves the configuration you need to develop, as in the following example dev
and prod
variants (PROD is the release version of the configuration).
Android {.... defaultconfig {...} Buildtypes {...} productflavors {//When building a VARIANT that uses this flavor, the following configurations //override those in the default Config block. dev { //To avoid using legacy Multidex, set Minsdkversion to or higher. Minsdkversion versionnamesuffix "-dev" Applicationidsuffix '. Dev '} prod { //If you ' ve configured The Defaultconfig block for the release version of//Your app, you can leave this block empty and Gradle uses config Urations in //the defaultconfig block instead. You still need-to-create this flavor. //Otherwise, all variants use the "dev" flavor configurations. }}
2, avoid compiling unnecessary resources
To avoid compiling and including resources that you do not test (such as adding a local language and screen density resources), you can specify only one language and one screen density under your ' dev ' flavor, as follows:
android { ... productFlavors { dev { ... // The following configuration limits the "dev" flavor to using // English stringresources and xxhdpi screen-density resources. resConfigs "en", "xxhdpi" } ... }}
The above configuration will restrict the dev
variant to use only the English string resource and the xxhdpi screen density resource.
3. Configure the Crushlytics for debug build to be unavailable
In the debug build state, if you do not need to run a crash escalation, you can set the plugin to be unavailable to increase your build speed, as follows:
android { ... buildTypes { debug { false }}
Above is just for example, crushlytics for crash escalation analysis tool, in the development of the time we may not need, so do not need to open, in our actual development, such as crash escalation SDK, data statistics SDK, such as Friends of the league statistics, Growingio, Baidu statistics) in the development phase are set to be unavailable, to improve the build speed.
4. Build your debug version with static build configuration values
Generally, when your debug is built, use static/hard-coded values for the manifest file or resource file configuration. If the value of your manifest or resource file needs to be dynamically updated each time you build, instant Run cannot perform code exchange-it must rebuild and install the new apk.
For example, using dynamic version codes, version names, resources, or other build logic to change manifest files, each time you want to perform a change, you will build all the APK, even though the actual modification may only require a hot swap. If these build configurations need to be configured dynamically, separate them from your release build variants and retain their static values in your debug build. as shown in the following Build.gradle file:
int Millis_in_minute =1000 *60int minutessinceepoch = System.currenttimemillis ()/millis_in_minuteandroid {... defaultconfig {Making either of these, values dynamic in the Defaultconfig wouldRequire a full APK build and reinstallation because the Androidmanifest.xmlMust be updated (which was not supported by Instant Run). Versioncode1 versionname "1.0" ...} //The Defaultconfig values above is fixed, so your incremental builds don ' t //need to rebuild the manifest (and Therefore the whole APK, slowing build times). //But for release builds, it ' s okay. So the following script iterates through //all the known variants, finds those that is "release" Build types, and
//changes those properties to something dynamic. Applicationvariants.all {Variant
-and if (Variant.buildType.name = = "Release") { Variant.mergedFlavor.versionCode = Minutessinceepoch; Variant.mergedFlavor.versionName = Minutessinceepoch + "-" + Variant.flavorname;}}}
5, with static version dependent
When you declare dependencies in the Build.gradle file, you should avoid using the + sign where the version number ends, such as: com.android.tools.build:gradle:2.+
because Gradle's check is updated, using a dynamic version number causes an unknown version to be updated, making the differences between the resolution versions difficult and slower to build. You should use a static or hard-coded version number instead. such as: com.android.tools.build:gradle:2.2.2
.
6, enable on demand configuration to enable state
In order for Gradle to know exactly how to build your app, build all the modules and other dependencies of the system configuration project before each build (even if you just want to build or test a modules), which makes the large multi-module project very slow to build. Tell Gradle to simply configure the modules you want to build and use the following steps to make the on demand configuration available
(1) On the menu bar, select File---Settings (on Mac, select Android Studio->preferences)
(2) Navigate to Build,execution,deployment-Compiler
(3) Check Configure on demand check box
(4) Click OK
On_demand.png
7. Create Library Module
By examining the code in your app and extracting the modular code from an Android Library module, the modularity of your code will allow the build system to simply compile the modified modules and cache their build results for use in subsequent builds. The same configuration of On demand and parallel project execution (project parallel execution) will be more efficient (when you open these features).
8 Creating tasks for custom build logic
After you have created the build profile, and if the time to show a relatively long build time is spent in the Configure Project phase, then review your build.gradle script, and find the code that can be included in the custom Gradle task, by moving some of the build logic into a task, running when needed, the results can be cached for subsequent builds, and the build logic can be executed in parallel (if you turn on parallel execution of project), For more detailed information, please read the official Gradle documentation. Official Gradle Documentation
Tips:
If your build contains a lot of customization tasks, you may want to clean up your build.gradle files by customizing the task classes (that is, customizing the Gradle plugin) to add your classes to project-root/ Under the buildsrc/src/main/groovy/directory, Gradle will automatically include them to class path, all build.gradle files for the project.
9, configure dexoptions and turn on library pre-dexing (Dex preprocessing)
Add a point of Knowledge:dex-in-process: The newly released Android Studio 2.1 adds a new feature: The Dex in process, which can greatly speed up recompilation, also improves the performance of instant run. (10th Optimization recommendation will be said)
For details, see faster Android Studio Builds with Dex in Process
The Android plugin provides the dexoptions script block, so you can configure the appropriate DEX build features that can improve the build speed:
(1) Predexlibraaies: Declares whether the dependent library is being Dex preprocessed to make your incremental build faster, because this feature may slow down your clean build, so you might want to turn off this feature on your continuous integration server.
(2) Maxprocesscount: Set the maximum number of threads use when dex-in-process is running, the default value is 4.
(3) Javamaxheapsize: To set the maximum heap size for the Dex compiler, you should increase the heap size of gradle relative to setting this property (the heap size dex-in-process available when the Dex compiler Works)
Example:
android { ... dexOptions { true maxProcessCount 8 // Instead of setting the heap size for the DEX process, increase Gradle‘s // heap size to enable dex-in-process. To learm more, read the next section. // javaMaxHeapSize "2048m" }}
You should increase their values to test these settings, and then look at the results through profile, which can have a negative impact when you allocate too many resources to the process.
10. Increase the heap size of gradle and open dex-in-process
Dex-in-process allows multiple Dex processes to run in a single VM, which makes incremental build and cleanup builds faster. By default, new projects created with Android Studio2.1 or later are allocated enough memory to turn this feature on, and if you don't create a project using Android Studio 2.1 or later, You need to set a heap size memory of at least 1536MB to the Gradle background cantonment program. The default is as follows:
Gradle_heap.png
The following example sets the Gradle heap memory size to 2048MB in gradle.properties:
//设置Gradle 堆大小 2G
In some large projects, allocating more memory for the Gradle heap is certainly more advantageous, however, if you are using a small memory machine, you may need to configure less memory for the IDE, and want to know how to change the amount of resources allocated to the IDE and the impact of Gradle on the build performance, see profiling your build
this article.
If Javamaxheapsize ' is 1280MB in your module Build.gradle file, android.dexOptions.javaMaxHeapSize定义了一个值,那么你需要给Gradle的堆大小设置 的值为比javaMaxHeapSize多512MB,并且满足至少为1536MB。举个例子:在build.gradle中设置
then you will have to set the Gradle heap size at least 1792MB (1280 + 512), of course, setting a bit larger is better.
Build.gradle:
dexOptions { "1280m" }
Gradle.properties:
org.gradle.jvmargs = -Xmx1792m
11. Convert picture to WEBP format
WEBP is a picture file format that provides lossy compression like JPEG and transparent support like PNG, but at the same time its compression quality is better than either JPEG or PNG, reducing the size of the image file rather than compressing it at build time, so it can improve the build speed, In particular, your app uses a lot of picture resources. But one thing, when extracting images from the WEBP format, your device's CPU usage will increase in small increments. with Android Studio you can easily go to WebP format, see convert your images to WebP for details.
Tip: In addition, converting the images in the project to WEBP format is also a direction to optimize the APK volume, WEBP is the Android native 4.0 started to support, it can provide JPEG and PNG same quality picture but size smaller. There is no problem with adaptation.
12, do not use PNG crunching
If you can't (or don't want to) convert your PNG format picture to WEBP, you can still increase the build speed by banning the images from being automatically compressed every time you build the app, to disable this optimization, build.gradle
add the following code:
android { ... aaptOptions { false }}
13, use Instant Run
Instant run significantly reduces the time to update the app by pushing the identified code, resource changes without building a new app, and, in some cases, not even restarting the current activity, after the code changes, using Instant Run by clicking Apply changes(yellow?? icon). When you have done the following steps, it will open by default:
- Build your app with Debug build variants
- Gradle plug-in version 2.3.0 or higher
- Set to 15 or higher in the build.gradle of the module level
minSdkVersion
- Publish your app on Android 5.0 (API level 21) or higher click Run.
14, using Build cache
When building your project, the build cache stores the deterministic artifacts generated by the Android Gradle plugin (such as the AAR package and the remote dependent pre-dexed). When you use caching, your cleanup builds faster because building system builds can easily reuse their caches without recreating them.
The new project uses the Android Gradle plugin 2.3.0 or later to turn on the build cache by default (unless you manually turn it off), read the accelerate clean builds with build caches.
15, disable the use of the annotation processor
Gradle 2.1 can be incrementally built after Java, when using the annotation processor when the incremental build will not be available, if possible, avoid the use of the annotation processor, so you can only build the changed class to benefit. (Increase compilation time)
16. Analyze your build (profile your build)
In large projects (or with a large number of custom build logic implementations), you may need a deeper understanding of the build process to find bottlenecks, and you can analyze how long each gradle task executes during each phase of the build lifecycle. For example, if your build profile shows that Gradle spends a lot of time configuring your project, it suggests that you need to put your custom build logic outside of the configuration phase. Also, if the mergedevdebugresources task consumes a lot of build time, it indicates that you need to convert the image to WEBP format or prohibit PNG crunching ( 11th, 12 optimization recommendations )
Building analytics to improve your build speed often requires running your build with analysis turned on, modifying build configurations, analyzing and observing the changes in the results multiple times.
To build and view the build profile, perform the following steps:
1. Open the project with Android Studio, select View---Tool Windows--Terminal Open command line
2, execute clean build input The following command, when you analyze your build, you need to perform a clean build operation between each build, because Gradle will skip the input unchanged tasks, therefore, The second build that does not change the input usually runs faster because tasks are not re-run, so running a task between builds clean
ensures that you analyze the entire build process.
//如果在Mac 或者 Linux上 用 ./gradlewgradlew clean
3, select one of the product flavors (products flavor) to perform the debug build, such as: dev
flavor, as follows:
gradlew --profile --recompile-scripts --offline --rerun-tasks assembleFlavorDebug
Command analysis:
--profile
: Open Profiling
--recompile-scripts
: Force script recompilation Skip Cache
--offline
: Prohibit Gradle from obtaining offline dependencies, which is to ensure that any delay is caused by gradle trying to update dependencies and will not mislead you with your analytical data. You should be ready to build a project to make sure that Gradle has been downloaded and cache dependent.
--rerun-tasks
: Forces Gradle to return all tasks and ignores any task optimizations.
4, after the build is finished, the project-root/build/reports/profile/directory:
Profile_build.png
5 Right click on profile_timestamp.html, select Open in Browser, you will see this picture, you can observe each tab in the report to understand your build, such as tasks execution shows the time of each task execution.
Profile_in_brower.png
Task execution shows the execution duration of each task, such as:
Task_execution.png
6, Optional: Repeat steps 3 several times before you make any changes to project or build configuration, but remove the --rerun-tasks
flag because Gradle attempts to save time without re-executing the task that entered without any modification (they are flagged as up-to-date Under Task Execution tab, such as:), you can identify which tasks have not been executed, for example, if they are :app:processDevUniversalDebugManifest
not marked UP-TO-DATE
, then it means that your build configuration is dynamically updating Manifest
files for each build. However, there are some tasks that need to be executed every time, such as::app:checkDevDebugManifest
Profile_up_to_date.png
Now that you have a build analysis report, you can start looking for optimization by observing each tab of the build report, and some build configurations need to be tested because they benefit differently in different projects or workspaces. For example, large projects based on large amounts of code may benefit from using confusion, cleaning up useless code, and reducing the APK volume. Small projects, however, may benefit from close confusion (confusing or time-consuming). In addition, it is possible to increase or decrease the heap size of gradle on the machine that is in memory, which may also play a negative role.
17, Project component
For large projects, may have some of the above optimization recommendations have some effect, but the construction speed is still some slow, then you can consider the formation of the project into a separate component, the development environment each module is an APK, when released, each module is a Lib Used for the main project. The space is valid, here is no longer detailed introduction of the component, now the component is a trend, if there is energy or strength, the component is a very good choice.
17 Tips for Android optimized app build speed