Current version is 1.3.2
This is an easy-to-use plugin for existing and newly created android projects. It is tested and developed against 0.12.x and 0.13.x.
The plugin supports normal android projects and projects that reference
library projects. 3rd party libraries can be included by placing them in
libs as in regular projects, or they can be added by using sbt's
libraryDependencies feature.
1.3.2: addAutoPluginsupport for0.13.5- Auto-set
localProjectswhen usingandroid.Plugin.androidBuild(...) - When
gen-android,gen-android, andandroid.AutoBuildrequire0.13.5if on the0.13.xsbt line. - Some refactoring of classes out of
android.Keys, should be mostly compatible still.
- Auto-set
1.3.1: addandroid:apkbuild-pickfirstsworks likeandroid:apkbuild-excludesbut picks the first occurrence of the resource.- A bug in com.android.tools.build:builder, https://code.google.com/p/android/issues/detail?id=73437, prevents PackagingOptions from working correctly with JNI libraries. A workaround is implemented copy all JNI to a single location first.
- NDK build process, similarly to
ANDROID_HOME, setANDROID_NDK_HOMEto the location where the Android NDK is installed. Alternatively,ndk.dircan be set in alocal.propertiesfile for the project.- libs will be generated into
binPath / "jni"and obj will drop intobinPath / "obj" - Pre-generated JNI libraries will no longer be pulled out of
jni(norsrc/main/jni) -- they will be taken fromlibs(orsrc/main/libs)- This does not apply to aar and apklib--they will be pulled out of appropriate locations per their spec.
javahis automatically executed on all classes that havenativemethods in their signatures. The header files are generated intosourceManagedand are available to include in native sources andAndroid.mkby addingLOCAL_CFLAGS := -I$(SBT_SOURCE_MANAGED)collect-jnino longer copies libraries, it only assembles a list of directory names for packaging
- libs will be generated into
- Global plugin installation friendly
- For sbt 0.13, add to
~/.sbt/0.13/plugins/android.sbt - For sbt 0.12, add to
~/.sbt/plugins/android.sbt addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.3.2")
- For sbt 0.13, add to
- New commands, all commands have proper tab-completion:
gen-android- creates android projects from scratch with sbt plumbinggen-android-sbt- creates SBT files for an existing android projectlogcat- supports all regular options, non-polling (-d by default)pidcat- logcat the current package or specified package with TAG filtersadb-ls- ls on-deviceadb-cat- cat a file on-deviceadb-rm- rm a file on-deviceadb-shell- execute a shell command on-deviceadb-push- push a file to deviceadb-pull- pull a file from devicereboot-devicerenamed toadb-reboot
- Existing commands available globally
devices,device,adb-wifi
AutoBuildsupport, (created automatically withgen-android), set your build to beobject Build extends android.AutoBuildand settings will be automatically applied to projects as necessary.- Update to latest
com.android.tools.build0.12.x- Now requires android build-tools
19.1.0or newer
- Now requires android build-tools
minSdkVersionandtargetSdkVersionare nowSettingKey[String]and no longerSettingKey[Int](support android-L)- Instrumentation tests are now located in
src/main/androidTestinstead ofsrc/main/instrumentTest(match layout generated by android create project) android:dextask now returns a folder for the output dex not aclasses.dexfile.
- Add setting
android:debug-includes-tests(default = true) to automatically include instrumented test cases in the debug APK instead of using a separate test APK. This feature improves IntelliJ testing integration.-
As a result of this new feature, if there are any
libraryDependenciesintestthat must be honored, the setting must be disabled, and a separate test APK must be created. An alternative is to include the test dependencies in the normal compile. Proguard will automatically strip these out in release builds if they are unused. -
This setting may be ignored, or set to
falseif one does not have tests or does not want to include the test cases in the debug package. -
If the setting is disabled, test cases will be generated into a test APK when running
android:test -
When generating release builds, it is important to
clean, otherwise test artifacts may be left over and present in the released apk. -
When using included tests, it is necessary to add the following proguard options, or else proguard will mistakenly remove test cases from the output:
proguardOptions in Android ++= Seq( "-keep public class * extends junit.framework.TestCase", "-keepclassmembers class * extends junit.framework.TestCase { *; }" )
-
- Add ability to disable manifest merging if upstream libraries have bad
manifest settings, set
mergeManifests in Android := false, default istrue- Disabling manifest merging will remove automatic import of Activities, Services, BroadcastReceivers, etc. from the library's manifest into the main application manifest
- Increase test timeout to 3 minutes, from 5 seconds, configurable by using the
instrumentTestTimeoutsetting key, in milliseconds - Add
apkbuildExcludessetting to skip/ignore duplicate files, an error like this:Can be rectified by setting[info] com.android.builder.packaging.DuplicateFileException: Duplicate files copied in APK META-INF/LICENSE.txt [info] File 1: /path1/some.jar [info] File 2: /path2/some.jarapkbuildExcludes in Android += "META-INF/LICENSE.txt" 1.2.18:zipalignPathhas changed from a Setting into a Task
- Automatically load declared library projects from
project.properties,build.scalais no longer necessary to configure the library projects, unless other advanced features are necessary (this means that any android project that only uses library projects does not need to use multi-project configurations).-
For those not using
project.propertiesan alternative is to addandroid.Dependencies.AutoLibraryProject(path)s tolocal-projectsimport android.Keys._ import android.Dependencies.AutoLibraryProject localProjects in Android <+= (baseDirectory) { b => AutoLibraryProject(b / ".." / "my-library-project") }
-
version-codeandversion-nameare defaulted to no-ops (no overrides)- They can be set programmatically using an sbt
Command
- They can be set programmatically using an sbt
- instrumented tests now go into
src/instrumentTestin gradle-layout projects- a test
AndroidManifest.xmlwill be automatically generated if not present
- a test
- Customizable proguard caching!
- Proguard cache rules are defined using the
proguardCache in Androidsetting, the rules are of typeandroid.Keys.ProguardCacheand can be defined like so:- The default cache rule is defined as
ProguardCache("scala") % "org.scala-lang", this caches all scala core libraries automatically. proguardCache in Android += ProguardCache("play") % "play" %% "play-json"will match all packages and classes contained inplay.**from the module defined by the organization nameplayand module nameplay-json.%%specifies that the module name should be cross-versioned for detecting a match.%can be used to select the plain module name without scala cross-versioning. If a module name is not specified, all libraries in the selected organization will be cached with the package names passed toProguardCache()... <+= baseDirectory (b => ProguardCache("android.support.v4") << (b / "libs / "android-support-v4.jar))"will cacheandroid.support.v4.**from the local jarlibs/android-support-v4.jar- All packages within a jar to be cached MUST be declared in the rule or else many NoClassDefFound errors will ensue!
- Multiple packages may be specified in a cache rule:
ProguardCache("package1", "package2", "package3") ... - All ProguardCache rules must be associated with a module-org+name or a local jar file.
- Defining many cache rules will result in a higher cache-miss rate, but will dramatically speed up builds on cache-hits; choose libraries and caching rules carefully to balance the the cache-hit ratio. Large, multi-megabyte libraries should always be cached to avoid hitting the dex-file method-limit.
- Transitive dependencies are not cached automatically, those rules need to be defined explicitly.
- The default cache rule is defined as
- Fixes NoSuchMethodError sometimes occuring when re-building after a proguard cache-miss (clear dex file on the first cache-hit build after proguarding; caused by dex incremental builds)
- Add a better method of specifying local-projects besides only in
project.properties, or overriding library-projects in a convoluted manner.
use
localProjects in Android += android.Dependencies.LibraryProject(lib_project.base)settings to add library projects without declaring them inproject.propertiesor otherwise - Add
local-aarssetting to allow the use of AARs without a repo. - Add
android.ArbitraryProjectload any project you want from a git repo, see this example for details.
- A variety of my own projects can be found on github that use this plugin
- In addition to this, a growing collection of tests can be found under
sbt-test/android-sdk-plugin/. Over time, this will grow to be a larger set of examples of how to use the plugin in various configurations. - Tests can be run via
sbt scriptedand requireANDROID_HOMEto be set in addition to having platformandroid-17installed. - All tests have auto-generated
build.propertiesandauto_plugins.sbtfiles that set the current version of sbt and the android-sdk-plugin to use for testing.
-
Install sbt (from http://www.scala-sbt.org or use your local packaging system like macports, brew, etc.) -- make sure the Android SDK is fully updated (minimum build-tools 19.1.0 and up)
- (OPTIONAL) Install the plugin globally into
~/.sbt/pluginsor~/.sbt/0.13/plugins(for 0.12 and 0.13, respectively)
addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.3.2") - (OPTIONAL) Install the plugin globally into
-
Create a new android project using
gen-androidif the plugin is installed globally- Instead of creating a new project, one can also do
android update projectto make sure everything is properly setup in an existing project. - Instead of keeping local.properties up-to-date, you may set the
environment variable
ANDROID_HOMEpointing to the path where the Android SDK is unpacked. This will bypass the requirement of having to runandroid update projecton existing projects. - When using
gen-android, theplatformTargetis automatically set to the newest version available in your local SDK, override this by settingtargetin aproject.propertiesfile, or settingplatformTarget in Android
- Instead of creating a new project, one can also do
-
(N/A if globally configured) Create a directory named
projectwithin your project and add the fileproject/plugins.sbt, in it, add the following line:addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.3.2") -
Create a file named
project/build.scalaand add the following line, (automatically performed if usinggen-android) :object Build extends android.Build -
Now you will be able to run SBT, some available commands in sbt are:
compile- Compiles all the sources in the project, java and scala
- Compile output is automatically processed through proguard if there are any Scala sources, otherwise; it can be enabled manually.
android:package-release- Builds a release APK and signs it with a release key if configured
android:package-debug- Builds a debug APK and signs it using the debug key
android:package- Builds an APK for the project of the last type selected, by default
debug
- Builds an APK for the project of the last type selected, by default
android:test- run instrumented android unit tests
android:install- Install the application to device
android:run- Install and run the application on-device
android:uninstall- Uninstall the application from device
- Any task can be repeated continuously whenever any source code changes
by prefixing the command with a
~.~ android:package-debugwill continuously build a debug build any time one of the project's source files is modified.
-
If you want android-sdk-plugin to automatically sign release packages add the following lines to
local.properties(or any file.properties of your choice that you will not check in to source control):key.alias: YOUR-KEY-ALIASkey.store: /path/to/your/.keystorekey.store.password: YOUR-KEY-PASSWORDkey.store.type: pkcs12(optional, defaults tojks)
-
IDE integration
- The primary IDE recommendation is IntelliJ, not Android Studio nor Eclipse.
- To generate project files for loading into IntelliJ, use the
sbt-ideaplugin by addingaddSbtPlugin("com.hanhuy.sbt" % "sbt-idea" % "1.7.0-SNAPSHOT")to yourproject/plugins.sbtand running the commandsbt gen-idea- This requires the snapshots repo which can be done by adding
resolvers += Resolver.sbtPluginRepo("snapshots") - Use my snapshot of sbt-idea until mpeltonen/sbt-idea#314 is merged
- As with this plugin, sbt-idea may be installed globally as well.
- This requires the snapshots repo which can be done by adding
- When loading a project into IntelliJ, it is required that the
SBTandScalaplugins are installed; theSBTplugin allows replacing the defaultMakebuilder with sbt, enabling seamless builds from the IDE. - The best practice is to set the IDE's run task to invoke sbt
android:packageinstead ofMake; this is found under the Run Configurations - The SBT plugin for IntelliJ is the one from this project https://github.com/orfjackal/idea-sbt-plugin
- The
Scalaplugin is still required for non-Scala projects in order to edit sbt build files from inside the IDE.
-
Consuming apklib and aar artifacts from other projects
- Optionally use
apklib()oraar()- using
apklib()andaar()are only necessary if there are multiple filetypes for the dependency, such asjar, etc.
- using
libraryDependencies += apklib("groupId" % "artifactId" % "version", "optionalArtifactFilename")- Basically, wrap the typical dependency specification with either apklib() or aar() to consume the library
- If aars or apklibs are duplicately included in a multi-project build,
specify
transitiveAndroidLibs in Android := false apklibandaarthat transitively depend onapklibandaarwill automatically be processed. To disable settransitiveAndroidLibs in Android := false
- Sometimes library projects and apklibs will incorrectly bundle
android-support-v4.jar, to rectify this, add this setting:
dependencyClasspath in Compile ~= { _ filterNot (_.data.getName startsWith "android-support-v4") }
- Optionally use
-
Using the google gms play-services aar:
libraryDependencies += "com.google.android.gms" % "play-services" % "4.4.52" -
Generating apklib and/or aar artifacts
- To specify that your project will generate and publish either an
aarorapklibartifact simply change theandroid.Plugin.androidBuildline to one of the variants that will build the desired output type.- For
apklibuseandroid.Plugin.androidBuildApklib - For
aaruseandroid.Plugin.androidBuildAar
- For
- Alternatively, use
android.Plugin.buildAarand/orandroid.Plugin.buildApklibin addition to any of the variants above- In build.sbt, add
android.Plugin.buildAarand/orandroid.Plugin.buildApklibon a new line. - It could also be specified, for example, like so:
android.Plugin.androidBuild ++ android.Plugin.buildAar
- In build.sbt, add
- To specify that your project will generate and publish either an
-
Multi-project builds
- See multi-project build examples in the test cases for an example of configuration.
- Multi-project builds must specify
transitiveAndroidLibs in Android := falseif any of the subprojects includeaars orapklibs as dependencies. androidBuild(...)should be used to specify all dependent library-projects- All sub-projects in a multi-project build must specify
exportJars := true. Android projects automatically set this variable. - When using multi-project builds in Scala, where library projects have
scala code, but the main project(s) do(es) not, you will need to specify
that proguard must run. To do this, the following must be set for each
main project:
proguardScala in Android := true
-
Configuring
android-sdk-pluginby editing build.sbtimport android.Keys._at the top to make sure you can use the plugin's configuration options (not required with sbt 0.13.5+ and AutoPlugin)- Add configuration options according to the sbt style:
useProguard in Android := trueto enable proguard. Note: if you disable proguard for scala, you must specify uses-library on a pre-installed scala lib on-device. Pre-dexing the scala libs is not supported.
- Configurable keys can be discovered by typing
android:<tab>at the sbt shell
-
Configuring proguard, some options are available
proguardOptions in Android += Seq("-dontobfuscate", "-dontoptimize")- will tell proguard not to obfuscute nor optimize code (any valid proguard option is usable here)
-
proguardConfig in Android ...can be used to replace the entire proguard config included with android-sdk-plugin -
On-device unit testing, use
android:testand see Android Testing Fundamentals -
Unit testing with robolectric, see my build.scala for this configuration:
-
This example is somewhat old and may include settings that are no longer necessary, this project hasn't been touched in nearly a year.
-
To get rid of robolectric's warnings about not finding certain classes to shadow, change the project target to include google APIs
-
jberkel has written a Suite trait to be able to use robolectric with scalatest rather than junit, see https://gist.github.com/2662806
-
Device Management
- The commands
devicesanddeviceare implemented. The former lists all connected devices. The latter command is for selecting a target device if there is more than one device. If there is more than one device, and no target is selected, all commands will execute against the first device in the list. android:install,android:runandandroid:testare tasks that can be used to install, run and test the built apk on-device, respectively.- Type
helpfor a list of all available commands.
- The commands
- Version checking of plugin and update notifications. This is not possible with ivy. Options: relocate plugin to sonatype and/or host an off-site versions config descriptor.
- Better handling of release vs. debug builds and creating other build flavors as supported by the Android Gradle plugin.
- Changes to
AndroidManifest.xmlmay require the plugin to be reloaded. The manifest data is stored internally as read-only data and does not reload automatically when it is changed. The current workaround is to typereloadmanually anytimeAndroidManifest.xmlis updated if necessary. Thisreloadis necessary to keepandroid:runworking properly if activities are changed, and packaging operating correctly when package names, or sdk references change. - sbt
0.12and0.13currently have a bug where jars specified in javac's -bootclasspath option forces a full rebuild of all classes everytime. sbt0.12.3and later has a hack that should workaround this problem. The plugin sets the system propertyxsbt.skip.cp.lookuptotrueto bypass this issue; this disables certain incremental compilation checks, but should not be an issue for the majority of use-cases. autolibsdo not properly processapklibandaarresources. If anything in anautolibuses resources from such a library, the answer is to create a standard multi-project build configuration rather than utilizeautolibs.autolibscan be disabled by manually configuringlocalProjects in Android