├── src
├── integTest
│ ├── resources
│ │ └── androidProjects
│ │ │ ├── hello
│ │ │ ├── default.properties
│ │ │ ├── simple.gradle
│ │ │ ├── test.keystore
│ │ │ ├── res
│ │ │ │ ├── drawable
│ │ │ │ │ └── icon.png
│ │ │ │ ├── values
│ │ │ │ │ └── strings.xml
│ │ │ │ └── layout
│ │ │ │ │ └── main.xml
│ │ │ ├── src
│ │ │ │ └── main
│ │ │ │ │ └── java
│ │ │ │ │ └── com
│ │ │ │ │ └── jvoegele
│ │ │ │ │ └── gradle
│ │ │ │ │ └── android
│ │ │ │ │ └── hello
│ │ │ │ │ └── HelloActivity.java
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── debug-release-otherwise.gradle
│ │ │ └── debug-release.gradle
│ │ │ ├── random
│ │ │ ├── default.properties
│ │ │ ├── res
│ │ │ │ ├── drawable
│ │ │ │ │ └── icon.png
│ │ │ │ ├── values
│ │ │ │ │ └── strings.xml
│ │ │ │ └── layout
│ │ │ │ │ └── main.xml
│ │ │ ├── src
│ │ │ │ └── main
│ │ │ │ │ └── scala
│ │ │ │ │ └── com
│ │ │ │ │ └── jvoegele
│ │ │ │ │ └── gradle
│ │ │ │ │ └── android
│ │ │ │ │ └── random
│ │ │ │ │ ├── Generator.scala
│ │ │ │ │ └── RandomActivity.scala
│ │ │ ├── build.gradle
│ │ │ └── AndroidManifest.xml
│ │ │ └── multi_resource
│ │ │ ├── default.properties
│ │ │ ├── multi_resource.gradle
│ │ │ ├── res
│ │ │ ├── drawable
│ │ │ │ └── icon.png
│ │ │ ├── values
│ │ │ │ └── strings.xml
│ │ │ └── layout
│ │ │ │ └── main.xml
│ │ │ ├── res2
│ │ │ ├── drawable
│ │ │ │ └── icon2.png
│ │ │ └── values
│ │ │ │ └── strings.xml
│ │ │ ├── src
│ │ │ └── main
│ │ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── jvoegele
│ │ │ │ └── gradle
│ │ │ │ └── android
│ │ │ │ └── hello
│ │ │ │ └── HelloActivity.java
│ │ │ └── AndroidManifest.xml
│ └── groovy
│ │ └── com
│ │ └── jvoegele
│ │ └── gradle
│ │ └── android
│ │ ├── AbstractIntegrationTest.groovy
│ │ ├── MultiResourceProjectTest.groovy
│ │ ├── support
│ │ ├── ZipAlignVerifier.groovy
│ │ ├── SignVerifier.groovy
│ │ ├── MyBuildListener.groovy
│ │ ├── TestArchive.groovy
│ │ └── TestProject.groovy
│ │ ├── RandomProjectTest.groovy
│ │ └── HelloProjectTest.groovy
└── main
│ ├── resources
│ └── META-INF
│ │ └── gradle-plugins
│ │ └── android.properties
│ └── groovy
│ └── com
│ └── jvoegele
│ └── gradle
│ ├── plugins
│ └── android
│ │ ├── AndroidSetup.groovy
│ │ ├── AbstractAndroidSetup.groovy
│ │ ├── AndroidSetupFactory.groovy
│ │ ├── AndroidPluginConvention.groovy
│ │ ├── AndroidSetup_r13.groovy
│ │ ├── AndroidSetup_r14.groovy
│ │ ├── AndroidSetup_r17.groovy
│ │ ├── AndroidSetup_r18.groovy
│ │ ├── AndroidSetup_r21.groovy
│ │ └── AndroidPlugin.groovy
│ ├── tasks
│ └── android
│ │ ├── exceptions
│ │ ├── AdbErrorException.groovy
│ │ └── InstrumentationTestsFailedException.groovy
│ │ ├── AndroidAntTask.groovy
│ │ ├── AaptExecTask_r7.groovy
│ │ ├── EmulatorTask.groovy
│ │ ├── AaptExecTask_r8.groovy
│ │ ├── ApkBuilderTask_r6.groovy
│ │ ├── AaptExecTask_r14.groovy
│ │ ├── ApkBuilderTask_r14.groovy
│ │ ├── ApkBuilderTask_r8.groovy
│ │ ├── ApkBuilderTask_r7.groovy
│ │ ├── AdbExec.groovy
│ │ ├── AndroidSdkToolsFactory.groovy
│ │ ├── AaptExecTask_r18.groovy
│ │ ├── AaptExecTask_r21.groovy
│ │ ├── instrumentation
│ │ ├── TestRunnersConfig.groovy
│ │ └── InstrumentationTestsTask.groovy
│ │ ├── ProcessAndroidResources.groovy
│ │ ├── AndroidPackageTask.groovy
│ │ ├── ProGuard.groovy
│ │ └── AndroidSignAndAlignTask.groovy
│ └── enhancements
│ ├── GradlePluginEnhancement.groovy
│ ├── JavadocEnhancement.groovy
│ ├── ScalaEnhancement.groovy
│ └── EclipseEnhancement.groovy
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── license-notice
├── CHANGELOG
├── gradlew.bat
├── gradlew
├── LICENSE
└── README.md
/src/integTest/resources/androidProjects/hello/default.properties:
--------------------------------------------------------------------------------
1 | target=android-7
2 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/random/default.properties:
--------------------------------------------------------------------------------
1 | target=android-7
2 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/multi_resource/default.properties:
--------------------------------------------------------------------------------
1 | target=android-7
2 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/hello/simple.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'android'
2 |
3 | version = '1.0'
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jvoegele/gradle-android-plugin/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/src/main/resources/META-INF/gradle-plugins/android.properties:
--------------------------------------------------------------------------------
1 | implementation-class=com.jvoegele.gradle.plugins.android.AndroidPlugin
2 |
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | .project
3 | .classpath
4 | .gradle
5 | .settings
6 | bin
7 | .idea
8 | *.iml
9 | .DS_Store
10 | *.ipr
11 | *.iws
12 | out
13 | jarlist.cache
14 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/multi_resource/multi_resource.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'android'
2 |
3 | version = '1.0'
4 |
5 | resDirs = files("res") + files("res2")
6 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/hello/test.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jvoegele/gradle-android-plugin/HEAD/src/integTest/resources/androidProjects/hello/test.keystore
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/hello/res/drawable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jvoegele/gradle-android-plugin/HEAD/src/integTest/resources/androidProjects/hello/res/drawable/icon.png
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/random/res/drawable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jvoegele/gradle-android-plugin/HEAD/src/integTest/resources/androidProjects/random/res/drawable/icon.png
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/multi_resource/res/drawable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jvoegele/gradle-android-plugin/HEAD/src/integTest/resources/androidProjects/multi_resource/res/drawable/icon.png
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/multi_resource/res2/drawable/icon2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jvoegele/gradle-android-plugin/HEAD/src/integTest/resources/androidProjects/multi_resource/res2/drawable/icon2.png
--------------------------------------------------------------------------------
/license-notice:
--------------------------------------------------------------------------------
1 | The icon in integTest projects comes from http://www.wpzoom.com/wpzoom/500-free-icons-wpzoom-social-networking-icon-set/
2 | and is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/hello/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello Application
4 | Hello, World!
5 |
6 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/multi_resource/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello Application
4 | Hello, World!
5 |
6 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/multi_resource/res2/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello Application
4 | Hello, World!
5 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu May 10 11:52:21 PHT 2012
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=http\://services.gradle.org/distributions/gradle-1.0-rc-3-bin.zip
7 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/random/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Random number generator
4 | Random number:
5 | Generate
6 |
7 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/random/src/main/scala/com/jvoegele/gradle/android/random/Generator.scala:
--------------------------------------------------------------------------------
1 | package com.jvoegele.gradle.android.random
2 |
3 | import java.util.Random
4 |
5 | class Generator {
6 | val random = new Random
7 |
8 | def generate = random.nextInt(9999) + 1
9 | }
10 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/random/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'android'
2 | apply plugin: 'scala'
3 |
4 | repositories {
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | scalaTools 'org.scala-lang:scala-compiler:2.8.1', 'org.scala-lang:scala-library:2.8.1'
10 |
11 | compile 'org.scala-lang:scala-library:2.8.1'
12 | }
13 |
14 | version = '1.0'
15 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/hello/src/main/java/com/jvoegele/gradle/android/hello/HelloActivity.java:
--------------------------------------------------------------------------------
1 | package com.jvoegele.gradle.android.hello;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 |
6 | public class HelloActivity extends Activity {
7 | @Override
8 | public void onCreate(Bundle savedInstanceState) {
9 | super.onCreate(savedInstanceState);
10 | setContentView(R.layout.main);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/multi_resource/src/main/java/com/jvoegele/gradle/android/hello/HelloActivity.java:
--------------------------------------------------------------------------------
1 | package com.jvoegele.gradle.android.hello;
2 |
3 | import android.app.Activity;
4 | import android.os.Bundle;
5 |
6 | public class HelloActivity extends Activity {
7 | @Override
8 | public void onCreate(Bundle savedInstanceState) {
9 | super.onCreate(savedInstanceState);
10 | setContentView(R.layout.main);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/hello/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/multi_resource/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/hello/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/random/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/multi_resource/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/hello/debug-release-otherwise.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'android'
2 |
3 | repositories {
4 | mavenCentral() // for Proguard
5 | }
6 |
7 | version = '1.0'
8 |
9 | task release(dependsOn: build)
10 |
11 | def configureDebug() {
12 | jar.classifier = 'debug'
13 | }
14 |
15 | def configureRelease() {
16 | androidSignAndAlign {
17 | keyStore = file('test.keystore')
18 | keyStorePassword = 'testpass'
19 | keyAlias = 'testkey'
20 | keyAliasPassword = 'testpass'
21 | }
22 |
23 | proguard.enabled = true
24 | }
25 |
26 | gradle.taskGraph.whenReady { taskGraph ->
27 | if (taskGraph.hasTask(':release')) {
28 | configureRelease()
29 | } else {
30 | configureDebug()
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/hello/debug-release.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'android'
2 |
3 | repositories {
4 | mavenCentral() // for Proguard
5 | }
6 |
7 | version = '1.0'
8 |
9 | task configureDebug << {
10 | jar.classifier = 'debug'
11 | }
12 |
13 | task configureRelease << {
14 | androidSignAndAlign {
15 | keyStore = file('test.keystore')
16 | keyStorePassword = 'testpass'
17 | keyAlias = 'testkey'
18 | keyAliasPassword = 'testpass'
19 | }
20 |
21 | proguard.enabled = true
22 | }
23 |
24 | task configureReleaseDeprecated << {
25 | androidPackage {
26 | keyStore = file('test.keystore')
27 | keyStorePassword = 'testpass'
28 | keyAlias = 'testkey'
29 | keyAliasPassword = 'testpass'
30 | }
31 |
32 | proguard.enabled = true
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/plugins/android/AndroidSetup.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.plugins.android
18 |
19 | interface AndroidSetup {
20 | void setup()
21 | }
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/random/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
9 |
12 |
16 |
17 |
--------------------------------------------------------------------------------
/src/integTest/resources/androidProjects/random/src/main/scala/com/jvoegele/gradle/android/random/RandomActivity.scala:
--------------------------------------------------------------------------------
1 | package com.jvoegele.gradle.android.random
2 |
3 | import android.app.Activity
4 | import android.os.Bundle
5 | import android.widget.{TextView, Button}
6 | import android.view.View
7 |
8 | class RandomActivity extends Activity {
9 | val generator = new Generator
10 |
11 | override def onCreate(savedInstanceState: Bundle) = {
12 | super.onCreate(savedInstanceState)
13 | setContentView(R.layout.main)
14 |
15 | val number = findViewById(R.id.number).asInstanceOf[TextView]
16 |
17 | val button = findViewById(R.id.button).asInstanceOf[Button]
18 | button.setOnClickListener(new View.OnClickListener() {
19 | def onClick(view: View) = {
20 | number.setText("" + generator.generate)
21 | }
22 | })
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/plugins/android/AbstractAndroidSetup.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.plugins.android
18 |
19 | abstract class AbstractAndroidSetup implements AndroidSetup {
20 | protected project
21 |
22 | AbstractAndroidSetup(project) {
23 | this.project = project
24 | }
25 | }
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/exceptions/AdbErrorException.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android.exceptions
18 |
19 | import org.gradle.api.GradleException
20 |
21 | class AdbErrorException extends GradleException {
22 | def AdbErrorException(String message) {
23 | super(message)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/exceptions/InstrumentationTestsFailedException.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android.exceptions;
18 |
19 | class InstrumentationTestsFailedException extends AdbErrorException {
20 | def InstrumentationTestsFailedException() {
21 | super("There were test failures")
22 | }
23 | }
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/enhancements/GradlePluginEnhancement.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.enhancements
18 |
19 | import org.gradle.api.Project;
20 |
21 | class GradlePluginEnhancement {
22 | protected Project project
23 | protected ant
24 |
25 | GradlePluginEnhancement(Project project) {
26 | this.project = project
27 | this.ant = project.ant
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/enhancements/JavadocEnhancement.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.enhancements
18 |
19 | import org.gradle.api.Project
20 |
21 | class JavadocEnhancement extends GradlePluginEnhancement {
22 | JavadocEnhancement(Project project) {
23 | super(project)
24 | }
25 |
26 | void apply() {
27 | project.tasks.javadoc.classpath += project.files(ant['android.jar'])
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/AndroidAntTask.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android
18 |
19 | import com.jvoegele.gradle.plugins.android.AndroidPluginConvention
20 |
21 | abstract class AndroidAntTask {
22 | protected final project
23 | protected final ant
24 | protected final AndroidPluginConvention androidConvention
25 |
26 | protected AndroidAntTask(project) {
27 | this.project = project
28 | this.ant = project.ant
29 | this.androidConvention = project.convention.plugins.android
30 | }
31 |
32 | public abstract void execute(Map args);
33 | }
34 |
--------------------------------------------------------------------------------
/src/integTest/groovy/com/jvoegele/gradle/android/AbstractIntegrationTest.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.android
18 |
19 | import org.gradle.testfixtures.ProjectBuilder
20 |
21 | import com.jvoegele.gradle.android.support.TestProject
22 |
23 | class AbstractIntegrationTest {
24 | def androidProjectsDir = new File(System.getProperty('integTest.androidProjects'))
25 |
26 | def project(path) {
27 | def projectDir = new File(androidProjectsDir, path)
28 | def project = ProjectBuilder.builder().withProjectDir(projectDir).build()
29 | return new TestProject(project: project)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/enhancements/ScalaEnhancement.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.enhancements
18 |
19 | import org.gradle.api.Project
20 | import org.gradle.api.plugins.scala.ScalaPlugin
21 |
22 | class ScalaEnhancement extends GradlePluginEnhancement {
23 | ScalaEnhancement(Project project) {
24 | super(project)
25 | }
26 |
27 | def apply() {
28 | project.gradle.projectsEvaluated {
29 | if (project.plugins.hasPlugin(ScalaPlugin)) {
30 | project.logger.info("Compiling Scala project, enabling Proguard (dexing fails without it)")
31 | project.proguard.enabled = true
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/integTest/groovy/com/jvoegele/gradle/android/MultiResourceProjectTest.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.android
18 |
19 | import org.junit.Test
20 |
21 | class MultiResourceProjectTest extends AbstractIntegrationTest {
22 | @Test
23 | void build() {
24 | def p = project('multi_resource')
25 |
26 | p.runTasks 'clean', 'build', buildScript: 'multi_resource.gradle'
27 |
28 | p.fileExists 'build/distributions/multi_resource-1.0.apk'
29 |
30 | p.archive('build/distributions/multi_resource-1.0.apk').assertContains 'res/drawable/icon.png'
31 | p.archive('build/distributions/multi_resource-1.0.apk').assertContains 'res/drawable/icon2.png'
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/integTest/groovy/com/jvoegele/gradle/android/support/ZipAlignVerifier.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.android.support
18 |
19 | import org.gradle.internal.os.OperatingSystem
20 | import static org.junit.Assert.assertTrue
21 |
22 | class ZipAlignVerifier {
23 | def project
24 |
25 | def verifyAligned(archive) {
26 | def androidTools = new File(System.getenv("ANDROID_HOME"), "tools")
27 | def zipalign = new File(androidTools, "zipalign${OperatingSystem.current().isWindows() ? '.exe' : ''}")
28 |
29 | def result = project.exec {
30 | executable zipalign.canonicalPath
31 | args '-c', 4, archive
32 | ignoreExitValue = true
33 | }
34 |
35 | assertTrue("The archive ${archive} must be zipaligned", result.exitValue == 0)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/integTest/groovy/com/jvoegele/gradle/android/RandomProjectTest.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.android
18 |
19 | import org.junit.Test
20 |
21 | class RandomProjectTest extends AbstractIntegrationTest {
22 | @Test
23 | void build() {
24 | def p = project('random')
25 |
26 | p.runTasks 'clean', 'build'
27 |
28 | p.fileExists 'build/libs/random-1.0.jar'
29 | p.fileExists 'build/libs/random-1.0-unsigned.apk'
30 | p.fileExists 'build/libs/random-1.0-unaligned.apk'
31 | p.fileExists 'build/distributions/random-1.0.apk'
32 |
33 | p.archive('build/libs/random-1.0.jar').assertContains 'com/jvoegele/gradle/android/random/RandomActivity.class'
34 |
35 | p.archive('build/distributions/random-1.0.apk').assertSigned('CN=Android Debug, O=Android, C=US')
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/AaptExecTask_r7.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android
18 |
19 | class AaptExecTask_r7 extends AndroidAntTask {
20 | AaptExecTask_r7(project) {
21 | super(project);
22 | }
23 |
24 | /* (non-Javadoc)
25 | * @see com.jvoegele.gradle.tasks.android.AndroidAntTask#execute(java.util.Map)
26 | */
27 | @Override
28 | void execute(Map args) {
29 | ant.aaptexec(
30 | executable: ant.aapt,
31 | command: args.get('command', 'package'),
32 | manifest: androidConvention.androidManifest.path,
33 | resources: androidConvention.resDir.path,
34 | assets: androidConvention.assetsDir,
35 | androidjar: ant['android.jar'],
36 | outfolder: project.libsDir,
37 | basename: project.name)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/EmulatorTask.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android
18 |
19 | import org.gradle.api.DefaultTask
20 | import org.gradle.api.tasks.Input;
21 | import org.gradle.api.tasks.TaskAction
22 |
23 | class EmulatorTask extends DefaultTask {
24 |
25 | @Input public String avdName
26 |
27 | def EmulatorTask() {}
28 |
29 | @TaskAction
30 | def start() {
31 | if (avdName == null) {
32 | throw new IllegalStateException("""
33 | Please specify avdName in your build.gradle:
34 |
35 | androidEmulatorStart {
36 | avdName = "YourAvdName"
37 | }
38 | """)
39 | }
40 |
41 | project.logger.info("Starting emulator...")
42 | def command = project.ant['sdk.dir'] + "/tools/emulator -avd " +avdName
43 | def proc = command.execute()
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/AaptExecTask_r8.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android
18 |
19 | class AaptExecTask_r8 extends AndroidAntTask {
20 | AaptExecTask_r8(project) {
21 | super(project);
22 | }
23 |
24 | /* (non-Javadoc)
25 | * @see com.jvoegele.gradle.tasks.android.AndroidAntTask#execute(java.util.Map)
26 | */
27 | @Override
28 | void execute(Map args) {
29 | ant.aaptexec(
30 | executable: ant.aapt,
31 | command: args.get('command', 'package'),
32 | debug: project.jar.classifier && project.jar.classifier == 'debug',
33 | manifest: androidConvention.androidManifest.path,
34 | assets: androidConvention.assetsDir,
35 | androidjar: ant['android.jar'],
36 | apkfolder: project.libsDir,
37 | resourcefilename: androidConvention.resourceFileName) {
38 | androidConvention.resDirs.each { File file ->
39 | res(path: file.path)
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/ApkBuilderTask_r6.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android
18 |
19 | class ApkBuilderTask_r6 extends AndroidAntTask {
20 | ApkBuilderTask_r6(project) {
21 | super(project)
22 | }
23 |
24 | /**
25 | * Execute the apkbuilder task.
26 | * @param args Map of keyword arguments. Supported keywords are sign and
27 | * verbose, both of which should be boolean values if provided.
28 | */
29 | void execute(Map args) {
30 | assert ant != null
31 | ant.apkbuilder(outfolder: project.buildDir,
32 | basename: project.name,
33 | signed: args.get('sign', false),
34 | 'verbose': args.get('verbose', false)) {
35 | ant.file(path: androidConvention.intermediateDexFile.absolutePath)
36 | //sourcefolder(path: project.sourceSets.main.java)
37 | nativefolder(path: androidConvention.nativeLibsDir)
38 | //jarfolder(path: androidConvention.nativeLibsDir)
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/AaptExecTask_r14.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android
18 |
19 | class AaptExecTask_r14 extends AndroidAntTask {
20 | AaptExecTask_r14(project) {
21 | super(project);
22 | }
23 |
24 | /* (non-Javadoc)
25 | * @see com.jvoegele.gradle.tasks.android.AndroidAntTask#execute(java.util.Map)
26 | */
27 | @Override
28 | void execute(Map args) {
29 | ant.aaptexec(
30 | executable: ant.aapt,
31 | command: args.get('command', 'package'),
32 | debug: project.jar.classifier && project.jar.classifier == 'debug',
33 | manifest: androidConvention.androidManifest.path,
34 | assets: androidConvention.assetsDir,
35 | androidjar: ant['android.jar'],
36 | apkfolder: project.libsDir,
37 | resourcefilename: androidConvention.resourceFileName,
38 | projectLibrariesResName: 'project.libraries.res',
39 | projectLibrariesPackageName: 'project.libraries.package') {
40 | androidConvention.resDirs.each { File file ->
41 | res(path: file.path)
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/integTest/groovy/com/jvoegele/gradle/android/support/SignVerifier.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.android.support
18 |
19 | import java.security.cert.X509Certificate
20 | import java.util.jar.JarFile
21 | import javax.security.auth.x500.X500Principal
22 |
23 | import static org.junit.Assert.fail
24 |
25 | class SignVerifier {
26 | def archive
27 |
28 | def verify(distinguishedNameStr) {
29 | def jar = new JarFile(archive)
30 | def distinguishedName = new X500Principal(distinguishedNameStr)
31 |
32 | def entry = jar.getEntry('classes.dex')
33 |
34 | // the entry must be fully read before getting certificates
35 | readStreamAndDiscard(jar.getInputStream(entry))
36 |
37 | def ok = false
38 | entry.certificates.each { cert ->
39 | if (!(cert instanceof X509Certificate)) {
40 | return
41 | }
42 |
43 | if (cert.subjectX500Principal == distinguishedName) {
44 | ok = true
45 | }
46 | }
47 |
48 | if (!ok) {
49 | fail "The jar ${archive} is not signed by ${distinguishedNameStr}"
50 | }
51 | }
52 |
53 | def readStreamAndDiscard(stream) {
54 | while (stream.read() != -1) {
55 | // empty on purpose
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/integTest/groovy/com/jvoegele/gradle/android/support/MyBuildListener.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.android.support
18 |
19 | import org.gradle.BuildAdapter
20 | import org.gradle.api.invocation.Gradle
21 | import org.gradle.initialization.ClassLoaderRegistry
22 |
23 | class MyBuildListener extends BuildAdapter {
24 | @Override
25 | void projectsLoaded(Gradle gradle) {
26 | // This is a hack: Gradle Android Plugin integration tests have Gradle Android Plugin itself on their classpath,
27 | // but Gradle lets the buildscript only access a few selected packages, not the full classpath. That is a good
28 | // idea per se, as we should make the test buildscripts self-contained anyway, but I wasn't able to make it work
29 | // (a 'buildscript { ... }' section in test buildscript isn't enough, something is missing...). So I simply
30 | // adjust the Gradle filtering classloader to allow access to Gradle Android Plugin. It is not a public API,
31 | // but it's highly unlikely that it will change before we switch to using Gradle Tooling API. See TestProject too.
32 | gradle.rootProject.services.get(ClassLoaderRegistry.class).rootClassLoader.allowPackage("com.jvoegele.gradle.plugins.android")
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/ApkBuilderTask_r14.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android
18 |
19 | class ApkBuilderTask_r14 extends AndroidAntTask {
20 | ApkBuilderTask_r14(project) {
21 | super(project)
22 | }
23 |
24 | /**
25 | * Execute the apkbuilder task.
26 | * @param args Map of keyword arguments. Supported keywords are sign and
27 | * verbose, both of which should be boolean values if provided.
28 | */
29 | void execute(Map args) {
30 | assert ant != null
31 | ant.apkbuilder(
32 | outfolder: project.libsDir,
33 | resourcefile: ant['resource.package.file.name'],
34 | apkfilepath: androidConvention.unsignedArchivePath,
35 | debugsigning: args.get('sign', false),
36 | hascode: ant['manifest.hasCode'],
37 | verbose: args.get('verbose', false)) {
38 | dex(path: androidConvention.intermediateDexFile)
39 | // Takes resource files from the source folder - classes are processed by the dx command
40 | sourcefolder(path: project.sourceSets.main.output.classesDir)
41 |
42 | if (project.sourceSets.main.output.resourcesDir.exists()) {
43 | sourcefolder(path: project.sourceSets.main.output.resourcesDir)
44 | }
45 |
46 | nativefolder(path: androidConvention.nativeLibsDir)
47 | project.configurations.runtime.each { jarfile(path: it) }
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/plugins/android/AndroidSetupFactory.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.plugins.android
18 |
19 | class AndroidSetupFactory {
20 | private static final String SOURCE_PROPERTIES_FILE = 'source.properties'
21 | private static final String PKG_REVISION_PROPERTY = 'Pkg.Revision'
22 |
23 | private project
24 | private int toolsRevision = -1
25 |
26 | AndroidSetupFactory(project) {
27 | this.project = project
28 | }
29 |
30 | int getAndroidSdkToolsRevision() {
31 | if (toolsRevision < 0) {
32 | def ant = project.ant
33 | def toolsDir = new File(ant['sdk.dir'], 'tools')
34 | assert toolsDir.exists()
35 | def sourcePropertiesFile = new File(toolsDir, SOURCE_PROPERTIES_FILE)
36 | assert sourcePropertiesFile.exists()
37 | ant.property(file: sourcePropertiesFile)
38 | String toolsFullRevision = ant[PKG_REVISION_PROPERTY];
39 | if (toolsFullRevision.contains('.')) {
40 | toolsRevision = Integer.parseInt(toolsFullRevision.substring(0, toolsFullRevision.indexOf('.')))
41 | } else {
42 | toolsRevision = Integer.parseInt(toolsFullRevision)
43 | }
44 | }
45 |
46 | return toolsRevision
47 | }
48 |
49 | AndroidSetup getAndroidSetup() {
50 | if (this.androidSdkToolsRevision < 14) {
51 | return new AndroidSetup_r13(project)
52 | } else if (this.androidSdkToolsRevision < 17) {
53 | return new AndroidSetup_r14(project)
54 | } else if (this.androidSdkToolsRevision < 18) {
55 | return new AndroidSetup_r17(project)
56 | } else if (this.androidSdkToolsRevision < 21) {
57 | return new AndroidSetup_r18(project)
58 | } else {
59 | return new AndroidSetup_r21(project)
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/CHANGELOG:
--------------------------------------------------------------------------------
1 | 2012-10-10 Gradle Android Plugin Developers
2 |
3 | * Fix problem with androidSignAndAlign task.
4 |
5 | 2012-09-18 Gradle Android Plugin Developers
6 |
7 | * Keep methods that could be used as click event handlers.
8 |
9 | * Added support for generating BuildConfig.java
10 |
11 | * Made sure resources from JAR dependencies get included in APK, as well
12 |
13 | * Fixed retrieval of password when typed during the build
14 |
15 | * Fixed issue of signing the app with a JDK 7.0
16 |
17 | * Fixed NumberFormatException a second place
18 |
19 | * Fixed NumberFormatException with sdk 20.0.x
20 |
21 | * Update to support r20
22 |
23 | * Add integration test assertions for debuggable flag
24 |
25 | * Use signing.signPom instead of signPom as the latter is deprecated already
26 |
27 | * Ignore jarlist.cache file
28 |
29 | * Corrected `downloadJavadocs` entry to simply `downloadJavadoc` (without the "s")
30 |
31 | * Changed package of OperatingSystem class from internal.nativeplatform to internal.os
32 |
33 | * Added shawnlauzon's fix for #52, which he reported in #53.
34 |
35 | * Avoiding Gradle internal class ConventionTask and replaced it with DefaultTask. Using fileTree method that provides parameters as Map to fix deprecation message.
36 |
37 | * Also enable debug packages for SDK versions 8 through 13
38 |
39 | * When making a debug package, make it debuggable
40 |
41 |
42 | 2011-12-15 Gradle Android Plugin Developers
43 |
44 | * Version 1.1.0 released!
45 |
46 | * Gradle Android Plugin is now in Maven Central!
47 |
48 | * Group ID is now org.gradle.api.plugins
49 |
50 | * Artifact ID is now gradle-android-plugins
51 |
52 | * Support for Android 4.0 "Ice Cream Sandwich", R14+
53 |
54 | * Support for Discobot
55 |
56 | 2011-08-11 Gradle Android Plugin Developers
57 |
58 | * Version 1.0.0 released!
59 |
60 | * Generate Eclipse projects with "gradle eclipse"
61 |
62 | * Use proguard.cfg for ProGuard configuration
63 |
64 | * ProGuard is automatically enabled in Scala projects
65 |
66 | * Ability to start Android emulator with Gradle
67 |
68 | * Instrumentation tests support; also contains support for Zutubi test runner
69 |
70 | * The plugin got some tests of itself; they can also serve as complete Gradle + Android project examples
71 |
--------------------------------------------------------------------------------
/src/integTest/groovy/com/jvoegele/gradle/android/support/TestArchive.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.android.support
18 |
19 | import java.util.jar.JarFile
20 | import org.gradle.internal.os.OperatingSystem
21 |
22 | import static org.junit.Assert.assertFalse
23 | import static org.junit.Assert.assertNotNull
24 | import static org.junit.Assert.assertTrue
25 |
26 | class TestArchive {
27 | def project
28 | def archive
29 |
30 | def assertContains(path) {
31 | def jar = new JarFile(archive)
32 | assertNotNull "The archive ${archive} must contain ${path}", jar.getEntry(path)
33 | }
34 |
35 | def assertAligned() {
36 | new ZipAlignVerifier(project: project).verifyAligned archive
37 | }
38 |
39 | def assertSigned(distinguishedName) {
40 | new SignVerifier(archive: archive).verify(distinguishedName)
41 | }
42 |
43 | def assertDebuggable() {
44 | assertTrue "The archive ${archive} must have the android:debuggable attribute set", isDebuggable()
45 | }
46 |
47 | def assertNotDebuggable() {
48 | assertFalse "The archive ${archive} must not have the android:debuggable attribute set", isDebuggable()
49 | }
50 |
51 | def isDebuggable() {
52 | def androidTools = new File(System.getenv("ANDROID_HOME"), "platform-tools")
53 | def aapt = new File(androidTools, "aapt${OperatingSystem.current().isWindows() ? '.exe' : ''}")
54 | def debuggable = false
55 |
56 | new ByteArrayOutputStream().withStream { os ->
57 | project.exec {
58 | executable aapt.canonicalPath
59 | args 'list', '-v', '-a', archive
60 | standardOutput = os
61 | ignoreExitValue = true
62 | }
63 | os.toString().eachLine {
64 | if (it.contains("A: android:debuggable") && it.contains("=(type 0x12)0xffffffff")) {
65 | debuggable = true
66 | }
67 | }
68 | }
69 |
70 | debuggable
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/ApkBuilderTask_r8.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android
18 |
19 | class ApkBuilderTask_r8 extends AndroidAntTask {
20 | ApkBuilderTask_r8(project) {
21 | super(project)
22 | }
23 |
24 | /**
25 | * Execute the apkbuilder task.
26 | * @param args Map of keyword arguments. Supported keywords are sign and
27 | * verbose, both of which should be boolean values if provided.
28 | */
29 | void execute(Map args) {
30 | assert ant != null
31 | ant.apkbuilder(outfolder: project.libsDir,
32 | resourcefile: ant['resource.package.file.name'],
33 | apkfilepath: androidConvention.unsignedArchivePath,
34 | debugsigning: args.get('sign', false),
35 | abifilter: '',
36 | hascode: ant['manifest.hasCode'],
37 | verbose: args.get('verbose', false)) {
38 | dex(path: androidConvention.intermediateDexFile)
39 | // Takes resource files from the source folder - classes are processed by the dx command
40 | sourcefolder(path: project.sourceSets.main.output.classesDir)
41 | if (project.sourceSets.main.output.resourcesDir.exists()) {
42 | sourcefolder(path: project.sourceSets.main.output.resourcesDir)
43 | }
44 | nativefolder(path: androidConvention.nativeLibsDir)
45 | project.configurations.runtime.each { jarfile(path: it) }
46 | }
47 | /*
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | */
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/ApkBuilderTask_r7.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android
18 |
19 | import java.util.Map;
20 |
21 | class ApkBuilderTask_r7 extends AndroidAntTask {
22 | ApkBuilderTask_r7(project) {
23 | super(project)
24 | }
25 |
26 | /**
27 | * Execute the apkbuilder task.
28 | * @param args Map of keyword arguments. Supported keywords are sign and
29 | * verbose, both of which should be boolean values if provided.
30 | */
31 | void execute(Map args) {
32 | assert ant != null
33 | ant.apkbuilder(outfolder: project.libsDir,
34 | resourcefile: ant['resource.package.file.name'],
35 | apkfilepath: androidConvention.unsignedArchivePath,
36 | signed: args.get('sign', false),
37 | abifilter: '',
38 | hascode: ant['manifest.hasCode'],
39 | verbose: args.get('verbose', false)) {
40 | dex(path: androidConvention.intermediateDexFile)
41 | // Takes resource files from the source folder - classes are processed by the dx command
42 | sourcefolder(path: project.sourceSets.main.output.classesDir)
43 | if (project.sourceSets.main.output.resourcesDir.exists()) {
44 | sourcefolder(path: project.sourceSets.main.output.resourcesDir)
45 | }
46 | nativefolder(path: androidConvention.nativeLibsDir)
47 | project.configurations.runtime.each { jarfile(path: it) }
48 | }
49 | /*
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | */
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/AdbExec.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android
18 |
19 | import org.apache.tools.ant.util.TeeOutputStream
20 | import org.gradle.api.DefaultTask
21 | import org.gradle.api.tasks.Exec
22 | import org.gradle.api.tasks.TaskAction
23 |
24 | import com.jvoegele.gradle.tasks.android.exceptions.AdbErrorException;
25 |
26 | class AdbExec extends DefaultTask {
27 | def exec = new Exec()
28 | def stdout = new ByteArrayOutputStream() // output is small, we can safely read it into memory
29 | def stderr = new ByteArrayOutputStream() // adb prints error messages both on stdout and stderr
30 |
31 | def AdbExec() {
32 | exec.executable project.ant['adb']
33 |
34 | if (project.ant['adb.device.arg']) {
35 | exec.args project.ant['adb.device.arg'].split(" ")
36 | }
37 |
38 | // both stdout and stderr should be logged AND inspected for error messages at the same time
39 | exec.standardOutput = new TeeOutputStream(System.out, stdout)
40 | exec.errorOutput = new TeeOutputStream(System.err, stderr)
41 |
42 | exec.ignoreExitValue = true
43 | }
44 |
45 | @TaskAction
46 | def exec() {
47 | project.logger.info("running '${exec.commandLine.join(" ")}'")
48 |
49 | exec.exec()
50 |
51 | checkForErrors stdout
52 | checkForErrors stderr
53 |
54 | // exit value was ignored to inspect stdout/stderr first and possibly throw exception with reasonable message
55 | // now it's sure that the exception wasn't thrown, but the exit value really should be checked
56 | exec.execResult.assertNormalExitValue()
57 | }
58 |
59 | def checkForErrors(stream) {
60 | def reader = new InputStreamReader(new ByteArrayInputStream(stream.toByteArray()))
61 |
62 | reader.eachLine {
63 | if (it.toLowerCase().contains("failure") || it.toLowerCase().contains("error")) {
64 | throw new AdbErrorException(it.trim())
65 | }
66 | }
67 | }
68 |
69 | def AdbExec args(Object... args) {
70 | exec.args(args)
71 | return this
72 | }
73 |
74 | def AdbExec args(Iterable> args) {
75 | exec.args(args)
76 | return this
77 | }
78 |
79 | def AdbExec setArgs(Iterable> args) {
80 | exec.setArgs(args)
81 | return this
82 | }
83 |
84 | def List getArgs() {
85 | return exec.getArgs()
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/integTest/groovy/com/jvoegele/gradle/android/support/TestProject.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.android.support
18 |
19 | import org.gradle.GradleLauncher
20 | import org.gradle.api.Project
21 | import org.gradle.internal.os.OperatingSystem
22 | import static org.junit.Assert.assertFalse
23 | import static org.junit.Assert.assertTrue
24 |
25 | // Note that on Windows, we don't test proper cleaning of the project. If we did,
26 | // we would get spurious test failures because somehow, there are file handles
27 | // leaking and the 'clean' task isn't able to finish successfully. See runTasks
28 | // and fileDoesntExist methods.
29 |
30 | // We still use GradleLauncher here to launch a Gradle build, even if it is
31 | // deprecated, because Tooling API doesn't yet support specifying custom
32 | // buildscript file (which we heavily use). It will be supported in the future.
33 |
34 | class TestProject {
35 | /*@Delegate*/ Project project
36 |
37 | def runTasks(String... tasks) {
38 | runTasks([:], tasks as List)
39 | }
40 |
41 | def runTasks(Map args, String... tasks) {
42 | runTasks(args, tasks as List)
43 | }
44 |
45 | def runTasks(Map args, List tasks) {
46 | if (OperatingSystem.current().isWindows()) {
47 | tasks.remove 'clean'
48 | }
49 |
50 | def startParameter = project.gradle.startParameter.newBuild()
51 | startParameter.projectDir = project.projectDir
52 | if (args.buildScript) {
53 | startParameter.buildFile = new File(project.projectDir, args.buildScript)
54 | }
55 | startParameter.taskNames = tasks
56 | def launcher = GradleLauncher.newInstance(startParameter)
57 | launcher.addListener(new MyBuildListener())
58 | def result = launcher.run()
59 | result.rethrowFailure()
60 | }
61 |
62 | def archive(path) {
63 | new TestArchive(project: project, archive: file(path))
64 | }
65 |
66 | // delegation (sadly, Groovy's @Delegate doesn't seem to work)
67 |
68 | def file(path) {
69 | project.file(path)
70 | }
71 |
72 | def exec(closure) {
73 | project.exec(closure)
74 | }
75 |
76 | // asserts
77 |
78 | def fileExists(path) {
79 | assertTrue("File ${path} must exist", file(path).isFile())
80 | }
81 |
82 | def fileDoesntExist(path) {
83 | if (OperatingSystem.current().isWindows()) {
84 | return
85 | }
86 |
87 | assertFalse("File ${path} must not exist", file(path).exists())
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/plugins/android/AndroidPluginConvention.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.plugins.android;
18 |
19 | import org.gradle.api.Project
20 | import org.gradle.api.file.FileCollection
21 |
22 | class AndroidPluginConvention {
23 | Project project
24 | File resDir
25 | File genDir
26 | File assetsDir
27 | File nativeLibsDir
28 | File androidManifest
29 | File intermediateDexFile
30 | String resourceFileName
31 | String instrumentationTestsRunner
32 | FileCollection resDirs
33 |
34 | AndroidPluginConvention(Project project) {
35 | this.project = project
36 |
37 | // Input paths
38 | resDir = new File(project.projectDir, 'res')
39 | assetsDir = new File(project.projectDir, 'assets')
40 | nativeLibsDir = new File(project.projectDir, 'libs')
41 | androidManifest = new File(project.projectDir, 'AndroidManifest.xml')
42 | resDirs = project.files(resDir)
43 |
44 | // Output paths
45 | // FIXME (Matthias): I find this misleading, this is NOT conventional; the gen/ folder
46 | // typically sits at the project root, not inside the build/ folder, that's a Gradle thing.
47 | // In fact, for the EclipseEnhancement to work, I had to hack around this by removing this
48 | // entry and replacing it with $projectDir/gen, which is the actual convention.
49 | genDir = new File(project.buildDir, 'gen')
50 |
51 | intermediateDexFile = new File(project.libsDir, "classes.dex")
52 |
53 | resourceFileName = project.name + ".ap_"
54 |
55 | // instrumentation conventions
56 | instrumentationTestsRunner = "android.test.InstrumentationTestRunner"
57 | }
58 |
59 | /**
60 | * This value has to be calculated dynamically
61 | * @return
62 | */
63 | String getApkBaseName() {
64 | def nameParts = [project.jar.baseName]
65 |
66 | if (project.jar.appendix) {
67 | nameParts << project.jar.appendix
68 | }
69 |
70 | if (project.version) {
71 | nameParts << project.version
72 | }
73 |
74 | if (project.jar.classifier) {
75 | nameParts << project.jar.classifier
76 | }
77 |
78 | return nameParts.join('-')
79 | }
80 |
81 | /**
82 | * This value has to be calculated dynamically
83 | * @return
84 | */
85 | File getApkArchivePath() {
86 | return new File (project.distsDir, "${apkBaseName}.apk")
87 | }
88 |
89 | File getUnsignedArchivePath() {
90 | return new File(project.libsDir, "${apkBaseName}-unsigned.apk")
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/plugins/android/AndroidSetup_r13.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.plugins.android
18 |
19 | class AndroidSetup_r13 extends AbstractAndroidSetup {
20 | AndroidSetup_r13(project) {
21 | super(project)
22 | }
23 |
24 | void setup() {
25 | def ant = project.ant
26 | def androidConvention = project.convention.plugins.android
27 |
28 | def sdkDir = ant['sdk.dir']
29 | def toolsDir = new File(sdkDir, "tools")
30 | def platformToolsDir = new File(sdkDir, "platform-tools")
31 |
32 | ant.condition('property': "exe", value: ".exe", 'else': "") { os(family: "windows") }
33 |
34 | if (platformToolsDir.exists()) { // since SDK r8, adb is moved from tools to platform-tools
35 | ant.property(name: "adb", location: new File(platformToolsDir, "adb${ant['exe']}"))
36 | } else {
37 | ant.property(name: "adb", location: new File(toolsDir, "adb${ant['exe']}"))
38 | }
39 |
40 | ant.property(name: "zipalign", location: new File(toolsDir, "zipalign${ant['exe']}"))
41 | ant.property(name: 'adb.device.arg', value: '')
42 |
43 | def outDir = project.buildDir.absolutePath
44 | ant.property(name: "resource.package.file.name", value: "${project.name}.ap_")
45 |
46 | ant.taskdef(name: 'setup', classname: 'com.android.ant.SetupTask', classpathref: 'android.antlibs')
47 |
48 | // The following properties are put in place by the setup task:
49 | // android.jar, android.aidl, aapt, aidl, and dx
50 | ant.setup('import': false)
51 |
52 | ant.taskdef(name: "xpath", classname: "com.android.ant.XPathTask", classpathref: "android.antlibs")
53 | ant.taskdef(name: "aaptexec", classname: "com.android.ant.AaptExecLoopTask", classpathref: "android.antlibs")
54 | ant.taskdef(name: "apkbuilder", classname: "com.android.ant.ApkBuilderTask", classpathref: "android.antlibs")
55 |
56 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/@package", output: "manifest.package")
57 |
58 | // TODO: there can be several instrumentations defined
59 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/instrumentation/@android:targetPackage", output: "tested.manifest.package")
60 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/application/@android:hasCode", output: "manifest.hasCode", 'default': "true")
61 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/instrumentation/@android:name", output: "android.instrumentation")
62 |
63 | if (ant['android.instrumentation']) {
64 | androidConvention.instrumentationTestsRunner = ant['android.instrumentation']
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/AndroidSdkToolsFactory.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android
18 |
19 | /**
20 | * Factory for creating Ant tasks and other tools packaged with the Android SDK.
21 | */
22 | class AndroidSdkToolsFactory {
23 | private static final String SOURCE_PROPERTIES_FILE = 'source.properties'
24 | private static final String PKG_REVISION_PROPERTY = 'Pkg.Revision'
25 |
26 | private final project
27 | private final logger
28 | private int toolsRevision = -1
29 |
30 | /**
31 | * Create a new AndroidSdkToolsFactory for the given project.
32 | */
33 | AndroidSdkToolsFactory(project) {
34 | this.project = project
35 | this.logger = project.logger
36 | }
37 |
38 | /**
39 | * Returns the value of the Pkg.Revision property from the source.properties
40 | * file in the Android SDK's tools directory.
41 | */
42 | int getAndroidSdkToolsRevision() {
43 | if (toolsRevision < 0) {
44 | def ant = project.ant
45 | def toolsDir = new File(ant['sdk.dir'], 'tools')
46 | assert toolsDir.exists()
47 | def sourcePropertiesFile = new File(toolsDir, SOURCE_PROPERTIES_FILE)
48 | assert sourcePropertiesFile.exists()
49 | ant.property(file: sourcePropertiesFile)
50 | String toolsFullRevision = ant[PKG_REVISION_PROPERTY];
51 | if (toolsFullRevision.contains('.')) {
52 | toolsRevision = Integer.parseInt(toolsFullRevision.substring(0, toolsFullRevision.indexOf('.')))
53 | } else {
54 | toolsRevision = Integer.parseInt(toolsFullRevision)
55 | }
56 | }
57 |
58 | return toolsRevision
59 | }
60 |
61 | /**
62 | * Returns an AndroidAntTask that invokes the appropriate
63 | * apkbuilder for the active Android SDK tools revision.
64 | */
65 | AndroidAntTask getApkbuilder() {
66 | if (this.androidSdkToolsRevision < 7) {
67 | return new ApkBuilderTask_r6(project)
68 | } else if (this.androidSdkToolsRevision < 8) {
69 | return new ApkBuilderTask_r7(project)
70 | } else if (this.androidSdkToolsRevision < 14) {
71 | return new ApkBuilderTask_r8(project)
72 | } else {
73 | return new ApkBuilderTask_r14(project)
74 | }
75 | }
76 |
77 | AndroidAntTask getAaptexec() {
78 | if (this.androidSdkToolsRevision < 8) {
79 | return new AaptExecTask_r7(project)
80 | } else if (this.androidSdkToolsRevision < 14) {
81 | return new AaptExecTask_r8(project)
82 | } else if (this.androidSdkToolsRevision < 18) {
83 | return new AaptExecTask_r14(project)
84 | } else if (this.androidSdkToolsRevision < 21) {
85 | return new AaptExecTask_r18(project)
86 | } else {
87 | return new AaptExecTask_r21(project)
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/AaptExecTask_r18.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android
18 |
19 | class AaptExecTask_r18 extends AndroidAntTask {
20 | AaptExecTask_r18(project) {
21 | super(project);
22 | }
23 |
24 | /* (non-Javadoc)
25 | * @see com.jvoegele.gradle.tasks.android.AndroidAntTask#execute(java.util.Map)
26 | */
27 | @Override
28 | void execute(Map args) {
29 | //
46 | //
47 | //
48 | //
49 | //
50 | //
51 |
52 | println "androidConvention.resDirs = ${androidConvention.resDirs}";
53 |
54 | ant.aapt(
55 | executable: ant.aapt,
56 | command: args.get('command', 'package'),
57 | // versioncode: ant['version.code'],
58 | // versionname: ant['version.name'],
59 | debug: project.jar.classifier && project.jar.classifier == 'debug',
60 | manifest: androidConvention.androidManifest.path,
61 | assets: androidConvention.assetsDir,
62 | androidjar: ant['android.jar'],
63 | apkfolder: project.libsDir,
64 | nocrunch: true,
65 | resourcefilename: androidConvention.resourceFileName,
66 | // resourcefilter="${aapt.resource.filter}"
67 | // previousBuildType="${build.last.target}"
68 | // buildType="${build.target}"
69 | // ignoreAssets="${aapt.ignore.assets}">
70 | libraryResFolderPathRefid: "project.library.res.folder.path",
71 | libraryPackagesRefid: "project.library.packages",
72 | ) {
73 | androidConvention.resDirs.each { File file ->
74 | res(path: file.path)
75 | }
76 | }
77 | }
78 | }
79 |
80 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/AaptExecTask_r21.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android
18 |
19 | class AaptExecTask_r21 extends AndroidAntTask {
20 | AaptExecTask_r21(project) {
21 | super(project);
22 | }
23 |
24 | /* (non-Javadoc)
25 | * @see com.jvoegele.gradle.tasks.android.AndroidAntTask#execute(java.util.Map)
26 | */
27 | @Override
28 | void execute(Map args) {
29 | //
47 | //
48 | //
49 | //
50 | //
51 | //
52 |
53 | println "androidConvention.resDirs = ${androidConvention.resDirs}";
54 |
55 | ant.aapt(
56 | executable: ant.aapt,
57 | command: args.get('command', 'package'),
58 | // versioncode: ant['version.code'],
59 | // versionname: ant['version.name'],
60 | debug: project.jar.classifier && project.jar.classifier == 'debug',
61 | manifest: androidConvention.androidManifest.path,
62 | assets: androidConvention.assetsDir,
63 | androidjar: ant['android.jar'],
64 | apkfolder: project.libsDir,
65 | nocrunch: true,
66 | resourcefilename: androidConvention.resourceFileName,
67 | // resourcefilter="${aapt.resource.filter}"
68 | // previousBuildType="${build.last.target}"
69 | // buildType="${build.target}"
70 | // ignoreAssets="${aapt.ignore.assets}">
71 | libraryResFolderPathRefid: "project.library.res.folder.path",
72 | libraryPackagesRefid: "project.library.packages",
73 | libraryRFileRefid: "project.library.bin.r.file.path",
74 | ) {
75 | androidConvention.resDirs.each { File file ->
76 | res(path: file.path)
77 | }
78 | }
79 | }
80 | }
81 |
82 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/instrumentation/TestRunnersConfig.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android.instrumentation
18 |
19 | /**
20 | * Configures the test runners used to run the instrumentation tests. This class basically
21 | * represents the 'runners' configure closure used in the build script.
22 | *
23 | * @author Matthias Kaeppler
24 | * @author Ladislav Thon
25 | */
26 | class TestRunnersConfig {
27 | static final String PACKAGE = "testpackage"
28 | static final String ANNOTATION = "annotation"
29 | static final String RUNNER = "with"
30 | static final String NAME = "name"
31 | static final String OPTIONS = "options"
32 |
33 | def project
34 | def testPackage
35 |
36 | def defaultConfig
37 | def packageRunners = [:]
38 | def annotationRunners = [:]
39 |
40 | def TestRunnersConfig(project, testPackage) {
41 | this.project = project
42 | this.testPackage = testPackage
43 | }
44 |
45 | def run(args = [:]) {
46 | createRunConfig(args)
47 | }
48 |
49 | def createRunConfig(args = [:]) {
50 | def testRunner = args[(RUNNER)] ?: project.convention.plugins.android.instrumentationTestsRunner
51 | def packageName = args[(PACKAGE)]
52 | def annotation = args[(ANNOTATION)]
53 | def name = args[(NAME)] ?: "instrumentation-tests-$numRunners"
54 | def options = args[(OPTIONS)] ?: []
55 |
56 | if (!options instanceof List) {
57 | options = [options]
58 | }
59 |
60 | // always wait for tests to finish
61 | options << "-w"
62 | // enable support for Zutubi's JUnit report test runner
63 | options += ["-e", "reportFilePath", "${name}.xml"]
64 |
65 | testRunner = expandFullyQualifiedName(testRunner)
66 |
67 | if (packageName) {
68 | packageRunners[expandFullyQualifiedName(packageName)] = buildRunner(testRunner, name, options)
69 | } else if (annotation) {
70 | annotationRunners[annotation] = buildRunner(testRunner, name, options)
71 | } else {
72 | defaultConfig = buildRunner(testRunner, name, options)
73 | }
74 | }
75 |
76 | boolean performDefaultRun() {
77 | packageRunners.isEmpty() && annotationRunners.isEmpty()
78 | }
79 |
80 | int getNumRunners() {
81 | packageRunners.size() + annotationRunners.size()
82 | }
83 |
84 | def buildRunner(def testRunner, def name, def options) {
85 | def wrapper = new Expando()
86 | wrapper.runner = testRunner
87 | wrapper.name = name
88 | wrapper.options = options
89 | wrapper
90 | }
91 |
92 | /**
93 | * Expand name according to Android convention: if it starts with a period ("."), it will be prepended
94 | * with package name from the manifest, otherwise it will be returned as is.
95 | */
96 | String expandFullyQualifiedName(String name) {
97 | if (name.startsWith(".")) {
98 | return "${testPackage}${name}"
99 | }
100 | return name;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/plugins/android/AndroidSetup_r14.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.plugins.android
18 |
19 | class AndroidSetup_r14 extends AbstractAndroidSetup {
20 | AndroidSetup_r14(project) {
21 | super(project)
22 | }
23 |
24 | void setup() {
25 | def ant = project.ant
26 | def androidConvention = project.convention.plugins.android
27 |
28 | def sdkDir = ant['sdk.dir']
29 | def toolsDir = new File(sdkDir, "tools")
30 | def platformToolsDir = new File(sdkDir, "platform-tools")
31 |
32 | ant.condition('property': "exe", value: ".exe", 'else': "") { os(family: "windows") }
33 | ant.condition('property': "bat", value: ".bat", 'else': "") { os(family: "windows") }
34 |
35 | if (platformToolsDir.exists()) { // since SDK r8, adb is moved from tools to platform-tools
36 | ant.property(name: "adb", location: new File(platformToolsDir, "adb${ant['exe']}"))
37 | } else {
38 | ant.property(name: "adb", location: new File(toolsDir, "adb${ant['exe']}"))
39 | }
40 |
41 | ant.property(name: "zipalign", location: new File(toolsDir, "zipalign${ant['exe']}"))
42 | ant.property(name: 'adb.device.arg', value: '')
43 |
44 | def outDir = project.buildDir.absolutePath
45 | ant.property(name: "resource.package.file.name", value: "${project.name}.ap_")
46 |
47 | ant.taskdef(name: 'setup', classname: 'com.android.ant.NewSetupTask', classpathref: 'android.antlibs')
48 |
49 | // The following properties are put in place by the setup task:
50 | // android.jar, android.aidl, aapt, aidl, and dx
51 | ant.setup(
52 | projectTypeOut: "android.project.type",
53 | androidJarFileOut: "android.jar",
54 | androidAidlFileOut: "android.aidl",
55 | renderScriptExeOut: "renderscript",
56 | renderScriptIncludeDirOut: "android.rs",
57 | bootclasspathrefOut: "android.target.classpath",
58 | projectLibrariesRootOut: "project.libraries",
59 | projectLibrariesJarsOut: "project.libraries.jars",
60 | projectLibrariesResOut: "project.libraries.res",
61 | projectLibrariesPackageOut: "project.libraries.package",
62 | projectLibrariesLibsOut: "project.libraries.libs",
63 | targetApiOut: "target.api")
64 |
65 | ant.taskdef(name: "xpath", classname: "com.android.ant.XPathTask", classpathref: "android.antlibs")
66 | ant.taskdef(name: "aaptexec", classname: "com.android.ant.AaptExecTask", classpathref: "android.antlibs")
67 | ant.taskdef(name: "apkbuilder", classname: "com.android.ant.ApkBuilderTask", classpathref: "android.antlibs")
68 |
69 | ant.property(name: "aapt", location: new File(platformToolsDir, "aapt${ant['exe']}"))
70 | ant.property(name: "aidl", location: new File(platformToolsDir, "aidl${ant['exe']}"))
71 | ant.property(name: "dx", location: new File(platformToolsDir, "dx${ant['bat']}"))
72 |
73 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/@package", output: "manifest.package")
74 | // TODO: there can be several instrumentations defined
75 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/instrumentation/@android:targetPackage", output: "tested.manifest.package")
76 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/application/@android:hasCode", output: "manifest.hasCode", 'default': "true")
77 |
78 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/instrumentation/@android:name", output: "android.instrumentation")
79 |
80 | if (ant['android.instrumentation']) {
81 | androidConvention.instrumentationTestsRunner = ant['android.instrumentation']
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/enhancements/EclipseEnhancement.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.enhancements
18 |
19 | import org.gradle.api.Project
20 | import org.gradle.plugins.ide.eclipse.model.BuildCommand
21 | import org.gradle.plugins.ide.eclipse.model.SourceFolder;
22 |
23 | class EclipseEnhancement extends GradlePluginEnhancement {
24 | def androidConvention = project.convention.plugins.android
25 |
26 | EclipseEnhancement(Project project) {
27 | super(project)
28 | }
29 |
30 | void apply() {
31 | project.gradle.taskGraph.whenReady { taskGraph ->
32 | if (!project.plugins.hasPlugin('eclipse'))
33 | return;
34 |
35 | def androidLibraryProjects = detectAndroidLibraryProjects()
36 |
37 | project.eclipse.project {
38 | natures 'com.android.ide.eclipse.adt.AndroidNature'
39 |
40 | def builders = new LinkedList(buildCommands)
41 | builders.addFirst(new BuildCommand('com.android.ide.eclipse.adt.PreCompilerBuilder'))
42 | builders.addFirst(new BuildCommand('com.android.ide.eclipse.adt.ResourceManagerBuilder'))
43 | builders.addLast(new BuildCommand('com.android.ide.eclipse.adt.ApkBuilder'))
44 | buildCommands = new ArrayList(builders)
45 |
46 | // add an Eclipse link to every library project's src folder (= type 2)
47 | androidLibraryProjects.each {
48 | linkedResource name: it.sourceName, type: "2", location: it.sourcePath
49 | }
50 | }
51 |
52 | project.eclipse.classpath {
53 | containers.removeAll { it == 'org.eclipse.jdt.launching.JRE_CONTAINER' }
54 | containers 'com.android.ide.eclipse.adt.ANDROID_FRAMEWORK'
55 |
56 | file {
57 | whenMerged { classpath ->
58 | // the ADT use a top-level gen/ folder, whereas the plugin uses build/gen, so swap them
59 | classpath.entries.removeAll { it instanceof SourceFolder && it.dir?.path == androidConvention.genDir.path }
60 | classpath.entries.add(new SourceFolder('gen', null))
61 |
62 | androidLibraryProjects.each {
63 | classpath.entries.add(new SourceFolder(it.sourceName, null))
64 |
65 | // now remove the artifact JAR from the classpath, or it would clash
66 | // with the classes compiled from src
67 | classpath.entries.removeAll { entry -> entry.path == it.artifact.file.absolutePath }
68 | }
69 | }
70 | }
71 | }
72 | }
73 | }
74 |
75 | // TODO: this currently only works if a Gradle dependency's artifact name equals the folder
76 | // name of the library project referenced in default.properties
77 | private def detectAndroidLibraryProjects() {
78 | // Android's SetupTask sets this for use based on library references in default.properties
79 | def librarySrcPaths = project.ant.references['project.libraries.src']?.list()
80 |
81 | if (!librarySrcPaths?.any()) {
82 | return []
83 | }
84 |
85 | def libraryProjects = []
86 |
87 | // try to match the project's resolved dependencies against the libraries in default.properties
88 | project.configurations.compile.resolvedConfiguration.resolvedArtifacts.each { artifact ->
89 | def matchingSrcPath = librarySrcPaths.find { it ==~ /.*\/${artifact.name}\/src$/ }
90 |
91 | if (matchingSrcPath) {
92 | def libraryProject = new Expando()
93 | libraryProject.artifact = artifact
94 | libraryProject.sourcePath = matchingSrcPath
95 | libraryProject.sourceName = "${artifact.name}_src"
96 | libraryProjects << libraryProject
97 | }
98 | }
99 |
100 | return libraryProjects
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/plugins/android/AndroidSetup_r17.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.plugins.android
18 |
19 | class AndroidSetup_r17 extends AbstractAndroidSetup {
20 | AndroidSetup_r17(project) {
21 | super(project)
22 | }
23 |
24 | void setup() {
25 | def ant = project.ant
26 | def androidConvention = project.convention.plugins.android
27 |
28 | def sdkDir = ant['sdk.dir']
29 | def toolsDir = new File(sdkDir, "tools")
30 | def platformToolsDir = new File(sdkDir, "platform-tools")
31 |
32 | ant.condition('property': "exe", value: ".exe", 'else': "") { os(family: "windows") }
33 | ant.condition('property': "bat", value: ".bat", 'else': "") { os(family: "windows") }
34 |
35 | if (platformToolsDir.exists()) { // since SDK r8, adb is moved from tools to platform-tools
36 | ant.property(name: "adb", location: new File(platformToolsDir, "adb${ant['exe']}"))
37 | } else {
38 | ant.property(name: "adb", location: new File(toolsDir, "adb${ant['exe']}"))
39 | }
40 |
41 | ant.property(name: "zipalign", location: new File(toolsDir, "zipalign${ant['exe']}"))
42 | ant.property(name: 'adb.device.arg', value: '')
43 |
44 | def outDir = project.buildDir.absolutePath
45 | ant.property(name: "resource.package.file.name", value: "${project.name}.ap_")
46 |
47 | // Required since SDK r17
48 | ant.property(name: "out.absolute.dir", value:'.')
49 |
50 | ant.taskdef(name: 'setup', classname: 'com.android.ant.NewSetupTask', classpathref: 'android.antlibs')
51 |
52 | // The following properties are put in place by the setup task:
53 | // android.jar, android.aidl, aapt, aidl, and dx
54 | ant.setup(
55 | projectTypeOut: "android.project.type",
56 | androidJarFileOut: "android.jar",
57 | androidAidlFileOut: "android.aidl",
58 | renderScriptExeOut: "renderscript",
59 | renderScriptIncludeDirOut: "android.rs",
60 | bootclasspathrefOut: "android.target.classpath",
61 | projectLibrariesRootOut: "project.libraries",
62 | projectLibrariesJarsOut: "project.libraries.jars",
63 | projectLibrariesResOut: "project.libraries.res",
64 | projectLibrariesPackageOut: "project.libraries.package",
65 | projectLibrariesLibsOut: "project.libraries.libs",
66 | targetApiOut: "target.api")
67 |
68 | ant.taskdef(name: "xpath", classname: "com.android.ant.XPathTask", classpathref: "android.antlibs")
69 | ant.taskdef(name: "aaptexec", classname: "com.android.ant.AaptExecTask", classpathref: "android.antlibs")
70 | ant.taskdef(name: "apkbuilder", classname: "com.android.ant.ApkBuilderTask", classpathref: "android.antlibs")
71 |
72 | ant.property(name: "aapt", location: new File(platformToolsDir, "aapt${ant['exe']}"))
73 | ant.property(name: "aidl", location: new File(platformToolsDir, "aidl${ant['exe']}"))
74 | ant.property(name: "dx", location: new File(platformToolsDir, "dx${ant['bat']}"))
75 |
76 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/@package", output: "manifest.package")
77 | // TODO: there can be several instrumentations defined
78 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/instrumentation/@android:targetPackage", output: "tested.manifest.package")
79 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/application/@android:hasCode", output: "manifest.hasCode", 'default': "true")
80 |
81 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/instrumentation/@android:name", output: "android.instrumentation")
82 |
83 | if (ant['android.instrumentation']) {
84 | androidConvention.instrumentationTestsRunner = ant['android.instrumentation']
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/ProcessAndroidResources.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android;
18 |
19 |
20 | import org.gradle.api.DefaultTask
21 | import org.gradle.api.file.FileTree
22 | import org.gradle.api.tasks.TaskAction
23 |
24 | import com.jvoegele.gradle.plugins.android.AndroidPluginConvention
25 | import groovy.io.FileType
26 |
27 | import java.util.regex.Matcher
28 |
29 | class ProcessAndroidResources extends DefaultTask {
30 | boolean verbose
31 |
32 | AndroidPluginConvention androidConvention
33 | File genDir
34 |
35 | ProcessAndroidResources () {
36 | super()
37 |
38 | androidConvention = project.convention.plugins.android
39 | genDir = androidConvention.genDir
40 |
41 | // Set input and output files and directories for this task
42 | inputs.file (androidConvention.androidManifest.absolutePath)
43 | inputs.dir (androidConvention.resDir.absolutePath)
44 | outputs.dir (genDir.absolutePath)
45 | }
46 |
47 |
48 | @TaskAction
49 | protected void process() {
50 | genDir.mkdirs()
51 |
52 | generateAIDLFiles()
53 |
54 | project.logger.info("Generating R.java / Manifest.java from the resources...")
55 | project.ant.exec(executable: ant.aapt, failonerror: "true") {
56 | arg(value: "package")
57 | if (verbose) arg(line: "-v")
58 | arg(value: "-m")
59 | arg(value: "-J")
60 | arg(path: genDir.absolutePath)
61 | arg(value: "-M")
62 | arg(path: androidConvention.androidManifest.absolutePath)
63 | androidConvention.resDirs.each { File file ->
64 | arg(value: "-S")
65 | arg(path: file.absolutePath)
66 | }
67 | arg(value: "-I")
68 | arg(path: ant['android.jar'])
69 | }
70 |
71 | generateBuildConfigFile()
72 | }
73 |
74 | private void generateAIDLFiles( ) {
75 | project.logger.info( "Generating AIDL Java files..." )
76 |
77 | project.sourceSets.main.java.srcDirs.each() {
78 | def srcDir = it
79 | if ( srcDir.exists() ) {
80 | def aidlFileTree = project.fileTree( dir: srcDir, include: '**/*.aidl' )
81 |
82 | if ( !aidlFileTree.isEmpty() ) {
83 | aidlFileTree.getFiles().each() {
84 | def aidlFile = new File( it.toString() )
85 |
86 | project.ant.exec( executable: ant.aidl, failonerror: "true" ) {
87 | arg( value: "-I${srcDir.getAbsolutePath()}" )
88 | arg( value: "-o${genDir.absolutePath}" )
89 | arg( value: aidlFile.getAbsolutePath() )
90 | }
91 | }
92 | }
93 | }
94 | }
95 | }
96 |
97 | private void generateBuildConfigFile( ) {
98 | project.logger.info( "Generating BuildConfig.java..." )
99 | def packageDir = getPackageDir()
100 |
101 | // Replace all path separators to a dot and strip out the first dot.
102 | def packageDeclaration = packageDir.replaceAll( Matcher.quoteReplacement(File.separator), '.' )
103 | packageDeclaration = packageDeclaration.substring( 1, packageDeclaration.length() )
104 |
105 | def isDebug = project.version.endsWith("-SNAPSHOT")
106 |
107 | def BuildConfigFile = new File( genDir.absolutePath, packageDir + '/BuildConfig.java' )
108 | BuildConfigFile.write( "package ${packageDeclaration};\n\npublic final class BuildConfig {\n\tpublic final static boolean DEBUG = ${isDebug};\n}" )
109 | }
110 |
111 | private String getPackageDir( ) {
112 | def packageDir
113 |
114 | def genDir = new File( genDir.absolutePath )
115 | genDir.eachFileRecurse( FileType.FILES ) {
116 | if ( ( ~/R.java/ ).matcher( it.name ).find() ) {
117 | // Returns something like /com/example.
118 | packageDir = it.parent.replace( genDir.absolutePath, '' )
119 | }
120 | }
121 |
122 | packageDir
123 | }
124 |
125 | }
126 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/AndroidPackageTask.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android
18 |
19 | import com.jvoegele.gradle.plugins.android.AndroidPluginConvention
20 | import org.gradle.api.DefaultTask
21 | import org.gradle.api.tasks.InputFile
22 | import org.gradle.api.tasks.OutputFile
23 | import org.gradle.api.tasks.TaskAction
24 |
25 | /**
26 | *
27 | * @author think01
28 | *
29 | */
30 | class AndroidPackageTask extends DefaultTask {
31 | String keyStore
32 | String keyAlias
33 | String keyStorePassword
34 | String keyAliasPassword
35 |
36 | boolean verbose
37 | List dexParams
38 |
39 | AndroidPluginConvention androidConvention
40 | AndroidSdkToolsFactory sdkTools
41 |
42 | private boolean keyStoreConfigurationDeprecationShown = false
43 |
44 | def ant
45 |
46 | AndroidPackageTask() {
47 | // Initialize internal data
48 | androidConvention = project.convention.plugins.android
49 | sdkTools = new AndroidSdkToolsFactory(project)
50 | ant = project.ant
51 |
52 | // Set static inputs and outputs for this task
53 | inputs.dir (androidConvention.resDir.absolutePath)
54 | inputs.dir (androidConvention.assetsDir.absolutePath)
55 | inputs.dir (androidConvention.nativeLibsDir.absolutePath)
56 | inputs.file (androidConvention.androidManifest.absolutePath)
57 | inputs.files (project.fileTree (dir: project.sourceSets.main.output.classesDir, exclude: "**/*.class"))
58 | dexParams = ['dex', "output=${androidConvention.intermediateDexFile}"]
59 | }
60 |
61 | // Inputs and outputs files and directories (to be determined dynamically)
62 | @InputFile
63 | File getJarArchivePath() {
64 | return project.jar.archivePath
65 | }
66 |
67 | @OutputFile
68 | File getUnsignedArchivePath() {
69 | return androidConvention.unsignedArchivePath
70 | }
71 |
72 | private void logKeyStoreConfigurationDeprecation() {
73 | if (!keyStoreConfigurationDeprecationShown) {
74 | logger.warn('Configuring signing on androidPackage task is deprecated. You should now configure it on androidSignAndAlign task.')
75 | keyStoreConfigurationDeprecationShown = true
76 | }
77 | }
78 |
79 | void setKeyStore(String keyStore) {
80 | this.keyStore = keyStore
81 | logKeyStoreConfigurationDeprecation()
82 | }
83 |
84 | void setKeyAlias(String keyAlias) {
85 | this.keyAlias = keyAlias
86 | logKeyStoreConfigurationDeprecation()
87 | }
88 |
89 | void setKeyStorePassword(String keyStorePassword) {
90 | this.keyStorePassword = keyStorePassword
91 | logKeyStoreConfigurationDeprecation()
92 | }
93 |
94 | void setKeyAliasPassword(String keyAliasPassword) {
95 | this.keyAliasPassword = keyAliasPassword
96 | logKeyStoreConfigurationDeprecation()
97 | }
98 |
99 | @TaskAction
100 | protected void process() {
101 | // Create necessary directories for this task
102 | getUnsignedArchivePath().getParentFile().mkdirs()
103 |
104 | createPackage()
105 | }
106 |
107 | /**
108 | * Creates a classes.dex file containing all classes required at runtime, i.e.
109 | * all class files from the application itself, plus all its dependencies, and
110 | * bundles it into the final APK.
111 | *
112 | */
113 | private void createPackage() {
114 | logger.info("Converting compiled files and external libraries into ${androidConvention.intermediateDexFile}...")
115 | ant.apply(executable: ant.dx, failonerror: true, parallel: true, logError: true) {
116 | dexParams.each { arg(value: "--$it") }
117 |
118 | if (verbose) arg(line: "--verbose")
119 |
120 | // add classes from application JAR
121 | fileset(file: getJarArchivePath())
122 |
123 | // Add classes from application dependencies block, unless ProGuard is
124 | // enabled, in which case dependencies have already been packaged into
125 | // the application JAR.
126 | if (!project.proguard.enabled) {
127 | project.configurations.runtime.each { fileset file: it }
128 | }
129 | }
130 |
131 | logger.info("Packaging resources")
132 | sdkTools.aaptexec.execute(command: 'package')
133 | sdkTools.apkbuilder.execute('sign': false, 'verbose': verbose)
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/integTest/groovy/com/jvoegele/gradle/android/HelloProjectTest.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.android
18 |
19 | import org.junit.Test
20 |
21 | import com.jvoegele.gradle.tasks.android.AndroidSdkToolsFactory;
22 |
23 | class HelloProjectTest extends AbstractIntegrationTest {
24 | private int toolsRevision = -1
25 |
26 | @Test
27 | void build() {
28 | def p = project('hello')
29 |
30 | p.runTasks 'clean', 'build', buildScript: 'simple.gradle'
31 |
32 | p.fileExists 'build/libs/hello-1.0.jar'
33 | p.fileExists 'build/libs/hello-1.0-unsigned.apk'
34 | p.fileExists 'build/libs/hello-1.0-unaligned.apk'
35 | p.fileExists 'build/distributions/hello-1.0.apk'
36 |
37 | p.archive('build/libs/hello-1.0.jar').assertContains 'com/jvoegele/gradle/android/hello/HelloActivity.class'
38 |
39 | p.archive('build/distributions/hello-1.0.apk').assertAligned()
40 | }
41 |
42 | @Test
43 | void debugBuild() {
44 | def p = project('hello')
45 |
46 | p.runTasks 'clean', 'configureDebug', 'build', buildScript: 'debug-release.gradle'
47 |
48 | assertDebugBuild(p)
49 | }
50 |
51 | @Test
52 | void debugBuildOtherwise() {
53 | def p = project('hello')
54 |
55 | p.runTasks 'clean', 'build', buildScript: 'debug-release-otherwise.gradle'
56 |
57 | assertDebugBuild(p)
58 | }
59 |
60 | void assertDebugBuild(p) {
61 | p.fileExists 'build/libs/hello-1.0-debug.jar'
62 | p.fileExists 'build/libs/hello-1.0-debug-unsigned.apk'
63 | p.fileExists 'build/libs/hello-1.0-debug-unaligned.apk'
64 | p.fileExists 'build/distributions/hello-1.0-debug.apk'
65 | p.fileDoesntExist 'build/libs/hello-1.0.jar'
66 | p.fileDoesntExist 'build/distributions/hello-1.0.apk'
67 |
68 | p.archive('build/libs/hello-1.0-debug.jar').assertContains 'com/jvoegele/gradle/android/hello/HelloActivity.class'
69 |
70 | p.archive('build/distributions/hello-1.0-debug.apk').assertAligned()
71 | if (this.androidSdkToolsRevision >= 8) {
72 | p.archive('build/distributions/hello-1.0-debug.apk').assertDebuggable()
73 | }
74 |
75 | p.archive('build/distributions/hello-1.0-debug.apk').assertSigned('CN=Android Debug, O=Android, C=US')
76 | }
77 |
78 | @Test
79 | void releaseBuild() {
80 | def p = project('hello')
81 |
82 | p.runTasks 'clean', 'configureRelease', 'build', buildScript: 'debug-release.gradle'
83 |
84 | assertReleaseBuild(p)
85 | }
86 |
87 | @Test
88 | void releaseBuildDeprecated() {
89 | def p = project('hello')
90 |
91 | p.runTasks 'clean', 'configureReleaseDeprecated', 'build', buildScript: 'debug-release.gradle'
92 |
93 | assertReleaseBuild(p)
94 | }
95 |
96 | @Test
97 | void releaseBuildOtherwise() {
98 | def p = project('hello')
99 |
100 | p.runTasks 'clean', 'release', buildScript: 'debug-release-otherwise.gradle'
101 |
102 | assertReleaseBuild(p)
103 | }
104 |
105 | void assertReleaseBuild(p) {
106 | p.fileExists 'build/libs/hello-1.0.jar'
107 | p.fileExists 'build/libs/hello-1.0-unsigned.apk'
108 | p.fileExists 'build/libs/hello-1.0-unaligned.apk'
109 | p.fileExists 'build/distributions/hello-1.0.apk'
110 |
111 | p.fileDoesntExist 'build/libs/hello-1.0-debug.jar'
112 | p.fileDoesntExist 'build/distributions/hello-1.0-debug.apk'
113 |
114 | p.archive('build/libs/hello-1.0.jar').assertContains 'com/jvoegele/gradle/android/hello/HelloActivity.class'
115 |
116 | p.archive('build/distributions/hello-1.0.apk').assertAligned()
117 | if (this.androidSdkToolsRevision >= 8) {
118 | p.archive('build/distributions/hello-1.0.apk').assertNotDebuggable()
119 | }
120 |
121 | p.archive('build/distributions/hello-1.0.apk').assertSigned('CN=Gradle Android Plugin integration tests, O=Gradle Android Plugin, C=US')
122 | }
123 |
124 | int getAndroidSdkToolsRevision() {
125 | if (toolsRevision < 0) {
126 | def toolsDir = new File(System.getenv("ANDROID_HOME"), "tools")
127 | assert toolsDir.exists()
128 | def sourcePropertiesFile = new File(toolsDir, AndroidSdkToolsFactory.SOURCE_PROPERTIES_FILE)
129 | assert sourcePropertiesFile.exists()
130 |
131 | Properties props = new Properties()
132 | props.load(new FileInputStream(sourcePropertiesFile))
133 |
134 | toolsRevision = Integer.parseInt(props[AndroidSdkToolsFactory.PKG_REVISION_PROPERTY])
135 | }
136 |
137 | return toolsRevision
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/plugins/android/AndroidSetup_r18.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.plugins.android
18 |
19 | class AndroidSetup_r18 extends AbstractAndroidSetup {
20 | AndroidSetup_r18(project) {
21 | super(project)
22 | }
23 |
24 | void setup() {
25 | def ant = project.ant
26 | def androidConvention = project.convention.plugins.android
27 |
28 | def sdkDir = ant['sdk.dir']
29 | def toolsDir = new File(sdkDir, "tools")
30 | def platformToolsDir = new File(sdkDir, "platform-tools")
31 |
32 | project.logger.info("sdkDir = ${sdkDir}");
33 | project.logger.info("toolsDir = ${toolsDir}");
34 | project.logger.info("platformToolsDir = ${platformToolsDir}");
35 |
36 | ant.condition('property': "exe", value: ".exe", 'else': "") { os(family: "windows") }
37 | ant.condition('property': "bat", value: ".bat", 'else': "") { os(family: "windows") }
38 |
39 | if (platformToolsDir.exists()) { // since SDK r8, adb is moved from tools to platform-tools
40 | ant.property(name: "adb", location: new File(platformToolsDir, "adb${ant['exe']}"))
41 | } else {
42 | ant.property(name: "adb", location: new File(toolsDir, "adb${ant['exe']}"))
43 | }
44 |
45 | ant.property(name: "zipalign", location: new File(toolsDir, "zipalign${ant['exe']}"))
46 | ant.property(name: 'adb.device.arg', value: '')
47 |
48 | def outDir = project.buildDir.absolutePath
49 | ant.property(name: "resource.package.file.name", value: "${project.name}.ap_")
50 |
51 | // Required since SDK r17
52 | ant.property(name: "out.absolute.dir", value:'.')
53 |
54 | ant.taskdef(resource: 'anttasks.properties', classpathref: 'android.antlibs')
55 |
56 | // The following properties are put in place by the setup task:
57 | // android.jar, android.aidl, aapt, aidl, and dx
58 | ant.gettype(
59 | projectTypeOut: "android.project.type",
60 | );
61 |
62 | ant.gettarget(
63 | androidJarFileOut: "android.jar",
64 | androidAidlFileOut: "android.aidl",
65 | bootClassPathOut: "android.target.classpath",
66 | targetApiOut: "project.target.apilevel",
67 | minSdkVersionOut: "project.minSdkVersion",
68 | //renderScriptExeOut: "renderscript",
69 | // renderScriptIncludeDirOut: "android.rs",
70 | //bootclasspathrefOut: "android.target.classpath",
71 | //projectLibrariesRootOut: "project.libraries",
72 | //projectLibrariesJarsOut: "project.libraries.jars",
73 | //projectLibrariesResOut: "project.libraries.res",
74 | //projectLibrariesPackageOut: "project.libraries.package",
75 | //projectLibrariesLibsOut: "project.libraries.libs",
76 | // targetApiOut: "target.api",
77 | );
78 |
79 | ant.dependency(
80 | libraryFolderPathOut: "project.library.folder.path",
81 | libraryPackagesOut: "project.library.packages",
82 | libraryManifestFilePathOut: "project.library.manifest.file.path",
83 | libraryResFolderPathOut: "project.library.res.folder.path",
84 | libraryBinAidlFolderPathOut: "project.library.bin.aidl.folder.path",
85 | libraryNativeFolderPathOut: "project.library.native.folder.path",
86 | jarLibraryPathOut: "project.all.jars.path",
87 |
88 | targetApi: ant['project.target.apilevel'],
89 | verbose: true
90 | );
91 |
92 | ant.property(name: "aapt", location: new File(platformToolsDir, "aapt${ant['exe']}"))
93 | ant.property(name: "aidl", location: new File(platformToolsDir, "aidl${ant['exe']}"))
94 | ant.property(name: "dx", location: new File(platformToolsDir, "dx${ant['bat']}"))
95 | ant.property(name: "renderscript", location: new File(platformToolsDir, "llvm-rs-cc${ant['bat']}"))
96 |
97 | ant.property(name: "android.tools.dir", location:"${ant['sdk.dir']}/tools")
98 | ant.property(name: "android.platform.tools.dir", location:"${ant['sdk.dir']}/platform-tools")
99 |
100 | ant.path(id: "android.renderscript.include.path") {
101 | pathelement(location:"${ant['android.platform.tools.dir']}/renderscript/include");
102 | pathelement(location:"${ant['android.platform.tools.dir']}/renderscript/clang-include");
103 | };
104 |
105 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/@package", output: "manifest.package")
106 | // TODO: there can be several instrumentations defined
107 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/instrumentation/@android:targetPackage", output: "tested.manifest.package")
108 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/application/@android:hasCode", output: "manifest.hasCode", 'default': "true")
109 |
110 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/instrumentation/@android:name", output: "android.instrumentation")
111 |
112 | if (ant['android.instrumentation']) {
113 | androidConvention.instrumentationTestsRunner = ant['android.instrumentation']
114 | }
115 | }
116 | }
117 |
118 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/plugins/android/AndroidSetup_r21.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.plugins.android
18 |
19 | class AndroidSetup_r21 extends AbstractAndroidSetup {
20 | AndroidSetup_r21(project) {
21 | super(project)
22 | }
23 |
24 | void setup() {
25 | def ant = project.ant
26 | def androidConvention = project.convention.plugins.android
27 |
28 | def sdkDir = ant['sdk.dir']
29 | def toolsDir = new File(sdkDir, "tools")
30 | def platformToolsDir = new File(sdkDir, "platform-tools")
31 |
32 | project.logger.info("sdkDir = ${sdkDir}");
33 | project.logger.info("toolsDir = ${toolsDir}");
34 | project.logger.info("platformToolsDir = ${platformToolsDir}");
35 |
36 | ant.condition('property': "exe", value: ".exe", 'else': "") { os(family: "windows") }
37 | ant.condition('property': "bat", value: ".bat", 'else': "") { os(family: "windows") }
38 |
39 | if (platformToolsDir.exists()) { // since SDK r8, adb is moved from tools to platform-tools
40 | ant.property(name: "adb", location: new File(platformToolsDir, "adb${ant['exe']}"))
41 | } else {
42 | ant.property(name: "adb", location: new File(toolsDir, "adb${ant['exe']}"))
43 | }
44 |
45 | ant.property(name: "zipalign", location: new File(toolsDir, "zipalign${ant['exe']}"))
46 | ant.property(name: 'adb.device.arg', value: '')
47 |
48 | def outDir = project.buildDir.absolutePath
49 | ant.property(name: "resource.package.file.name", value: "${project.name}.ap_")
50 |
51 | // Required since SDK r17
52 | ant.property(name: "out.absolute.dir", value:'.')
53 |
54 | ant.taskdef(resource: 'anttasks.properties', classpathref: 'android.antlibs')
55 |
56 | // The following properties are put in place by the setup task:
57 | // android.jar, android.aidl, aapt, aidl, and dx
58 | ant.gettype(
59 | projectTypeOut: "android.project.type",
60 | );
61 |
62 | ant.gettarget(
63 | androidJarFileOut: "android.jar",
64 | androidAidlFileOut: "android.aidl",
65 | bootClassPathOut: "android.target.classpath",
66 | targetApiOut: "project.target.apilevel",
67 | minSdkVersionOut: "project.minSdkVersion",
68 | //renderScriptExeOut: "renderscript",
69 | // renderScriptIncludeDirOut: "android.rs",
70 | //bootclasspathrefOut: "android.target.classpath",
71 | //projectLibrariesRootOut: "project.libraries",
72 | //projectLibrariesJarsOut: "project.libraries.jars",
73 | //projectLibrariesResOut: "project.libraries.res",
74 | //projectLibrariesPackageOut: "project.libraries.package",
75 | //projectLibrariesLibsOut: "project.libraries.libs",
76 | // targetApiOut: "target.api",
77 | );
78 |
79 | ant.dependency(
80 | libraryFolderPathOut: "project.library.folder.path",
81 | libraryPackagesOut: "project.library.packages",
82 | libraryManifestFilePathOut: "project.library.manifest.file.path",
83 | libraryResFolderPathOut: "project.library.res.folder.path",
84 | libraryBinAidlFolderPathOut: "project.library.bin.aidl.folder.path",
85 | libraryRFilePathOut: "project.library.bin.r.file.path",
86 | libraryNativeFolderPathOut: "project.library.native.folder.path",
87 | jarLibraryPathOut: "project.all.jars.path",
88 |
89 | targetApi: ant['project.target.apilevel'],
90 | verbose: true
91 | );
92 |
93 | ant.property(name: "aapt", location: new File(platformToolsDir, "aapt${ant['exe']}"))
94 | ant.property(name: "aidl", location: new File(platformToolsDir, "aidl${ant['exe']}"))
95 | ant.property(name: "dx", location: new File(platformToolsDir, "dx${ant['bat']}"))
96 | ant.property(name: "renderscript", location: new File(platformToolsDir, "llvm-rs-cc${ant['bat']}"))
97 |
98 | ant.property(name: "android.tools.dir", location:"${ant['sdk.dir']}/tools")
99 | ant.property(name: "android.platform.tools.dir", location:"${ant['sdk.dir']}/platform-tools")
100 |
101 | ant.path(id: "android.renderscript.include.path") {
102 | pathelement(location:"${ant['android.platform.tools.dir']}/renderscript/include");
103 | pathelement(location:"${ant['android.platform.tools.dir']}/renderscript/clang-include");
104 | };
105 |
106 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/@package", output: "manifest.package")
107 | // TODO: there can be several instrumentations defined
108 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/instrumentation/@android:targetPackage", output: "tested.manifest.package")
109 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/application/@android:hasCode", output: "manifest.hasCode", 'default': "true")
110 |
111 | ant.xpath(input: androidConvention.androidManifest, expression: "/manifest/instrumentation/@android:name", output: "android.instrumentation")
112 |
113 | if (ant['android.instrumentation']) {
114 | androidConvention.instrumentationTestsRunner = ant['android.instrumentation']
115 | }
116 | }
117 | }
118 |
119 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/"
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED"
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query businessSystem maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/ProGuard.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android;
18 |
19 | import com.jvoegele.gradle.plugins.android.AndroidPluginConvention
20 | import org.gradle.api.DefaultTask
21 | import org.gradle.api.tasks.TaskAction
22 |
23 | /**
24 | * Uses the ProGuard tool to create a minimal JAR containing only those classes
25 | * and resources actually used by the application code.
26 | */
27 | class ProGuard extends DefaultTask {
28 | private static final String PRO_GUARD_RESOURCE = "proguard/ant/task.properties"
29 |
30 | String artifactGroup = "net.sf.proguard"
31 | String artifactName = "proguard"
32 | String artifactVersion = "4.4"
33 |
34 | boolean warn = false
35 | boolean note = false
36 | boolean obfuscate = true
37 |
38 | private boolean proGuardTaskDefined = false
39 |
40 | ProGuard () {
41 | // By default, this task is disabled - it has to be explicitly enabled by user in build.gradle
42 | enabled = false
43 | }
44 |
45 | File getTempFile() {
46 | AndroidPluginConvention androidConvention = project.convention.plugins.android
47 | return new File (project.libsDir, androidConvention.getApkBaseName() + "-proguard-temp.jar")
48 | }
49 |
50 | File getProguardConfig() {
51 | return new File(project.projectDir, "proguard.cfg")
52 | }
53 |
54 | @TaskAction
55 | protected void process() {
56 | defineProGuardTask()
57 |
58 | String tempFilePath = getTempFile().getAbsolutePath()
59 |
60 | Map proguardOptions = [
61 | 'warn': warn,
62 | 'obfuscate': obfuscate
63 | ]
64 |
65 | if (proguardConfig.exists()) {
66 | project.logger.info("File ${proguardConfig} found. Using it.")
67 | proguardOptions['configuration'] = proguardConfig
68 | } else {
69 | project.logger.info("File ${proguardConfig} not found. Using default configuration.")
70 | // use some minimal configuration if proguard.cfg doesn't exist
71 | // this is basically the same as what "android create project" generates
72 | proguardOptions['optimizationpasses'] = 5
73 | proguardOptions['usemixedcaseclassnames'] = false
74 | proguardOptions['skipnonpubliclibraryclasses'] = false
75 | proguardOptions['preverify'] = false
76 | proguardOptions['verbose'] = true
77 | }
78 |
79 | ant.proguard(proguardOptions) {
80 | injar(path: project.jar.archivePath)
81 |
82 | // Add each dependency into the ProGuard-processed JAR
83 | project.configurations.compile.files.each { dependency ->
84 | injar(file: dependency)
85 | }
86 |
87 | outjar(file: tempFilePath)
88 |
89 | ant.references['android.target.classpath'].each { targetjar ->
90 | libraryjar(file: targetjar)
91 | }
92 |
93 | if (!proguardConfig.exists()) {
94 | // use some minimal configuration if proguard.cfg doesn't exist
95 | // this is basically the same as what "android create project" generates
96 | optimizations(filter: "!code/simplification/arithmetic,!field/*,!class/merging/*")
97 |
98 | keep(access: 'public', 'extends': 'android.app.Activity')
99 | keep(access: 'public', 'extends': 'android.app.Application')
100 | keep(access: 'public', 'extends': 'android.app.Service')
101 | keep(access: 'public', 'extends': 'android.content.BroadcastReceiver')
102 | keep(access: 'public', 'extends': 'android.content.ContentProvider')
103 | keep(access: 'public', 'extends': 'android.app.backup.BackupAgentHelper')
104 | keep(access: 'public', 'extends': 'android.preference.Preference')
105 | keep(access: 'public', name: 'com.android.vending.licensing.ILicensingService')
106 | keepclasseswithmembernames {
107 | method(access: 'native')
108 | constructor(access: 'public', parameters: 'android.content.Context,android.util.AttributeSet')
109 | constructor(access: 'public', parameters: 'android.content.Context,android.util.AttributeSet,int')
110 | }
111 | keepclassmembers('extends': 'java.lang.Enum') {
112 | method(access: 'public static', type: '**[]', name: 'values', parameters: '')
113 | method(access: 'public static', type: '**', name: 'valueOf', parameters: 'java.lang.String')
114 | }
115 | keepclassmembers('extends': 'android.app.Activity') {
116 | method(access: 'public', type: 'void', name: '*', parameters: 'android.view.View')
117 | }
118 | keep('implements': 'android.os.Parcelable') {
119 | field(access: 'public static final', type: 'android.os.Parcelable$Creator')
120 | }
121 | }
122 |
123 | keep(access: 'public', 'name': '**.R')
124 | keep('name': '**.R$*')
125 | }
126 |
127 | // Update the output file of this task
128 | ant.move(file: tempFilePath, toFile: project.jar.archivePath, overwrite: true)
129 | }
130 |
131 | private void defineProGuardTask() {
132 | if (!proGuardTaskDefined) {
133 | project.configurations {
134 | proguard
135 | }
136 |
137 | project.dependencies {
138 | proguard group: artifactGroup, name: artifactName, version: artifactVersion
139 | }
140 |
141 | ant.taskdef(resource: PRO_GUARD_RESOURCE, classpath: project.configurations.proguard.asPath)
142 |
143 | proGuardTaskDefined = true
144 | }
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/instrumentation/InstrumentationTestsTask.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android.instrumentation
18 |
19 | import com.jvoegele.gradle.plugins.android.AndroidPlugin;
20 | import com.jvoegele.gradle.tasks.android.AdbExec;
21 | import com.jvoegele.gradle.tasks.android.exceptions.InstrumentationTestsFailedException;
22 | import com.jvoegele.gradle.tasks.android.exceptions.AdbErrorException;
23 |
24 | /**
25 | * Runs instrumentation tests on a connected device or emulator.
26 | *
27 | * @author Matthias Kaeppler
28 | * @author Ladislav Thon
29 | */
30 | class InstrumentationTestsTask extends AdbExec {
31 | def testPackage
32 | def testRunnersConfig
33 | def testReportsSourcePath
34 | def testReportsTargetPath
35 | def defaultAdbArgs
36 |
37 | def InstrumentationTestsTask() {
38 | logger.info("Running instrumentation tests...")
39 |
40 | this.testPackage = ant['manifest.package']
41 | this.defaultAdbArgs = super.getArgs()
42 | this.testRunnersConfig = new TestRunnersConfig(project, testPackage)
43 |
44 | def testedPackage = ant['tested.manifest.package']
45 | if (testedPackage) { // this is only set for instrumentation projects
46 | this.testReportsSourcePath = "/data/data/$testedPackage/files"
47 | this.testReportsTargetPath = project.file('build/test-results').toString()
48 | }
49 |
50 | onlyIf {
51 | boolean isTestingOtherPackage = testedPackage || false
52 | if (!isTestingOtherPackage) {
53 | logger.warn("!! Skipping $AndroidPlugin.ANDROID_INSTRUMENTATION_TESTS_TASK_NAME task "
54 | + "for project $project.name since no target package was specified in the manifest")
55 | }
56 | isTestingOtherPackage
57 | }
58 | }
59 |
60 | /**
61 | * Used to configure test runners using a closure, e.g.:
62 | *
63 | * androidInstrumentationTests {
64 | * runners {
65 | * run testpackage: "com.my.package", with: "com.my.TestRunner"
66 | * }
67 | * }
68 | *
69 | * @param config
70 | * @return
71 | */
72 | def runners(Closure config) {
73 | config.delegate = testRunnersConfig
74 | config()
75 | }
76 |
77 | @Override
78 | def exec() {
79 | if (testRunnersConfig.performDefaultRun()) {
80 | def runConfig = testRunnersConfig.defaultConfig
81 | if (!runConfig) {
82 | // this will happen if there was no runners block provided at all
83 | runConfig = testRunnersConfig.createRunConfig()
84 | }
85 | performTestRun(runConfig)
86 | } else {
87 | // execute package specific runners
88 | testRunnersConfig.packageRunners.each {
89 | def packageName = it.key
90 | def runConfig = it.value
91 | performTestRun(runConfig, ["-e", "package", "$packageName"])
92 | }
93 | // execute annotation specific runners
94 | testRunnersConfig.annotationRunners.each {
95 | def annotation = it.key
96 | def runConfig = it.value
97 | performTestRun(runConfig, ["-e", "annotation", "$annotation"])
98 | }
99 | }
100 | }
101 |
102 | def performTestRun(def runConfig, def filter = null) {
103 | // run the tests
104 | setArgs(defaultAdbArgs)
105 | args "shell", "am", "instrument"
106 | args runConfig.options // it's a List!
107 | if (filter) {
108 | args filter // this too
109 | }
110 | args "$testPackage/$runConfig.runner"
111 |
112 | InstrumentationTestsFailedException testFailure = null
113 | try {
114 | super.exec()
115 | } catch (InstrumentationTestsFailedException itfex) {
116 | testFailure = itfex
117 | } finally {
118 | // publish test results, if any (requires a runner that supports this)
119 | def reportFile = "${testReportsSourcePath}/${runConfig.name}.xml"
120 | try {
121 | publishTestReport(runConfig, reportFile)
122 | } catch (Exception e) {
123 | logger.warn "!! Failed to publish test reports"
124 | }
125 | }
126 |
127 | logger.info "Test run complete."
128 |
129 | if (testFailure) {
130 | throw testFailure
131 | }
132 | }
133 |
134 | private void publishTestReport(def runConfig, def reportFile) {
135 | logger.info("Publishing test results from $reportFile to $testReportsTargetPath")
136 |
137 | def pullTestReport = new AdbExec()
138 | pullTestReport.args "pull", "$reportFile", "$testReportsTargetPath"
139 | pullTestReport.exec()
140 | }
141 |
142 | @Override
143 | def checkForErrors(stream) {
144 | def reader = new InputStreamReader(new ByteArrayInputStream(stream.toByteArray()))
145 | if (stream == stdout) {
146 | detectBuildFailures(reader)
147 | } else { // stderr
148 | detectAdbErrors(reader);
149 | }
150 | }
151 |
152 | private void detectBuildFailures(def reader) {
153 | def success = false
154 | // ADB currently fails with errors on stdout, so we literally have to check
155 | // for 'OK' to decide whether test failed or not
156 | reader.eachLine {
157 | if (it.matches("^OK \\(([0-9]+ test[s]?){1}\\)")) {
158 | success = true
159 | return
160 | }
161 | }
162 |
163 | if (!success) {
164 | throw new InstrumentationTestsFailedException();
165 | }
166 | }
167 |
168 | // at the moment, ADB errors are actually reported via stdout instead of stderr.
169 | // this method may become useful though once Google fixes that.
170 | private void detectAdbErrors(def reader) {
171 | if (reader.getText().trim()) {
172 | // at the moment, we treat any non-empty text on stderr as an error
173 | throw new AdbErrorException("There was an error while trying to run the instrumentation tests")
174 | }
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/tasks/android/AndroidSignAndAlignTask.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.tasks.android
18 |
19 | import com.jvoegele.gradle.plugins.android.AndroidPluginConvention
20 | import org.gradle.api.DefaultTask
21 | import org.gradle.api.tasks.*
22 | import org.gradle.api.GradleException
23 |
24 | import org.apache.tools.ant.util.JavaEnvUtils
25 |
26 | class AndroidSignAndAlignTask extends DefaultTask {
27 | @Optional @Input String keyStore
28 | @Optional @Input String keyAlias
29 | @Optional @Input String keyStorePassword
30 | @Optional @Input String keyAliasPassword
31 | @Optional @Input String sigalg
32 | @Optional @Input String digestalg
33 | @Optional @Input String keyalg
34 | boolean verbose
35 |
36 | private File customUnsingedArchivePath
37 | private AndroidPluginConvention androidConvention = project.convention.plugins.android
38 |
39 | private void doSign(String keystore, String keypass, String storepass, String alias) {
40 | project.ant.copyfile(src: unsignedArchivePath.absolutePath,
41 | dest: buildUnalignedArchivePath().absolutePath,
42 | forceoverwrite: true)
43 |
44 | if (!(new File(keystore)).exists())
45 | throw new GradleException("Keystore file ${keystore} not found")
46 |
47 | def args = [JavaEnvUtils.getJdkExecutable('jarsigner'),
48 | '-verbose',
49 | '-sigalg', sigalg != null ? sigalg : 'MD5withRSA',
50 | '-digestalg', digestalg != null ? digestalg : 'SHA1',
51 | '-keystore', keystore,
52 | '-keypass', keypass,
53 | '-storepass', storepass,
54 | buildUnalignedArchivePath().absolutePath,
55 | alias]
56 |
57 | println "Signing with command:"
58 | for (String s : args)
59 | print s + " "
60 | println ""
61 | def proc = args.execute()
62 | def outRedir = new StreamRedir(proc.inputStream, System.out)
63 | def errRedir = new StreamRedir(proc.errorStream, System.out)
64 |
65 | outRedir.start()
66 | errRedir.start()
67 |
68 | def result = proc.waitFor()
69 | outRedir.join()
70 | errRedir.join()
71 |
72 | if (result != 0)
73 | throw new GradleException('Couldn\'t sign')
74 |
75 | }
76 |
77 | private File buildUnalignedArchivePath() {
78 | return new File(project.libsDir, "${androidConvention.apkBaseName}-unaligned.apk")
79 | }
80 |
81 | @InputFile
82 | File getUnsignedArchivePath() {
83 | customUnsingedArchivePath ?: androidConvention.unsignedArchivePath
84 | }
85 |
86 | void setUnsignedArchivePath(File unsignedArchivePath) {
87 | customUnsingedArchivePath = unsignedArchivePath
88 | }
89 |
90 | @OutputFile
91 | File getApkArchivePath() {
92 | return androidConvention.apkArchivePath
93 | }
94 |
95 | @TaskAction
96 | void process() {
97 | createDirs()
98 | sign()
99 | zipAlign()
100 | }
101 |
102 | private void createDirs() {
103 | apkArchivePath.parentFile.mkdirs()
104 | unsignedArchivePath.parentFile.mkdirs()
105 | buildUnalignedArchivePath().parentFile.mkdirs()
106 | }
107 |
108 | private void sign() {
109 | if (getKeyStore() || getKeyAlias()) {
110 | signWithProvidedKey()
111 | } else {
112 | signWithDebugKey()
113 | }
114 | }
115 |
116 | private void signWithProvidedKey() {
117 | if (!getKeyStorePassword() || !getKeyAliasPassword()) {
118 | def console = System.console()
119 | keyStorePassword = new String(console.readPassword(
120 | "Please enter keystore password (store:${keyStore}): "))
121 | keyAliasPassword = new String(console.readPassword(
122 | "Please enter password for alias '${keyAlias}': "))
123 | }
124 |
125 | logger.info("Signing final apk...")
126 |
127 | doSign(getKeyStore(), keyAliasPassword, keyStorePassword, getKeyAlias())
128 | }
129 |
130 | private String retrieveDebugKeystore() {
131 | File usersAndroidDir = new File(System.getProperty('user.home'), '.android')
132 | if(!usersAndroidDir.exists()){
133 | def result = usersAndroidDir.mkdirs()
134 | if(!result){
135 | throw new GradleException("Failed creating " + usersAndroidDir)
136 | }
137 | }
138 |
139 | File debugKeystore = new File(usersAndroidDir, 'debug.keystore')
140 |
141 | if (!debugKeystore.exists()) {
142 | logger.info('Creating a new debug key...')
143 |
144 | project.ant.genkey(
145 | alias: 'androiddebugkey',
146 | storepass: 'android',
147 | keystore: debugKeystore.absolutePath,
148 | keypass: 'android',
149 | validity: 10 * 365,
150 | storetype: 'JKS',
151 | dname: 'CN=Android Debug,O=Android,C=US',
152 | sigalg: sigalg != null ? sigalg : 'MD5withRSA',
153 | keyalg: keyalg != null ? keyalg : 'RSA')
154 | }
155 |
156 | return debugKeystore.absolutePath
157 | }
158 |
159 | private void signWithDebugKey() {
160 | logger.info("Signing final apk with debug key...")
161 |
162 | doSign(retrieveDebugKeystore(), 'android', 'android', 'androiddebugkey')
163 | }
164 |
165 | private void zipAlign() {
166 | logger.info("Running zip align on final apk...")
167 | String inPath = buildUnalignedArchivePath().absolutePath
168 | String outPath = apkArchivePath.absolutePath
169 | project.exec {
170 | executable ant.zipalign
171 | if (verbose) args '-v'
172 | args '-f', 4, inPath, outPath
173 | }
174 | }
175 | }
176 |
177 | class StreamRedir extends Thread {
178 | private inStream
179 | private outStream
180 |
181 | public StreamRedir(inStream, outStream) {
182 | this.inStream = inStream
183 | this.outStream = outStream
184 | }
185 |
186 | public void run() {
187 | int b;
188 | while ((b = inStream.read()) != -1)
189 | outStream.write(b)
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/src/main/groovy/com/jvoegele/gradle/plugins/android/AndroidPlugin.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.jvoegele.gradle.plugins.android
18 |
19 | import org.gradle.api.GradleException
20 | import org.gradle.api.Plugin
21 | import org.gradle.api.Project
22 | import org.gradle.api.logging.LogLevel
23 | import org.gradle.api.plugins.JavaPlugin
24 |
25 | import com.jvoegele.gradle.enhancements.JavadocEnhancement
26 | import com.jvoegele.gradle.tasks.android.AdbExec
27 | import com.jvoegele.gradle.tasks.android.AndroidPackageTask
28 | import com.jvoegele.gradle.tasks.android.EmulatorTask
29 | import com.jvoegele.gradle.enhancements.EclipseEnhancement
30 | import com.jvoegele.gradle.tasks.android.ProGuard
31 | import com.jvoegele.gradle.tasks.android.ProcessAndroidResources
32 | import com.jvoegele.gradle.tasks.android.instrumentation.InstrumentationTestsTask
33 | import com.jvoegele.gradle.enhancements.ScalaEnhancement
34 | import com.jvoegele.gradle.tasks.android.AndroidSignAndAlignTask
35 |
36 | /**
37 | * Gradle plugin that extends the Java plugin for Android development.
38 | *
39 | * @author Jason Voegele (jason@jvoegele.com)
40 | */
41 | class AndroidPlugin implements Plugin {
42 | public static final ANDROID_PROCESS_RESOURCES_TASK_NAME = "androidProcessResources"
43 | public static final PROGUARD_TASK_NAME = "proguard"
44 | public static final ANDROID_PACKAGE_TASK_NAME = "androidPackage"
45 | public static final ANDROID_SIGN_AND_ALIGN_TASK_NAME = "androidSignAndAlign"
46 | public static final ANDROID_INSTALL_TASK_NAME = "androidInstall"
47 | public static final ANDROID_UNINSTALL_TASK_NAME = "androidUninstall"
48 | public static final ANDROID_INSTRUMENTATION_TESTS_TASK_NAME = "androidInstrumentationTests"
49 | public static final ANDROID_START_EMULATOR_TASK_NAME = "androidEmulatorStart"
50 |
51 | private static final ANDROID_GROUP = "Android";
52 |
53 | private static final PROPERTIES_FILES = ['local', 'build', 'default', 'project']
54 | private static final ANDROID_JARS = ['anttasks', 'sdklib', 'androidprefs', 'apkbuilder', 'jarutils']
55 |
56 | private AndroidPluginConvention androidConvention
57 |
58 | private Project project
59 | private logger
60 |
61 | private androidProcessResourcesTask, proguardTask, androidPackageTask, androidSignAndAlignTask, androidInstallTask, androidUninstallTask, androidInstrumentationTestsTask, androidEmulatorStartTask
62 |
63 | boolean verbose = false
64 |
65 | @Override
66 | void apply(Project project) {
67 | project.plugins.apply(JavaPlugin.class)
68 |
69 | this.project = project
70 | this.logger = project.logger
71 |
72 | androidConvention = new AndroidPluginConvention(project)
73 | project.convention.plugins.android = androidConvention
74 |
75 | androidSetup()
76 | defineTasks()
77 | configureEnhancements()
78 | configureCompile()
79 | }
80 |
81 | private void androidSetup() {
82 | registerPropertyFiles()
83 | determineAndroidDirs()
84 | registerAndroidJars()
85 |
86 | def setupFactory = new AndroidSetupFactory(project)
87 | setupFactory.androidSetup.setup()
88 | }
89 |
90 | private void registerPropertyFiles() {
91 | def ant = project.ant
92 |
93 | PROPERTIES_FILES.each { ant.property(file: "${it}.properties") }
94 | }
95 |
96 | private void determineAndroidDirs() {
97 | def ant = project.ant
98 | def sdkDir
99 |
100 | // Determine the sdkDir value.
101 | // First, let's try the sdk.dir property in local.properties file.
102 | try {
103 | sdkDir = ant['sdk.dir']
104 | } catch (MissingPropertyException e) {
105 | sdkDir = null
106 | }
107 |
108 | if (sdkDir == null || sdkDir.length() == 0) {
109 | // No local.properties and/or no sdk.dir property: let's try ANDROID_HOME
110 | sdkDir = System.getenv("ANDROID_HOME")
111 | // Propagate it to the Gradle's Ant environment
112 | if (sdkDir != null) {
113 | ant.setProperty("sdk.dir", sdkDir)
114 | }
115 | }
116 |
117 | // Check for sdkDir correctly valued, and in case throw an error
118 | if (sdkDir == null || sdkDir.length() == 0) {
119 | throw new MissingPropertyException("Unable to find location of Android SDK. Please read documentation.")
120 | }
121 | }
122 |
123 | private void registerAndroidJars() {
124 | def ant = project.ant
125 | def sdkDir = ant['sdk.dir']
126 |
127 | ant.path(id: 'android.antlibs') {
128 | ANDROID_JARS.each { pathelement(path: "${sdkDir}/tools/lib/${it}.jar") }
129 | }
130 | }
131 |
132 | private void defineTasks() {
133 | defineAndroidProcessResourcesTask()
134 | defineProguardTask()
135 | defineAndroidPackageTask()
136 | defineAndroidSignAndAlignTask()
137 | defineAndroidInstallTask()
138 | defineAndroidUninstallTask()
139 | defineAndroidEmulatorStartTask()
140 | defineAndroidInstrumentationTestsTask()
141 | defineTaskDependencies()
142 | configureTaskLogging()
143 | }
144 |
145 | private void defineAndroidProcessResourcesTask() {
146 | androidProcessResourcesTask = project.task(
147 | ANDROID_PROCESS_RESOURCES_TASK_NAME,
148 | group: ANDROID_GROUP,
149 | description: "Generate R.java source file from Android resource XML files",
150 | type: ProcessAndroidResources)
151 | }
152 |
153 | private void defineProguardTask() {
154 | proguardTask = project.task(
155 | PROGUARD_TASK_NAME,
156 | group: ANDROID_GROUP,
157 | description: "Process classes and JARs with ProGuard",
158 | type: ProGuard)
159 | }
160 |
161 | private void defineAndroidPackageTask() {
162 | androidPackageTask = project.task(
163 | ANDROID_PACKAGE_TASK_NAME,
164 | group: ANDROID_GROUP,
165 | description: "Creates the Android application apk package",
166 | type: AndroidPackageTask)
167 | }
168 |
169 | private void defineAndroidSignAndAlignTask() {
170 | androidSignAndAlignTask = project.task(
171 | ANDROID_SIGN_AND_ALIGN_TASK_NAME,
172 | group: ANDROID_GROUP,
173 | description: "Signs and zipaligns the application apk package",
174 | type: AndroidSignAndAlignTask)
175 |
176 | ['keyStore', 'keyAlias', 'keyStorePassword', 'keyAliasPassword'].each { String propertyName ->
177 | androidSignAndAlignTask.conventionMapping[propertyName] = { androidPackageTask[propertyName] }
178 | }
179 | }
180 |
181 | private void defineAndroidInstallTask() {
182 | androidInstallTask = project.task(
183 | ANDROID_INSTALL_TASK_NAME,
184 | group: ANDROID_GROUP,
185 | description: "Installs the debug package onto a running emulator or device",
186 | type: AdbExec) {
187 | doFirst {
188 | logger.info("Installing ${androidConvention.getApkArchivePath()} onto default emulator or device...")
189 | args 'install', '-r', androidConvention.apkArchivePath
190 | }
191 | }
192 | }
193 |
194 | private void defineAndroidUninstallTask() {
195 | androidUninstallTask = project.task(
196 | ANDROID_UNINSTALL_TASK_NAME,
197 | group: ANDROID_GROUP,
198 | description: "Uninstalls the application from a running emulator or device",
199 | type: AdbExec) {
200 | def manifestPackage = null
201 |
202 | try {
203 | manifestPackage = ant['manifest.package']
204 | } catch (Exception e) {
205 | throw new GradleException("Application package is not defined in AndroidManifest.xml, unable to uninstall.", e)
206 | }
207 |
208 | // Should uninstall fail only because the package wasn't on the device? It does now...
209 | args 'uninstall', manifestPackage
210 |
211 | doFirst {
212 | logger.info("Uninstalling ${manifestPackage} from the default emulator or device...")
213 | }
214 | }
215 | }
216 |
217 | private void defineAndroidEmulatorStartTask() {
218 | androidEmulatorStartTask = project.task(
219 | ANDROID_START_EMULATOR_TASK_NAME,
220 | group: ANDROID_GROUP,
221 | description: "Starts the android emulator",
222 | type: EmulatorTask)
223 | }
224 |
225 | private void defineAndroidInstrumentationTestsTask() {
226 | def description = """
227 | Runs instrumentation tests on a running emulator or device.
228 | Use the 'runners' closure to configure your test runners:
229 |
230 | androidInstrumentationTests {
231 | runners {
232 | run testpackage: "com.my.package", with: "com.my.TestRunner"
233 | run annotation: "com.my.Annotation", with: "com.my.OtherRunner"
234 | }
235 | }
236 |
237 | You can also use 'run with: "..."' to run all tests using the given runner, but
238 | note that this only works as long as you do not bind any other more specific runners.
239 | """
240 |
241 | androidInstrumentationTestsTask = project.task(
242 | ANDROID_INSTRUMENTATION_TESTS_TASK_NAME,
243 | group: ANDROID_GROUP,
244 | description: description,
245 | type: InstrumentationTestsTask)
246 | }
247 |
248 | private void defineTaskDependencies() {
249 | project.tasks.compileJava.dependsOn(androidProcessResourcesTask)
250 | proguardTask.dependsOn(project.tasks.jar)
251 | androidPackageTask.dependsOn(proguardTask)
252 | androidSignAndAlignTask.dependsOn(androidPackageTask)
253 | project.tasks.assemble.dependsOn(androidSignAndAlignTask)
254 | androidInstallTask.dependsOn(project.tasks.assemble)
255 | androidInstrumentationTestsTask.dependsOn(androidInstallTask)
256 | }
257 |
258 | private void configureTaskLogging() {
259 | androidProcessResourcesTask.logging.captureStandardOutput(LogLevel.INFO)
260 | proguardTask.logging.captureStandardOutput(LogLevel.INFO)
261 | androidPackageTask.logging.captureStandardOutput(LogLevel.INFO)
262 | androidSignAndAlignTask.logging.captureStandardOutput(LogLevel.INFO)
263 | androidInstallTask.logging.captureStandardOutput(LogLevel.INFO)
264 | androidUninstallTask.logging.captureStandardOutput(LogLevel.INFO)
265 | }
266 |
267 | /**
268 | * Configure enhancements to other Gradle plugins so that they work better in
269 | * concert with the Android plugin.
270 | */
271 | private void configureEnhancements() {
272 | new JavadocEnhancement(project).apply()
273 | new EclipseEnhancement(project).apply()
274 | new ScalaEnhancement(project).apply()
275 | }
276 |
277 | private void configureCompile() {
278 | def mainSource = project.tasks.compileJava.source
279 | project.tasks.compileJava.source = [androidConvention.genDir, mainSource]
280 | project.sourceSets.main.compileClasspath +=
281 | project.files(project.ant.references['android.target.classpath'].list())
282 | project.compileJava.options.bootClasspath = project.ant.references['android.target.classpath']
283 | }
284 | }
285 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | DISCONTINUED
2 | ============
3 |
4 | We are very sorry to announce that development of this plugin has been discontinued.
5 | Google has created their own Android development toolchain based on Gradle, which supercedes this plugin.
6 |
7 | Please see http://tools.android.com/tech-docs/new-build-system/user-guide for further information.
8 |
9 | ABOUT
10 | =====
11 |
12 | This is the Android plugin for the Gradle build system. This plugin
13 | enables the creation of Android applications using Gradle, with all of
14 | the power and flexibility you've come to expect from Gradle.
15 |
16 | Currently, Gradle 1.0-rc-3 is required.
17 |
18 | For mailing lists see the project page on Google Code:
19 | https://code.google.com/p/gradle-android-plugin/
20 |
21 | For issue tracking see the GitHub issues page:
22 | https://github.com/jvoegele/gradle-android-plugin/issues
23 |
24 | FEATURES
25 | ========
26 |
27 | Features of the Android plugin include:
28 |
29 | * Compile, package, and install Android applications. (Including
30 | handling of Android resource files.)
31 | * Sign application packages using the default debug key, or with a
32 | release key for publication to Android Market.
33 | * Incorporation of ProGuard to ensure that applications have minimal
34 | memory footprint.
35 | * Easily create Android applications in Scala (and possibly Groovy or Clojure).
36 |
37 | The Android plugin fully integrates into the Gradle build lifecycle by
38 | extending the Java plugin. Furthermore, the incorporation of ProGuard
39 | into the build not only ensures that Android application packages are
40 | small and tight, it also trivially enables the use of Scala for Android
41 | application development simply by incorporating the existing Scala
42 | plugin into the build. ProGuard will include only those classes
43 | from the Scala library that are actually used by your Android
44 | application, resulting in an application package that is as small as
45 | possible.
46 |
47 |
48 | TASKS AND LIFECYCLE
49 | ===================
50 |
51 | The Android plugin adds the following tasks and dependencies to the
52 | build:
53 |
54 | :androidProcessResources
55 | Generate R.java source file from Android resource XML files (:compileJava task depends on this task)
56 |
57 | :proguard
58 | Process classes and JARs with ProGuard (by default, this task is disabled, more on this below)
59 | -> :jar
60 |
61 | :androidPackage
62 | Creates the Android application apk package
63 | -> :proguard
64 |
65 | :androidSignAndAlign
66 | Signs (with a debug or provided key; more on this below) and zipaligns the application apk package
67 | -> :androidPackage
68 | (:assemble lifecycle task depends on this task)
69 |
70 | :androidInstall
71 | Installs the built package onto a running emulator or device
72 | -> :assemble
73 |
74 | :androidUninstall
75 | Uninstalls the application from a running emulator or device
76 |
77 | :androidEmulatorStart
78 | Starts the android emulator
79 |
80 | :androidInstrumentationTests
81 | Runs an instrumentation test suite on a running emulator or device
82 | -> :androidInstall
83 |
84 | USAGE
85 | =====
86 |
87 | To use the Android plugin for Gradle you must first create the
88 | application skeleton using the android command-line tool. For example:
89 |
90 | $ android create project --target 1 --path ./MyAndroidApp \
91 | --activity MyAndroidActivity --package my.android.package
92 |
93 | This will create and Android application skeleton that you can
94 | immediately build using Ant. To build with Gradle instead, you must (1)
95 | create a build.gradle file that includes the Android plugin, and (2)
96 | either move the source code to the directory expected by Gradle, or tell
97 | Gradle to use the src directory of your project directly.
98 |
99 | 1) Create a build.gradle file in the root directory of the project, and
100 | include the Android plugin as follows:
101 |
102 | buildscript {
103 | repositories {
104 | mavenCentral()
105 | }
106 |
107 | dependencies {
108 | classpath 'org.gradle.api.plugins:gradle-android-plugin:1.2.1'
109 | }
110 | }
111 | apply plugin: 'android'
112 | repositories {
113 | mavenCentral()
114 | }
115 |
116 | 2) The android create project command created the source code directly in the
117 | src directory of the project. The Android plugin tries to conform to the
118 | conventions established by Android's Ant-based build, but in this case
119 | it is better to conform to Gradle's "source sets" convention, since it allows
120 | you to have separate test source code, or to use multiple languages.
121 | Therefore, we recommend that the source should be moved to src/main/java
122 | instead. Once you've done this you can, of course, utilize Gradle's source
123 | sets to their full extent by placing resources in src/main/resources, Scala
124 | source files in src/main/scala etc. However, if you prefer to keep your
125 | source code directly in the src directory (for example, if you need to retain
126 | compatibility with Ant) then you can do so by configuring the Java source set
127 | in your build.gradle file. Just add the following to build.gradle:
128 |
129 | sourceSets {
130 | main {
131 | java {
132 | srcDir 'src/java'
133 | }
134 | }
135 | }
136 |
137 | If your Android project was initially created by Eclipse rather than
138 | the android create project command, then you will have some additional
139 | setup work to do. The Android plugin for Gradle must be told the
140 | location of the Android SDK. When you create a project with the
141 | android create project command, the location is filled in for you by
142 | the application generator, but the Eclipse project generator does not
143 | provide this information to the project. Therefore, you must fill it
144 | in yourself. To do this, create (or edit) the local.properties file in
145 | the root of the project and add the sdk.dir property, referring to the
146 | location of your Android SDK installation:
147 |
148 | sdk.dir = /path/to/android/sdk
149 |
150 | Note that this file should not be checked in to your version control
151 | system as it will likely differ across various development
152 | environments. Alternatively, you can use the ANDROID_HOME environment
153 | variable instead.
154 |
155 | Once you've performed these steps you can build your Android application
156 | by invoking the tasks described above.
157 |
158 | A complete minimal but real-world example is as follows.
159 |
160 | build.gradle
161 | ------------
162 |
163 | buildscript {
164 | repositories {
165 | mavenCentral()
166 | // To use a development snapshot version of the plugin, add the
167 | // Sonatype Snapshots repository.
168 | maven {
169 | url "https://oss.sonatype.org/content/repositories/snapshots"
170 | }
171 | }
172 |
173 | dependencies {
174 | classpath 'org.gradle.api.plugins:gradle-android-plugin:1.2.1'
175 | }
176 | }
177 |
178 | apply plugin: 'android'
179 |
180 | repositories {
181 | mavenCentral()
182 | }
183 |
184 | // Sets the package version
185 | version = "1.0.0"
186 |
187 | // Signing configuration, valid for all builds (1)
188 | androidSignAndAlign {
189 | keyStore = "path/to/my/keystore"
190 | keyAlias = "my-key-alias"
191 | keyStorePassword = "mystorepass"
192 | keyAliasPassword = "myaliaspass"
193 | }
194 |
195 | // Configure the filtering of resources with properties from the Gradle's project scope (2)
196 | processResources {
197 | expand (project.properties)
198 | }
199 |
200 | // Configure a dedicated debug build (3)
201 | task configureDebug << {
202 | jar.classifier = "debug"
203 | }
204 |
205 | // Configure a dedicated release build (4)
206 | task configureRelease << {
207 | proguard.enabled = true
208 | }
209 |
210 | ============
211 |
212 |
213 | This build script configures the build to sign with a provided keystore. This
214 | configuration applies for every build (1).
215 | It also sets Gradle to expand properties in every resource file (2).
216 |
217 | In this way you can get a full build with the command:
218 |
219 | gradle assemble
220 |
221 | It processes all the resources, expanding them with properties from the project's scope,
222 | compiles classes, packs them into the dex file, builds the apk, signs it with
223 | the provided keystore (but does not process it with proguard) and zipaligns
224 | the package, which is named -x.y.z.apk and placed in /build/distributions.
225 | You can see the proguard task is skipped from Gradle's output during the build.
226 |
227 | You can create several build configurations and choose which one to execute from the
228 | gradle command line.
229 | The task configureDebug (3) defines the Gradle classifier for the package name.
230 | Executing this build with the command:
231 |
232 | gradle configureDebug assemble
233 |
234 | creates a package with same steps than the default build, but the package name
235 | is project-x.y.z-debug.apk.
236 |
237 | The task configureRelease (4) defines a release configuration task, which
238 | activate the proguard step. Again, you get the package named -x.y.z.apk
239 | in the same output directory.
240 |
241 | To disable signing and get a signed apk with the debug key, you can remove the
242 | androidPackage configuration (1): if keyStore or keyAlias are null, the signing is
243 | skipped and the debug key is used. Of course, you can put the signing configuration
244 | in a dedicated configuration task and invoke that task in order to get a signed
245 | package (or not to call it for the debug signed package).
246 |
247 | Also note that if you don't supply password (that is, keyStorePassword or keyAliasPassword
248 | are null), Gradle asks for them on the command line (not very good for CI servers...).
249 |
250 |
251 | To install the generated apk onto a running emulator or a device connected with USB (and
252 | configured in debug mode), run:
253 |
254 | gradle androidInstall
255 |
256 | This installs the default built package; as with previous examples, if you want to install the
257 | debug (or release) package, you have to issue:
258 |
259 | gradle configureDebug androidInstall
260 |
261 | or
262 |
263 | gradle configureRelease androidInstall
264 |
265 |
266 | The androidUninstall task unistalls the application from a running emulator or a device.
267 | There is no need to specify which package: there can be only one package to undeploy and
268 | it's defined by the base package name of the application, from androidManifest.xml.
269 |
270 | ECLIPSE
271 | =======
272 | You can use Gradle to generate an Eclipse project for you. The Android plugin enhances this
273 | process by setting up the Eclipse project correctly for Android, which includes establishing
274 | the correct class path and inserting the Android builders into the build process.
275 |
276 | To use the Eclipse integration, first make sure that you apply the Gradle Eclipse plugin in
277 | your build.gradle file:
278 |
279 | apply plugin: 'eclipse'
280 |
281 | Then you can generate the Eclipse project files as follows:
282 |
283 | gradle eclipse
284 |
285 |
286 | INSTRUMENTATION TESTS
287 | =====================
288 | The plugin is able to run instrumentation tests for you on a connected device or emulator:
289 |
290 | gradle androidInstrumentationTests
291 |
292 | On projects that do not define any instrumentations in their manifest, this task will safely
293 | be skipped. By default, the task runs all tests in the given project, using Android's default
294 | test runner. If you want more control, you can add a configure closure to your test project:
295 |
296 | androidInstrumentationTests {
297 | runners {
298 | run with: "com.mydomain.MyTestRunner", options: "..."
299 | }
300 | }
301 |
302 | The 'run' method can you be used in different ways. If used as above, all tests will be run
303 | using the given test runner. The 'options' field can be used to route parameters to the
304 | Activity manager that's used to run the instrumentation (cf. 'adb shell am instrument').
305 | Note that you don't have to supply the "-w" parameter, that's done by default.
306 |
307 | You can also partition your test suite to run with different runners. Note that this only
308 | works if you don't also have a more general runner configured as seen above. Currently,
309 | the plugin allows you to partition by test package and annotation:
310 |
311 | run testpackage: ".unit", with: ".MyUnitTestRunner"
312 | run annotation: "android.test.suitebuilder.annotation.Smoke", with: ".MySmokeTestRunner"
313 |
314 | If your test project's package ID is com.myapp.test, then this configuration will first run
315 | all test cases within the com.myapp.test.unit package with the com.myapp.test.MyUnitTestRunner,
316 | and then run all test cases carrying Android's "Smoke" annotation in the same manner.
317 |
318 | There is also limited support for publishing JUnit compliant test reports that can be read
319 | by build servers like Hudson. Currently, this only works if you're using the Android JUnit
320 | test report runner or a sub-class of it: https://github.com/jsankey/android-junit-report
321 | In that case, the test reports generated by that runner will be published to build/test-results.
322 | We plan to make this more flexible and configurable in future versions.
323 |
324 | START EMULATOR
325 | =====================
326 | For starting the emulator wih gradle, you need do define the AVD-Name from your android-emulator
327 | in your build.gradle:
328 |
329 | androidEmulatorStart {
330 | avdName = "Main"
331 | }
332 |
333 |
334 | LIMITATIONS
335 | ===========
336 |
337 | * In the current version of the Android plugin, the proguard task is not very configurable.
338 | * The androidManifest.xml file is not processed as a normal resource, i.e. there is
339 | no properties expansion (so, for example, you don't get the version set in the version tag,
340 | you have to align them manually).
341 |
--------------------------------------------------------------------------------