How can I configure a Gradle Android project so that a release APK built by the IDE is saved to a path of my choosing (eg the project root) rather than buried deep in the build folder?
I've added this to the defaultConfig section of the app build file to sensibly name the APK and it works well, but how can I specify where it goes, or move it post build completion?
archivesBaseName = "AppName-v$versionName" // AppName-v1.2.3-release.apk
UPDATE:
I created a task in the app-level Gradle build file that successfully copies the release APK, if I run the Gradle task manually:
task copyReleaseApk(type: Copy) {
from 'build/outputs/apk'
into '..' // project root, one-level above "app"
include '**/*release.apk'
}
But I have not yet found a way to make the task run automatically after the last build task. I tried this:
assembleRelease.finalizedBy(copySupportFiles)
But that results in "Could not get unknown property 'assembleRelease' for object of type com.android.build.gradle.AppExtension."
I also tried this:
assembleRelease.finalizedBy(copySupportFiles)
It appears not to do anything.
This worked (in the android tag of the app build.gradle file). The afterEvaluate seems to be required in order to refer to tasks like packageRelease that don't initially exist.
task copyReleaseApk(type: Copy) {
from 'build/outputs/apk'
into '..' // folder above the app folder
include '**/*release.apk'
}
afterEvaluate {
packageRelease.finalizedBy(copyReleaseApk)
}
It can be defined in the project's root build.gradle:
allprojects {
buildDir = "/path/to/build/${rootProject.name}/${project.name}"
}
Related
I updated to use Android Studio 2.2 and Gradle 2.2.0. And now I have a problem building.
I followed this post https://medium.com/google-cloud/automatic-per-variant-google-services-json-configurations-with-gradle-d3d3e40abc0e#.g1p7c1tx2 to configure two "google-services.json" files to be used for dev vs prod builds and use the following method in my app/build.gradle file to toggle between the copying the two "google-services.json" files.
afterEvaluate {
processDebugGoogleServices.dependsOn switchToDebug
processReleaseGoogleServices.dependsOn switchToRelease
}
task switchToDebug(type: Copy) {
description = 'Switches to DEBUG google-services.json'
from "src/gcm-dev"
include "google-services.json"
into "."
}
task switchToRelease(type: Copy) {
description = 'Switches to RELEASE google-services.json'
from "src/gcm-prod"
include "google-services.json"
into "."
}
Gradle complies fine but when I click on the "Run app" (triangle "play" icon) or "Debug app" (triangle "play" icon with a bug behind) buttons in Android Studio, I get the following:
* What went wrong:
A problem occurred configuring project ':app'.
> Could not get unknown property 'processReleaseGoogleServices' for object of type com.android.build.gradle.AppExtension.
Please help, much appreciated.
I had the same issue and problem was in enabled instant run.Try to disable it and run again.
You should update Google Play Services gradle plugin as well, follow the documentation to set it up: https://developers.google.com/android/guides/google-services-plugin
The great thing is that you no longer need to write gradle tasks which create appropriate google-services.json files in your root directory. Build type specific google-services.json are now supported by the plugin:
"As of version 2.2.0 the plugin supports build type and product flavor
specific JSON files. All of the following directory structures are
valid"
An alternative way to this is to refer to the task in the following way:
tasks.whenTaskAdded { task ->
if (task.name == 'assembleDebug') {
task.dependsOn 'switchToDebug'
} else if (task.name == 'assembleRelease') {
task.dependsOn 'switchToRelease'
}
}
UPDATE
The problem you mentioned in comment is related to your google-services.json file. You need to place google-services.json into app/ dir. And for each build type there should be accordant director in app/src folder.
If file already exists check if correct package name inside it
"client_info": {
"mobilesdk_app_id": "1:6596814400689:android:65d6f25f5006145",
"android_client_info": {
"package_name": "com.my.app.package.name"
}
As described by #Singed, add a directory pr build type/flavor under src-directory and the corresponding google-services.jsonand Google Play gradle plugin will take care of the rest, e.g.:
src/
debug/google-services.json
release/google-services.json
During build the correct file will be processed, ending up in build/generated/res/google-services/debug|release/values/values.xml
I am including feature of gcm in my app, For that i need to maintain two google-services.json one for debug and one for release build. How to do that ?? can i configure gcm without using google-services.json ??
First, place the respective google_services.json for each buildType in the following locations:
app/src/debug/google_services.json
app/src/test/google_services.json
app/google_services.json
Note: Root app/google_services.json This file should be there according to the build variants copy the json code in the root json file
Now, let’s whip up some gradle tasks in your: app’s build.gradle to automate moving the appropriate google_services.json to app/google_services.json
copy this in the app/Gradle file
task switchToDebug(type: Copy) {
description = 'Switches to DEBUG google-services.json'
from "src/debug"
include "google-services.json"
into "."
}
task switchToRelease(type: Copy) {
description = 'Switches to RELEASE google-services.json'
from "src/release"
include "google-services.json"
into "."
}
Great — but having to manually run these tasks before you build your app is cumbersome. We would want the appropriate copy task above run sometime before: assembleDebug or :assembleRelease is run. Let’s see what happens when :assembleRelease is run: copy this one in the /gradlew file
Zaks-MBP:my_awesome_application zak$ ./gradlew assembleRelease
Parallel execution is an incubating feature.
.... (other tasks)
:app:processReleaseGoogleServices
....
:app:assembleRelease
Notice the :app:processReleaseGoogleServices task. This task is responsible for processing the root google_services.json file. We want the correct google_services.json to be processed, so we must run our copy task immediately beforehand.
Add this to your build.gradle. Note the afterEvaluate enclosing.
copy this in the app/Gradle file
afterEvaluate {
processDebugGoogleServices.dependsOn switchToDebug
processReleaseGoogleServices.dependsOn switchToRelease
}
Now, anytime :app:processReleaseGoogleServices is called, our newly defined :app:switchToRelease will be called beforehand. Same logic for the debug buildType. You can run :app:assembleRelease and the release version google_services.json will be automatically copied to your app module’s root folder.
Credit goes to the : Zak Taccardi
https://medium.com/google-cloud/automatic-per-variant-google-services-json-configurations-with-gradle-d3d3e40abc0e
The current plugin (com.google.gms:google-services:2.1.X) supports flavors but not types.
So if you create a productflavor you can put the json file in src/$flavorname
Example:
app/src/
flavor1/google-services.json
flavor2/google-services.json
Currently it doesn't work with types (debug, release...) but you can use somenthing like this:
app/src/release/google-services.json
app/google-services.json
In this case the plugin looks in the locations and stops when it finds a google-services.json file.
If you are using a flavor it becomes:
app/src/foo/release/google-services.json
app/src/foo/google-services.json
You can find updated info here.
I'm currently using the following versions: com.google.gms:google-services:4.3.3, com.google.firebase:firebase-messaging:20.2.0
Place your google-services.json file in your $projectName/app/src/$buildType directory. For example, place one json file in src/release and another in src/debug. You will likely need to create the release & debug folders.
Note: It's a common mistake to add these files in the app folder, be sure you add this in the src folder as described above.
The google-services plugin always looks for the google-services.json
file in two directories: First, on the
$projectName/app/src/$buildType/google-services.json. If it does not
find it here, it goes one level above, to the
$projectName/app/google-services.json. So, when you are building the
debug version of your app, it will search for the google-services.json
on the $projectName/app/src/debug/ directory.
At the link below, see David Ojeda's response.
I'm trying to set up a Gradle build to build and include an NDK static library into an Android project, but can't get the inclusion to work. I'm running Gradle 2.8 on a Linux system directly from the command line (AndroidStudio, Android SDK, and Android NDK are installed, but I'm not using them directly in the sample below). I've boiled down my issue to the following purely Gradle-based sample, and was hoping someone more versed in Gradle could show me the way.
Let's say I have the following directory structure:
gradle_test
mySubLibs
common.gradle
mySubA
build.gradle
settings.gradle
myProjA
common.gradle
Projects
Android
build.gradle
settings.gradle
My library sub projects are under the mySubLibs directory. I'll have gradle_test be the root project directory to get around the fact that Gradle sucks with dealing with arbitrary paths (another gripe for another time).
First, I set up my library to build with "assembleRelease" and "clean" tasks. In reality it will call to command-line compilers to work, but for testing Gradle this simplification will do.
gradle_test/mySubLibs/common.gradle
buildscript {
}
task NDKBuildReleaseLib(type: Exec) {
println "Running NDKBuildReleaseLib for " + rootProject.name
commandLine 'touch', 'obj/local/myOutput.a'
}
task NDKBuildCleanLib(type: Exec) {
println "Running NDKBuildCleanLib for " + rootProject.name
commandLine 'rm', '../libs/myOutput.a', 'obj/local/myOutput.a'
}
task copyLibs(type:Copy) {
from 'obj/local'
into '../libs'
include '*.a'
outputs.upToDateWhen {false}
}
NDKBuildReleaseLib.finalizedBy copyLib
gradle_test/mySubLibs/mySubA/build.gradle
apply from: '../common.gradle'
configurations.create('default')
allprojects {
task assembleRelease(dependsOn: NDKBuildReleaseLib) << {}
task clean(dependsOn: NDKBuildCleanLib) << {}
}
gradle_test/mySubLibs/mySubA/settings.gradle
rootProject.name = "mySubA"
include ':'
This works fine. I can call "gradle assembleRelease" from the mySubA directory, and it builds my library file (the build being simulated by running "touch" to create a file). Now let's create a similar setup for the main project.
gradle_test/myProjA/common.gradle
buildscript {
}
task NDKBuildRelease(type: Exec) {
println "Running NDKBuildRelease for " + rootProject.name
commandLine 'touch', 'obj/local/myProjOutput.a'
}
task NDKBuildClean(type: Exec) {
println "Running NDKBuildClean for " + rootProject.name
commandLine 'rm', 'obj/local/myProjOutput.a'
}
gradle_test/myProjA/Projects/Android/build.gradle
apply from: '../../common.gradle'
configurations.create('default')
dependencies {
// default project(':mySubLibs:mySubA')
}
allprojects {
task assembleRelease(dependsOn: NDKBuildRelease) << {
println "Assemble Release for " + project.name
}
task clean(dependsOn: NDKBuildClean) << {
println "Clean for " + project.name
}
}
gradle_test/myProjA/Projects/Android/settings.gradle
rootProject.projectDir = new File(settingsDir, '../../..')
rootProject.name = "myTestBase"
include ':'
include 'mySubLibs:mySubA'
include 'myProjA:Projects:Android'
This mostly works, except that it is not causing the sub project to build. So my questions are:
How do I get the sub-project to build? If I uncomment the line above in the "dependencies" section, I get an undefined token error. Almost all samples dealing with dependencies use "compile" instead of "default" there, but since this example doesn't have a compile configuration created by the java plugin inclusion, I can't do that (nor did it work when I tried that). I know the sub project is being evaluated from "gradle --info", but it doesn't run.
How would I specify an arbitrary task to build the sub-project? In the above examples, I've set both up to build off a task named "assembleRelease". How could I call "assembleRelease" to build the project, but have a task called "buildMySubLib" called to build the library project?
The end goal is to have multiple library projects called to each build their own static library and copy it to a known common location, then for the main project to include all the static lib files from that common location in its own compile and link stage. It seems silly to have to set up a task for each library in the main project that uses an Exec task to recursively call the command line version of "gradle" for each library project.
Thanks for any insight. So far Gradle is proving to be more hindrance than helpful in trying to set up what should actually be a pretty common build scenario.
I would like to create a properties file named "dev.properties" using gradle. Here is my build.gradle code:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.8.+'
}
}
apply plugin: 'android'
repositories {
mavenCentral()
}
android {
compileSdkVersion 16
buildToolsVersion "19.0.0"
defaultConfig {
minSdkVersion 16
targetSdkVersion 16
}
def prop = new Properties()
def propFile = new File("dev.properties");
propFile.createNewFile();
prop.store(propFile.newWriter(), null);
buildTypes {
release {
runProguard false
proguardFile getDefaultProguardFile('proguard-android.txt')
}
}
}
The file is created when I right click on the build.gradle and choose run. However it's not created when I make the entire project. How come?
I'm using android studio 0.4.6 with gradle 1.10.
It's creating the file, just not where you expect. Your script is creating the file inside the current working directory, and in Android Studio, that will be in Android Studio's distribution. There's a bug filed to make Android Studio consistent with the command line (https://code.google.com/p/android/issues/detail?id=65552) and put the working directory at the project root (well, that's assuming your working directory is set there when you issue Gradle commands), but the fix is actually difficult, and the real answer is you should probably never implicitly rely on the working directory, so that you can make your builds as bulletproof as possible.
If you do something like this:
def propFile = new File("${project.rootDir}/dev.properties")
it will put the file in your project's root directory. There's also project.projectDir, which will be your module directory; see http://www.gradle.org/docs/current/dsl/org.gradle.api.Project.html for more details on what's available to you.
As a side note, you should keep in mind this will run every time the build file is evaluated (because the android block is executed every time the build script is run), which could be more often than you want. It's more than just build time; it's project import time as well, and any time Android Studio decides to evaluate the build file, which happens when you open the project and also when you click the Sync Project with Gradle Files button.
Additionally, you should consider at what phase of the build process you want it to happen: is it script evaluation time, or do you want it to run after Gradle has done its analysis and is ready to actually start building things? You can read http://www.gradle.org/docs/current/userguide/build_lifecycle.html to find out more about that.
Sorry, I know it's a lot of information to drop on you when you're just trying to get something going, but those concepts will help you out pretty soon down the road.
I have downloaded some library sources and would like to export it as a Jar file using
Android Studio. Is there a way to export to jar file using Android studio ?
edit:
The library I want to export as jar is an Android library.
It's called "StandOut" and can be downloaded from GitHub.
https://github.com/pingpongboss/StandOut
It is not possible to export an Android library as a jar file. It is possible, however, to export it as aar file. Aar files being the new binary format for Android libraries. There's info about them in Google I/O, the New Build System video.
First, build the library in Android Studio or from command line issuing gradle build from your library's root directory.
This will result in <yourlibroot>/libs/build/yourlib.aar file.
This aar file is a binary representation of your library and can be added to your project instead of the library as a dependency project.
To add aar file as a dependency you have to publish it to the maven central or to your local maven repository, and then refer the aar file in your project's gradle.build file.
However, this step is a bit convoluted. I've found a good explanation how to do so here:
http://www.flexlabs.org/2013/06/using-local-aar-android-library-packages-in-gradle-builds
I was able to build a library source code to compiled .jar file, using approach from this solution:
https://stackoverflow.com/a/19037807/1002054
Here is the breakdown of what I did:
1. Checkout library repository
In may case it was a Volley library
2. Import library in Android Studio.
I used Android Studio 0.3.7. I've encountered some issues during that step, namely I had to copy gradle folder from new android project before I was able to import Volley library source code, this may vary depending on source code you use.
3. Modify your build.gradle file
// If your module is a library project, this is needed
//to properly recognize 'android-library' plugin
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.6.3'
}
}
apply plugin: 'android-library'
android {
compileSdkVersion 17
buildToolsVersion = 17
sourceSets {
main {
// Here is the path to your source code
java {
srcDir 'src'
}
}
}
}
// This is the actual solution, as in https://stackoverflow.com/a/19037807/1002054
task clearJar(type: Delete) {
delete 'build/libs/myCompiledLibrary.jar'
}
task makeJar(type: Copy) {
from('build/bundles/release/')
into('build/libs/')
include('classes.jar')
rename ('classes.jar', 'myCompiledLibrary.jar')
}
makeJar.dependsOn(clearJar, build)
4. Run gradlew makeJar command from your project root.
I my case I had to copy gradlew.bat and gradle files from new android project into my library project root.
You should find your compiled library file myCompiledLibrary.jar in build\libs directory.
I hope someone finds this useful.
Edit:
Caveat
Althought this works, you will encounter duplicate library exception while compiling a project with multiple modules, where more than one module (including application module) depends on the same jar file (eg. modules have own library directory, that is referenced in build.gradle of given module).
In case where you need to use single library in more then one module, I would recommend using this approach:
Android gradle build and the support library
Since Android Studio V1.0 the jar file is available inside the following project link:
debug ver: "your_app"\build\intermediates\bundles\debug\classes.jar
release ver: "your_app"\build\intermediates\bundles\release\classes.jar
The JAR file is created on the build procedure,
In Android Studio GUI it's from Build->Make Project and from CMD line it's "gradlew build".
Include the following into build.gradle:
android.libraryVariants.all { variant ->
task("generate${variant.name}Javadoc", type: Javadoc) {
description "Generates Javadoc for $variant.name."
source = variant.javaCompile.source
ext.androidJar = "${android.plugin.sdkDirectory}/platforms/${android.compileSdkVersion}/android.jar"
classpath = files(variant.javaCompile.classpath.files) + files(ext.androidJar)
}
task("javadoc${variant.name}", type: Jar) {
classifier = "javadoc"
description "Bundles Javadoc into a JAR file for $variant.name."
from tasks["generate${variant.name}Javadoc"]
}
task("jar${variant.name}", type: Jar) {
description "Bundles compiled .class files into a JAR file for $variant.name."
dependsOn variant.javaCompile
from variant.javaCompile.destinationDir
exclude '**/R.class', '**/R$*.class', '**/R.html', '**/R.*.html'
}
}
You can then execute gradle with: ./gradlew clean javadocRelease jarRelease which will build you your Jar and also a javadoc jar into the build/libs/ folder.
EDIT: With android gradle tools 1.10.+ getting the android SDK dir is different than before. You have to change the following (thanks Vishal!):
android.sdkDirectory
instead of
android.plugin.sdkDirectory
I was able to export a jar file in Android Studio using this tutorial:
https://www.youtube.com/watch?v=1i4I-Nph-Cw
"How To Export Jar From Android Studio "
I updated my answer to include all the steps for exporting a JAR in Android Studio:
1) Create Android application project, go to app->build.gradle
2) Change the following in this file:
modify apply plugin: 'com.android.application' to apply plugin: 'com.android.library'
remove the following: applicationId, versionCode and versionName
Add the following code:
// Task to delete old jar
task deleteOldJar(type: Delete){
delete 'release/AndroidPlugin2.jar'
}
// task to export contents as jar
task exportJar(type: Copy) {
from ('build/intermediates/bundles/release/')
into ('release/')
include ('classes.jar')
rename('classes.jar', 'AndroidPlugin2.jar')
}
exportJar.dependsOn(deleteOldJar, build)
3) Don't forget to click sync now in this file (top right or use sync button).
4) Click on Gradle tab (usually middle right) and scroll down to exportjar
5) Once you see the build successful message in the run window, using normal file explorer go to exported jar using the path: C:\Users\name\AndroidStudioProjects\ProjectName\app\release
you should see in this directory your jar file.
Good Luck :)
Here's yet another, slightly different answer with a few enhancements.
This code takes the .jar right out of the .aar. Personally, that gives me a bit more confidence that the bits being shipped via .jar are the same as the ones shipped via .aar. This also means that if you're using ProGuard, the output jar will be obfuscated as desired.
I also added a super "makeJar" task, that makes jars for all build variants.
task(makeJar) << {
// Empty. We'll add dependencies for this task below
}
// Generate jar creation tasks for all build variants
android.libraryVariants.all { variant ->
String taskName = "makeJar${variant.name.capitalize()}"
// Create a jar by extracting it from the assembled .aar
// This ensures that products distributed via .aar and .jar exactly the same bits
task (taskName, type: Copy) {
String archiveName = "${project.name}-${variant.name}"
String outputDir = "${buildDir.getPath()}/outputs"
dependsOn "assemble${variant.name.capitalize()}"
from(zipTree("${outputDir}/aar/${archiveName}.aar"))
into("${outputDir}/jar/")
include('classes.jar')
rename ('classes.jar', "${archiveName}-${variant.mergedFlavor.versionName}.jar")
}
makeJar.dependsOn tasks[taskName]
}
For the curious reader, I struggled to determine the correct variables and parameters that the com.android.library plugin uses to name .aar files. I finally found them in the Android Open Source Project here.
We can export a jar file for Android library project without resource files by Android studio. It is also requirement what I met recently.
1. Config your build.gradle file
// Task to delete old jar
task clearJar(type: Delete){
delete 'release/lunademo.jar'
}
// task to export contents as jar
task makeJar(type: Copy) {
from ('build/intermediates/bundles/release/')
into ('build/libs/')
include ('classes.jar')
rename('classes.jar', 'lunademo.jar')
}
makeJar.dependsOn(clearJar, build)
2. Run gradlew makeJar under your project root
You will see your libs under dir as build/libs/ if you are luckily.
============================================================
If you met issue as "Socket timeout exception" on command line as below,
You can follow this steps to open Gradle window in the right part and click "makeJar" on Android studio like this,
Then go to build/libs dir, you will see your jar file.
Hope that it is helpful for u.
Good Luck #.#
Luna