├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── io │ │ │ └── github │ │ │ └── lizhangqu │ │ │ └── samples │ │ │ └── MainActivity.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── io │ └── github │ └── lizhangqu │ └── samples │ └── ExampleUnitTest.java ├── build.gradle ├── buildSrc ├── .gitignore ├── build.gradle └── src │ └── main │ ├── groovy │ └── io │ │ └── github │ │ └── lizhangqu │ │ └── plugin │ │ └── compat │ │ └── CompatPlugin.groovy │ └── resources │ └── META-INF │ └── gradle-plugins │ └── com.android.compat.properties ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android Gradle Plugin兼容插件 2 | 3 | 4 | ### 在com.android.application中使用provided aar功能 5 | 6 | 首先调用一遍 7 | 8 | ``` 9 | providedAarCompat() 10 | ``` 11 | 12 | 然后就可以正常使用providedAar了,如 13 | 14 | ``` 15 | dependencies { 16 | providedAar 'com.tencent.tinker:tinker-android-lib:1.9.1' 17 | } 18 | ``` 19 | 20 | 目前只支持如下版本 21 | - android gradle plugin [1.3.0,3.1.0], 支持传递依赖 22 | 23 | 小于1.3.0的版本不支持,抛异常 24 | 25 | ### aapt2是否开启 26 | 27 | ``` 28 | if (isAapt2EnabledCompat()) { 29 | 30 | } else { 31 | 32 | } 33 | ``` 34 | 35 | ### aapt2 jni方式是否开启 36 | 37 | ``` 38 | if (isAapt2JniEnabledCompat()) { 39 | 40 | } else { 41 | 42 | } 43 | ``` 44 | 45 | ### aapt2 守护进程方式是否开启 46 | 47 | ``` 48 | if (isAapt2DaemonModeEnabledCompat()) { 49 | 50 | } else { 51 | 52 | } 53 | ``` 54 | 55 | ### 获取 android gradle plugin 版本号 56 | 57 | ``` 58 | String androidGradlePluginVersion = getAndroidGradlePluginVersionCompat() 59 | ``` 60 | 61 | ### 是否在jenkins环境中 62 | 63 | ``` 64 | boolean onJenkins = isJenkins() 65 | ``` 66 | 67 | ### 获取R.java文件中的包名 68 | 69 | ``` 70 | String packageForR = getPackageForRCompatCompat('release') 71 | ``` 72 | 73 | ### 获取R.java文件路径 74 | 75 | ``` 76 | File rFile = getRFileCompat('release') 77 | ``` 78 | 79 | 80 | ### 获取R.java文件去除包名后的父路径 81 | 82 | ``` 83 | File rDir = getRDirCompat('release') 84 | ``` 85 | 86 | ### 获取resource.ap_文件路径 87 | 88 | ``` 89 | File apFile = getPublishApFileCompat('release') 90 | ``` -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'com.android.compat' 3 | 4 | 5 | project.logger.error "[CompatPlugin] isAapt2EnabledCompat:${isAapt2EnabledCompat()}" 6 | project.logger.error "[CompatPlugin] isAapt2JniEnabledCompat:${isAapt2JniEnabledCompat()}" 7 | project.logger.error "[CompatPlugin] isAapt2DaemonModeEnabledCompat:${isAapt2DaemonModeEnabledCompat()}" 8 | project.logger.error "[CompatPlugin] getAndroidGradlePluginVersionCompat:${getAndroidGradlePluginVersionCompat()}" 9 | project.logger.error "[CompatPlugin] isJenkins:${isJenkins()}" 10 | 11 | //启用providedAar功能 12 | providedAarCompat() 13 | 14 | android { 15 | compileSdkVersion 26 16 | buildToolsVersion '26.0.2' 17 | defaultConfig { 18 | applicationId "io.github.lizhangqu.samples" 19 | minSdkVersion 14 20 | targetSdkVersion 26 21 | versionCode 1 22 | versionName "1.0" 23 | } 24 | buildTypes { 25 | debug { 26 | 27 | } 28 | release { 29 | minifyEnabled false 30 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 31 | } 32 | } 33 | } 34 | 35 | 36 | dependencies { 37 | compile fileTree(dir: 'libs', include: ['*.jar']) 38 | compile 'com.android.support:appcompat-v7:26.1.0' 39 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 40 | testCompile 'junit:junit:4.12' 41 | 42 | providedAar 'com.tencent.tinker:tinker-android-lib:1.9.1' 43 | 44 | 45 | } 46 | 47 | 48 | project.afterEvaluate { 49 | project.logger.error "host getPublishApFileCompat:${getPublishApFileCompat('release')}" 50 | project.logger.error "host getRDirCompat:${getRDirCompat('release')}" 51 | project.logger.error "host getRFileCompat:${getRFileCompat('release')}" 52 | project.logger.error "host getPackageForRCompatCompat:${getPackageForRCompatCompat('release')}" 53 | project.logger.error "host R File exists:${getRFileCompat('release').exists()}" 54 | } 55 | 56 | project.logger.error "getPublishApFileCompat:${getPublishApFileCompat('release')}" 57 | project.logger.error "getRDirCompat:${getRDirCompat('release')}" 58 | project.logger.error "getRFileCompat:${getRFileCompat('release')}" 59 | project.logger.error "getPackageForRCompatCompat:${getPackageForRCompatCompat('release')}" 60 | project.logger.error "R File exists:${getRFileCompat('release').exists()}" 61 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/io/github/lizhangqu/samples/MainActivity.java: -------------------------------------------------------------------------------- 1 | package io.github.lizhangqu.samples; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | 6 | import com.tencent.tinker.lib.tinker.Tinker; 7 | 8 | public class MainActivity extends AppCompatActivity { 9 | 10 | @Override 11 | protected void onCreate(Bundle savedInstanceState) { 12 | super.onCreate(savedInstanceState); 13 | setContentView(R.layout.activity_main); 14 | Tinker.with(getApplicationContext()).cleanPatch(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhangqu/AndroidGradlePluginCompat/d1e974aa0fadc4c6a211a5421427d465491e78e2/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhangqu/AndroidGradlePluginCompat/d1e974aa0fadc4c6a211a5421427d465491e78e2/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhangqu/AndroidGradlePluginCompat/d1e974aa0fadc4c6a211a5421427d465491e78e2/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhangqu/AndroidGradlePluginCompat/d1e974aa0fadc4c6a211a5421427d465491e78e2/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhangqu/AndroidGradlePluginCompat/d1e974aa0fadc4c6a211a5421427d465491e78e2/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhangqu/AndroidGradlePluginCompat/d1e974aa0fadc4c6a211a5421427d465491e78e2/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhangqu/AndroidGradlePluginCompat/d1e974aa0fadc4c6a211a5421427d465491e78e2/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhangqu/AndroidGradlePluginCompat/d1e974aa0fadc4c6a211a5421427d465491e78e2/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhangqu/AndroidGradlePluginCompat/d1e974aa0fadc4c6a211a5421427d465491e78e2/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhangqu/AndroidGradlePluginCompat/d1e974aa0fadc4c6a211a5421427d465491e78e2/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | AndroidGradlePluginSamples 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/io/github/lizhangqu/samples/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package io.github.lizhangqu.samples; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | maven { url 'https://maven.google.com' } 6 | jcenter() 7 | } 8 | dependencies { 9 | File localFile = project.rootProject.file('local.properties') 10 | Properties extProperties = new Properties() 11 | if (localFile.exists()) { 12 | extProperties.load(localFile.newDataInputStream()) 13 | } 14 | def androidGradlePluginVersion = "3.0.1" 15 | if (extProperties.containsKey('gradleVersion')) { 16 | androidGradlePluginVersion = extProperties.get("gradleVersion") as String 17 | } 18 | project.logger.error "root build.gradle androidGradlePluginVersion ${androidGradlePluginVersion}" 19 | 20 | classpath "com.android.tools.build:gradle:${androidGradlePluginVersion}" 21 | } 22 | } 23 | 24 | allprojects { 25 | repositories { 26 | maven { url 'https://maven.google.com' } 27 | jcenter() 28 | } 29 | } 30 | 31 | task clean(type: Delete) { 32 | delete rootProject.buildDir 33 | } 34 | -------------------------------------------------------------------------------- /buildSrc/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | -------------------------------------------------------------------------------- /buildSrc/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'groovy' 2 | apply plugin: 'idea' 3 | apply plugin: 'maven' 4 | sourceCompatibility = 1.8 5 | 6 | repositories { 7 | maven { url 'https://maven.google.com' } 8 | jcenter() 9 | } 10 | configurations { 11 | provided 12 | } 13 | 14 | idea { 15 | module { 16 | scopes.PROVIDED.plus += [configurations.provided] 17 | } 18 | } 19 | 20 | sourceSets { 21 | main { 22 | compileClasspath += configurations.provided 23 | } 24 | } 25 | 26 | dependencies { 27 | compile gradleApi() 28 | compile localGroovy() 29 | compile "commons-io:commons-io:2.6" 30 | compile 'commons-codec:commons-codec:1.10' 31 | 32 | File localFile = project.rootProject.file('../local.properties') 33 | Properties extProperties = new Properties() 34 | if (localFile.exists()) { 35 | extProperties.load(localFile.newDataInputStream()) 36 | } 37 | def androidGradlePluginVersion = "3.0.1" 38 | if (extProperties.containsKey('gradleVersion')) { 39 | androidGradlePluginVersion = extProperties.get("gradleVersion") as String 40 | } 41 | project.logger.error "buildSrc build.gradle androidGradlePluginVersion ${androidGradlePluginVersion}" 42 | 43 | compile "com.android.tools.build:gradle:${androidGradlePluginVersion}" 44 | 45 | } 46 | 47 | 48 | //remove install task compile 'com.android.tools.build:gradle:$androidGradlePluginVersion' 49 | install { 50 | repositories { 51 | mavenInstaller { 52 | pom { 53 | whenConfigured { p -> 54 | p.dependencies = p.dependencies.findAll { 55 | dep -> (dep.groupId != "com.android.tools.build" && dep.artifactId != "gradle") 56 | } 57 | } 58 | } 59 | } 60 | } 61 | } 62 | //remove uploadArchives task compile 'com.android.tools.build:gradle:$androidGradlePluginVersion' 63 | uploadArchives { 64 | repositories { 65 | mavenDeployer { 66 | pom { 67 | whenConfigured { p -> 68 | p.dependencies = p.dependencies.findAll { 69 | dep -> (dep.groupId != "com.android.tools.build" && dep.artifactId != "gradle") 70 | } 71 | } 72 | } 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /buildSrc/src/main/groovy/io/github/lizhangqu/plugin/compat/CompatPlugin.groovy: -------------------------------------------------------------------------------- 1 | package io.github.lizhangqu.plugin.compat 2 | 3 | import org.gradle.api.GradleException 4 | import org.gradle.api.Plugin 5 | import org.gradle.api.Project 6 | import org.gradle.api.artifacts.Configuration 7 | import org.gradle.api.artifacts.component.ComponentIdentifier 8 | import org.gradle.api.artifacts.component.ModuleComponentIdentifier 9 | import org.gradle.api.artifacts.component.ProjectComponentIdentifier 10 | import org.gradle.api.artifacts.result.ResolvedArtifactResult 11 | import org.gradle.util.GFileUtils 12 | import java.lang.reflect.Field 13 | 14 | /** 15 | * Android Gradle Plugin兼容插件 16 | */ 17 | class CompatPlugin implements Plugin { 18 | Project project 19 | 20 | @Override 21 | void apply(Project project) { 22 | this.project = project 23 | project.ext.isAapt2EnabledCompat = this.&isAapt2EnabledCompat 24 | project.ext.isAapt2JniEnabledCompat = this.&isAapt2JniEnabledCompat 25 | project.ext.isAapt2DaemonModeEnabledCompat = this.&isAapt2DaemonModeEnabledCompat 26 | project.ext.getAndroidGradlePluginVersionCompat = this.&getAndroidGradlePluginVersionCompat 27 | project.ext.isJenkins = this.&isJenkins 28 | project.ext.providedAarCompat = this.&providedAarCompat 29 | 30 | project.ext.getPublishApFileCompat = this.&getPublishApFileCompat 31 | project.ext.getRDirCompat = this.&getRDirCompat 32 | project.ext.getRFileCompat = this.&getRFileCompat 33 | project.ext.getPackageForRCompatCompat = this.&getPackageForRCompatCompat 34 | } 35 | 36 | static T resolveEnumValue(String value, Class type) { 37 | for (T constant : type.getEnumConstants()) { 38 | if (constant.toString().equalsIgnoreCase(value)) { 39 | return constant 40 | } 41 | } 42 | return null 43 | } 44 | 45 | 46 | def getProjectOptions() { 47 | Class classProjectOptions = Class.forName("com.android.build.gradle.options.ProjectOptions") 48 | def constructor = classProjectOptions.getDeclaredConstructor(Project.class) 49 | constructor.setAccessible(true) 50 | def projectOptions = constructor.newInstance(project) 51 | return projectOptions 52 | } 53 | 54 | /** 55 | * 导出aapt2是否开启的兼容方法,build.gradle中apply后可直接使用isAapt2EnabledCompat() 56 | */ 57 | boolean isAapt2EnabledCompat() { 58 | boolean aapt2Enabled = false 59 | try { 60 | def projectOptions = getProjectOptions() 61 | Object enumValue = resolveEnumValue("ENABLE_AAPT2", Class.forName("com.android.build.gradle.options.BooleanOption")) 62 | aapt2Enabled = projectOptions.get(enumValue) 63 | } catch (Exception e) { 64 | try { 65 | //gradle 2.3.3的方法 66 | Class classAndroidGradleOptions = Class.forName("com.android.build.gradle.AndroidGradleOptions") 67 | def isAapt2Enabled = classAndroidGradleOptions.getDeclaredMethod("isAapt2Enabled", Project.class) 68 | isAapt2Enabled.setAccessible(true) 69 | aapt2Enabled = isAapt2Enabled.invoke(null, project) 70 | } catch (Exception e1) { 71 | //都取不到表示还不支持 72 | aapt2Enabled = false 73 | } 74 | } 75 | return aapt2Enabled 76 | } 77 | 78 | /** 79 | * 导出aapt2 jni 和 aapt2 daemon mode 是否被废弃 80 | */ 81 | @SuppressWarnings("GrMethodMayBeStatic") 82 | boolean isAapt2JniAndAapt2DaemonModeDeprecated() { 83 | try { 84 | def aapt2JniEnumValue = resolveEnumValue("ENABLE_IN_PROCESS_AAPT2", Class.forName("com.android.build.gradle.options.DeprecatedOptions")) 85 | def aapt2DaemonModeEnumValue = resolveEnumValue("ENABLE_DAEMON_MODE_AAPT2", Class.forName("com.android.build.gradle.options.DeprecatedOptions")) 86 | return aapt2JniEnumValue != null && aapt2DaemonModeEnumValue != null 87 | } catch (Exception e) { 88 | 89 | } 90 | return false 91 | } 92 | 93 | /** 94 | * 导出aapt2Jni是否开启的兼容方法,build.gradle中apply后可直接使用isAapt2JniEnabledCompat() 95 | */ 96 | boolean isAapt2JniEnabledCompat() { 97 | boolean aapt2JniEnabled = false 98 | if (isAapt2EnabledCompat()) { 99 | try { 100 | def projectOptions = getProjectOptions() 101 | def enumValue = resolveEnumValue("ENABLE_IN_PROCESS_AAPT2", Class.forName("com.android.build.gradle.options.BooleanOption")) 102 | aapt2JniEnabled = projectOptions.get(enumValue) 103 | if (isAapt2JniAndAapt2DaemonModeDeprecated()) { 104 | aapt2JniEnabled = false 105 | } 106 | } catch (Exception e) { 107 | aapt2JniEnabled = false 108 | } 109 | } 110 | return aapt2JniEnabled 111 | } 112 | 113 | /** 114 | * 导出aapt2DaemonMode是否开启的兼容方法,build.gradle中apply后可直接使用isAapt2DaemonModeEnabledCompat() 115 | */ 116 | boolean isAapt2DaemonModeEnabledCompat() { 117 | boolean aapt2DaemonEnabled = false 118 | if (isAapt2EnabledCompat()) { 119 | try { 120 | def projectOptions = getProjectOptions() 121 | def enumValue = resolveEnumValue("ENABLE_DAEMON_MODE_AAPT2", Class.forName("com.android.build.gradle.options.BooleanOption")) 122 | aapt2DaemonEnabled = projectOptions.get(enumValue) 123 | if (isAapt2JniAndAapt2DaemonModeDeprecated()) { 124 | aapt2DaemonEnabled = false 125 | } 126 | } catch (Exception e) { 127 | aapt2DaemonEnabled = false 128 | } 129 | } 130 | return aapt2DaemonEnabled 131 | } 132 | 133 | /** 134 | * 导出获得android gradle plugin插件的版本号,build.gradle中apply后可直接使用getAndroidGradlePluginVersionCompat() 135 | */ 136 | @SuppressWarnings("GrMethodMayBeStatic") 137 | String getAndroidGradlePluginVersionCompat() { 138 | String version = null 139 | try { 140 | Class versionModel = Class.forName("com.android.builder.model.Version") 141 | def versionFiled = versionModel.getDeclaredField("ANDROID_GRADLE_PLUGIN_VERSION") 142 | versionFiled.setAccessible(true) 143 | version = versionFiled.get(null) 144 | } catch (Exception e) { 145 | version = "unknown" 146 | } 147 | return version 148 | } 149 | 150 | /** 151 | * 导出是否在jenkins环境中,build.gradle中apply后可直接使用isJenkins() 152 | */ 153 | @SuppressWarnings("GrMethodMayBeStatic") 154 | boolean isJenkins() { 155 | Map environmentMap = System.getenv() 156 | boolean result = false 157 | if (environmentMap != null && environmentMap.containsKey("JOB_NAME") && environmentMap.containsKey("BUILD_NUMBER")) { 158 | result = true 159 | } 160 | return result 161 | } 162 | 163 | /** 164 | * 在application 插件中开启providedAar功能 165 | */ 166 | @SuppressWarnings("UnnecessaryQualifiedReference") 167 | void providedAarCompat() { 168 | if (!project.getPlugins().hasPlugin("com.android.application")) { 169 | return 170 | } 171 | if (project.getConfigurations().findByName("providedAar") != null) { 172 | return 173 | } 174 | Configuration providedConfiguration = project.getConfigurations().findByName("provided") 175 | Configuration compileOnlyConfiguration = project.getConfigurations().findByName("compileOnly") 176 | if (providedConfiguration == null && compileOnlyConfiguration == null) { 177 | return 178 | } 179 | Configuration providedAarConfiguration = project.getConfigurations().create("providedAar") 180 | String androidGradlePluginVersion = getAndroidGradlePluginVersionCompat() 181 | if (androidGradlePluginVersion.startsWith("1.3") || androidGradlePluginVersion.startsWith("1.5") || androidGradlePluginVersion.startsWith("2.") || androidGradlePluginVersion.startsWith("3.")) { 182 | //大于等于1.3.0的版本让provided继承providedAar,低于1.3.0的版本,手动提取aar中的jar添加依赖 183 | if (compileOnlyConfiguration != null) { 184 | compileOnlyConfiguration.extendsFrom(providedAarConfiguration) 185 | } else { 186 | providedConfiguration.extendsFrom(providedAarConfiguration) 187 | } 188 | } 189 | if (androidGradlePluginVersion.startsWith("0.") || androidGradlePluginVersion.startsWith("1.0") || androidGradlePluginVersion.startsWith("1.1") || androidGradlePluginVersion.startsWith("1.2")) { 190 | //不支持小于1.3.0的版本,不含1.3.0 191 | throw new GradleException("Not support version ${androidGradlePluginVersion}, android gradle plugin must >=1.3.0") 192 | } else { 193 | def android = project.getExtensions().getByName("android") 194 | android.applicationVariants.all { def variant -> 195 | if (androidGradlePluginVersion.startsWith("1.3") || androidGradlePluginVersion.startsWith("1.5") || androidGradlePluginVersion.startsWith("2.0") || androidGradlePluginVersion.startsWith("2.1") || androidGradlePluginVersion.startsWith("2.2") || androidGradlePluginVersion.startsWith("2.3") || androidGradlePluginVersion.startsWith("2.4")) { 196 | //支持1.3.0+ ~ 2.4.0+,且低于2.5.0,支持传递依赖 197 | def prepareDependenciesTask = project.tasks.findByName("prepare${variant.getName().capitalize()}Dependencies") 198 | if (prepareDependenciesTask) { 199 | def removeSyncIssues = { 200 | try { 201 | Class prepareDependenciesTaskClass = Class.forName("com.android.build.gradle.internal.tasks.PrepareDependenciesTask") 202 | Field checkersField = prepareDependenciesTaskClass.getDeclaredField('checkers') 203 | checkersField.setAccessible(true) 204 | def checkers = checkersField.get(prepareDependenciesTask) 205 | checkers.iterator().with { checkersIterator -> 206 | checkersIterator.each { dependencyChecker -> 207 | def syncIssues = dependencyChecker.syncIssues 208 | syncIssues.iterator().with { syncIssuesIterator -> 209 | syncIssuesIterator.each { syncIssue -> 210 | if (syncIssue.getType() == 7 && syncIssue.getSeverity() == 2) { 211 | project.logger.info "[providedAar] WARNING: providedAar has been enabled in com.android.application you can ignore ${syncIssue}" 212 | syncIssuesIterator.remove() 213 | } 214 | } 215 | } 216 | 217 | //兼容1.3.0~2.1.3版本,为了将provided的aar不参与打包,将isOptional设为true 218 | if (androidGradlePluginVersion.startsWith("1.3") || androidGradlePluginVersion.startsWith("1.5") || androidGradlePluginVersion.startsWith("2.0") || androidGradlePluginVersion.startsWith("2.1")) { 219 | def configurationDependencies = dependencyChecker.configurationDependencies 220 | List libraries = configurationDependencies.libraries 221 | libraries.each { library -> 222 | providedAarConfiguration.dependencies.each { providedDependency -> 223 | String libName = library.getName() 224 | if (libName.contains(providedDependency.group) && libName.contains(providedDependency.name) && libName.contains(providedDependency.version)) { 225 | Field isOptionalField = library.getClass().getDeclaredField("isOptional") 226 | Field modifiersField = Field.class.getDeclaredField("modifiers") 227 | modifiersField.setAccessible(true) 228 | modifiersField.setInt(isOptionalField, isOptionalField.getModifiers() & ~java.lang.reflect.Modifier.FINAL) 229 | isOptionalField.setAccessible(true) 230 | isOptionalField.setBoolean(library, true) 231 | //为了递归调用可以引用,先声明再赋值 232 | def fixDependencies = null 233 | fixDependencies = { dependencies -> 234 | dependencies.each { dependency -> 235 | if (dependency.getClass() == library.getClass()) { 236 | isOptionalField.setBoolean(dependency, true) 237 | fixDependencies(dependency.dependencies) 238 | } 239 | } 240 | } 241 | fixDependencies(library.dependencies) 242 | } 243 | } 244 | } 245 | } 246 | } 247 | } 248 | } catch (Exception e) { 249 | e.printStackTrace() 250 | } 251 | } 252 | if (androidGradlePluginVersion.startsWith("1.3") || androidGradlePluginVersion.startsWith("1.5") || androidGradlePluginVersion.startsWith("2.0") || androidGradlePluginVersion.startsWith("2.1")) { 253 | //这里不处理as sync的时候会出错 254 | def appPlugin = project.getPlugins().findPlugin("com.android.application") 255 | def taskManager = appPlugin.getMetaClass().getProperty(appPlugin, "taskManager") 256 | def dependencyManager = taskManager.getClass().getSuperclass().getMetaClass().getProperty(taskManager, "dependencyManager") 257 | def extraModelInfo = dependencyManager.getMetaClass().getProperty(dependencyManager, "extraModelInfo") 258 | Map syncIssues = extraModelInfo.getSyncIssues() 259 | syncIssues.iterator().with { syncIssuesIterator -> 260 | syncIssuesIterator.each { syncIssuePair -> 261 | if (syncIssuePair.getValue().getType() == 7 && syncIssuePair.getValue().getSeverity() == 2) { 262 | syncIssuesIterator.remove() 263 | } 264 | } 265 | } 266 | //下面同2.2.0+处理 267 | prepareDependenciesTask.configure removeSyncIssues 268 | } else if (androidGradlePluginVersion.startsWith("2.2") || androidGradlePluginVersion.startsWith("2.3")) { 269 | prepareDependenciesTask.configure removeSyncIssues 270 | } else if (androidGradlePluginVersion.startsWith("2.4")) { 271 | prepareDependenciesTask.doFirst removeSyncIssues 272 | } 273 | } 274 | } else if (androidGradlePluginVersion.startsWith("2.5") || androidGradlePluginVersion.startsWith("3.")) { 275 | //支持2.5.0+ ~ 3.2.0+,支持传递依赖 276 | def prepareBuildTask = project.tasks.findByName("pre${variant.getName().capitalize()}Build") 277 | if (prepareBuildTask) { 278 | boolean needRedirectAction = false 279 | prepareBuildTask.actions.iterator().with { actionsIterator -> 280 | actionsIterator.each { action -> 281 | if (action.getActionClassName().contains("AppPreBuildTask")) { 282 | actionsIterator.remove() 283 | needRedirectAction = true 284 | } 285 | } 286 | } 287 | if (needRedirectAction) { 288 | prepareBuildTask.doLast { 289 | def compileManifests = null 290 | def runtimeManifests = null 291 | Class appPreBuildTaskClass = Class.forName("com.android.build.gradle.internal.tasks.AppPreBuildTask") 292 | try { 293 | //3.0.0+ 294 | Field compileManifestsField = appPreBuildTaskClass.getDeclaredField("compileManifests") 295 | Field runtimeManifestsField = appPreBuildTaskClass.getDeclaredField("runtimeManifests") 296 | compileManifestsField.setAccessible(true) 297 | runtimeManifestsField.setAccessible(true) 298 | compileManifests = compileManifestsField.get(prepareBuildTask) 299 | runtimeManifests = runtimeManifestsField.get(prepareBuildTask) 300 | } catch (Exception e) { 301 | try { 302 | //2.5.0+ 303 | Field variantScopeField = appPreBuildTaskClass.getDeclaredField("variantScope") 304 | variantScopeField.setAccessible(true) 305 | def variantScope = variantScopeField.get(prepareBuildTask) 306 | //noinspection UnnecessaryQualifiedReference 307 | compileManifests = variantScope.getArtifactCollection(com.android.build.gradle.internal.publishing.AndroidArtifacts.ConsumedConfigType.COMPILE_CLASSPATH, com.android.build.gradle.internal.publishing.AndroidArtifacts.ArtifactScope.ALL, com.android.build.gradle.internal.publishing.AndroidArtifacts.ArtifactType.MANIFEST) 308 | runtimeManifests = variantScope.getArtifactCollection(com.android.build.gradle.internal.publishing.AndroidArtifacts.ConsumedConfigType.RUNTIME_CLASSPATH, com.android.build.gradle.internal.publishing.AndroidArtifacts.ArtifactScope.ALL, com.android.build.gradle.internal.publishing.AndroidArtifacts.ArtifactType.MANIFEST) 309 | } catch (Exception e1) { 310 | } 311 | } 312 | try { 313 | Set compileArtifacts = compileManifests.getArtifacts() 314 | Set runtimeArtifacts = runtimeManifests.getArtifacts() 315 | 316 | Map runtimeIds = new HashMap<>(runtimeArtifacts.size()) 317 | 318 | def handleArtifact = { id, consumer -> 319 | if (id instanceof ProjectComponentIdentifier) { 320 | consumer(((ProjectComponentIdentifier) id).getProjectPath().intern(), "") 321 | } else if (id instanceof ModuleComponentIdentifier) { 322 | ModuleComponentIdentifier moduleComponentId = (ModuleComponentIdentifier) id 323 | consumer( 324 | moduleComponentId.getGroup() + ":" + moduleComponentId.getModule(), 325 | moduleComponentId.getVersion()) 326 | } else { 327 | project.getLogger() 328 | .warn( 329 | "Unknown ComponentIdentifier type: " 330 | + id.getClass().getCanonicalName()) 331 | } 332 | } 333 | 334 | runtimeArtifacts.each { def artifact -> 335 | def runtimeId = artifact.getId().getComponentIdentifier() 336 | def putMap = { def key, def value -> 337 | runtimeIds.put(key, value) 338 | } 339 | handleArtifact(runtimeId, putMap) 340 | } 341 | 342 | compileArtifacts.each { def artifact -> 343 | final ComponentIdentifier compileId = artifact.getId().getComponentIdentifier() 344 | def checkCompile = { def key, def value -> 345 | String runtimeVersion = runtimeIds.get(key) 346 | if (runtimeVersion == null) { 347 | String display = compileId.getDisplayName() 348 | project.logger.info( 349 | "[providedAar] WARNING: providedAar has been enabled in com.android.application you can ignore 'Android dependency '" 350 | + display 351 | + "' is set to compileOnly/provided which is not supported'") 352 | } else if (!runtimeVersion.isEmpty()) { 353 | // compare versions. 354 | if (!runtimeVersion.equals(value)) { 355 | throw new RuntimeException( 356 | String.format( 357 | "Android dependency '%s' has different version for the compile (%s) and runtime (%s) classpath. You should manually set the same version via DependencyResolution", 358 | key, value, runtimeVersion)); 359 | } 360 | } 361 | } 362 | handleArtifact(compileId, checkCompile) 363 | } 364 | } catch (Exception e) { 365 | e.printStackTrace() 366 | } 367 | } 368 | } 369 | } 370 | } 371 | } 372 | } 373 | 374 | 375 | //redirect warning log to info log 376 | def listenerBackedLoggerContext = project.getLogger().getMetaClass().getProperty(project.getLogger(), "context") 377 | def originalOutputEventListener = listenerBackedLoggerContext.getOutputEventListener() 378 | def originalOutputEventLevel = listenerBackedLoggerContext.getLevel() 379 | listenerBackedLoggerContext.setOutputEventListener({ def outputEvent -> 380 | def logLevel = originalOutputEventLevel.name() 381 | if (!("QUIET".equalsIgnoreCase(logLevel) || "ERROR".equalsIgnoreCase(logLevel))) { 382 | if ("WARN".equalsIgnoreCase(outputEvent.getLogLevel().name())) { 383 | String message = outputEvent.getMessage() 384 | //Provided dependencies can only be jars. 385 | //provided dependencies can only be jars. 386 | if (message != null && (message.contains("Provided dependencies can only be jars.") || message.contains("provided dependencies can only be jars. "))) { 387 | project.logger.info(message) 388 | return 389 | } 390 | } 391 | } 392 | if (originalOutputEventListener != null) { 393 | originalOutputEventListener.onOutput(outputEvent) 394 | } 395 | }) 396 | } 397 | 398 | /** 399 | * R.java包名兼容获取 400 | */ 401 | String packageForRCompat(def processAndroidResourceTask) { 402 | if (processAndroidResourceTask == null) { 403 | return null 404 | } 405 | String packageForR = null 406 | try { 407 | packageForR = processAndroidResourceTask.getPackageForR() 408 | } catch (Exception e) { 409 | project.logger.info(e.getMessage()) 410 | } 411 | if (packageForR == null) { 412 | try { 413 | packageForR = processAndroidResourceTask.getOriginalApplicationId() 414 | } catch (Exception e) { 415 | project.logger.info(e.getMessage()) 416 | } 417 | } 418 | return packageForR 419 | } 420 | /** 421 | * R.java输出路径兼容获取 422 | */ 423 | File rFileDirCompat(def processAndroidResourceTask) { 424 | if (processAndroidResourceTask == null) { 425 | return null 426 | } 427 | File rFileDir = processAndroidResourceTask.getSourceOutputDir() 428 | GFileUtils.mkdirs(rFileDir) 429 | return rFileDir 430 | } 431 | 432 | /** 433 | * resources.ap_输出路径兼容获取 434 | */ 435 | File apFileCompat(def processAndroidResourceTask) { 436 | if (processAndroidResourceTask == null) { 437 | return null 438 | } 439 | File apFile = null 440 | try { 441 | apFile = processAndroidResourceTask.getPackageOutputFile() 442 | } catch (Exception e) { 443 | project.logger.info(e.getMessage()) 444 | } 445 | 446 | String variantName = null 447 | if (apFile == null) { 448 | try { 449 | variantName = processAndroidResourceTask.getMetaClass().getMetaProperty("variantName").getProperty(processAndroidResourceTask) 450 | File resPackageOutputFolder = processAndroidResourceTask.getResPackageOutputFolder() 451 | apFile = new File(resPackageOutputFolder, "resources" + "-" + variantName + ".ap_"); 452 | } catch (Exception e) { 453 | project.logger.info(e.getMessage()) 454 | } 455 | } 456 | 457 | if (apFile == null) { 458 | apFile = project.file("build${File.separator}intermediates${File.separator}res${File.separator}resources" + "-" + variantName + ".ap_") 459 | } 460 | return apFile 461 | } 462 | 463 | /** 464 | * 暴露给外界获取publish ap的函数 465 | */ 466 | File getPublishApFileCompat(String variantName) { 467 | if (variantName == null || variantName.length() == 0) { 468 | throw new GradleException("variantName 不能为空,且必须是驼峰形式") 469 | } 470 | def processAndroidResourceTask = project.tasks.findByName("process${variantName.capitalize()}Resources") 471 | File originalApFile = apFileCompat(processAndroidResourceTask) 472 | if (originalApFile == null) { 473 | String androidGradlePluginVersion = getAndroidGradlePluginVersionCompat() 474 | if (androidGradlePluginVersion.startsWith("0.") || androidGradlePluginVersion.startsWith("1.") || androidGradlePluginVersion.startsWith("2.")) { 475 | //驼峰转换为-分隔 476 | int length = variantName.length() 477 | StringBuilder sb = new StringBuilder(length) 478 | for (int i = 0; i < length; i++) { 479 | char c = variantName.charAt(i); 480 | if (Character.isUpperCase(c)) { 481 | sb.append("-") 482 | sb.append(Character.toLowerCase(c)) 483 | } else { 484 | sb.append(c) 485 | } 486 | } 487 | return project.file("build${File.separator}intermediates${File.separator}res${File.separator}resources-${sb}.ap_") 488 | } else { 489 | //驼峰转换为对应的目录和文件名 490 | int length = variantName.length() 491 | StringBuilder dirName = new StringBuilder(length) 492 | for (int i = 0; i < length; i++) { 493 | char c = variantName.charAt(i); 494 | if (Character.isUpperCase(c)) { 495 | dirName.append(File.separator) 496 | dirName.append(Character.toLowerCase(c)) 497 | } else { 498 | dirName.append(c) 499 | } 500 | } 501 | return project.file("build${File.separator}intermediates${File.separator}res${File.separator}${dirName}${File.separator}resources-${variantName}.ap_") 502 | } 503 | } 504 | return originalApFile 505 | } 506 | 507 | /** 508 | * 暴露给外界获取R.java除去包名路径的函数,必须在project.afterEvaluate中调用,否则获取到的是null 509 | */ 510 | File getRDirCompat(String variantName) { 511 | if (variantName == null || variantName.length() == 0) { 512 | throw new GradleException("variantName 不能为空,且必须是驼峰形式") 513 | } 514 | def processAndroidResourceTask = project.tasks.findByName("process${variantName.capitalize()}Resources") 515 | File rDir = rFileDirCompat(processAndroidResourceTask) 516 | if (rDir == null) { 517 | int length = variantName.length() 518 | StringBuilder dirName = new StringBuilder(length) 519 | for (int i = 0; i < length; i++) { 520 | char c = variantName.charAt(i); 521 | if (Character.isUpperCase(c)) { 522 | dirName.append(File.separator) 523 | dirName.append(Character.toLowerCase(c)) 524 | } else { 525 | dirName.append(c) 526 | } 527 | } 528 | return project.file("build${File.separator}generated${File.separator}source${File.separator}r${File.separator}${dirName}") 529 | } 530 | return rDir 531 | } 532 | 533 | /** 534 | * 暴露给外界获取R.java路径的函数,必须在project.afterEvaluate中调用,否则获取到的是null 535 | */ 536 | File getRFileCompat(String variantName) { 537 | if (variantName == null || variantName.length() == 0) { 538 | throw new GradleException("variantName 不能为空,且必须是驼峰形式") 539 | } 540 | File rDir = getRDirCompat(variantName) 541 | String packageForR = getPackageForRCompatCompat(variantName) 542 | return new File(new File(rDir, packageForR.replaceAll("\\.", File.separator)), "R.java") 543 | } 544 | 545 | /** 546 | * 暴露给外界获取R.java包名的函数,必须在project.afterEvaluate中调用,否则获取到的是null 547 | */ 548 | String getPackageForRCompatCompat(String variantName) { 549 | if (variantName == null || variantName.length() == 0) { 550 | throw new GradleException("variantName 不能为空,且必须是驼峰形式") 551 | } 552 | def processAndroidResourceTask = project.tasks.findByName("process${variantName.capitalize()}Resources") 553 | String packageForR = packageForRCompat(processAndroidResourceTask) 554 | if (packageForR == null) { 555 | return project.android.defaultConfig.applicationId 556 | } 557 | return packageForR 558 | } 559 | 560 | } 561 | -------------------------------------------------------------------------------- /buildSrc/src/main/resources/META-INF/gradle-plugins/com.android.compat.properties: -------------------------------------------------------------------------------- 1 | implementation-class=io.github.lizhangqu.plugin.compat.CompatPlugin -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | 19 | 20 | #android.enableAapt2=true 21 | #android.enableAapt2jni=false 22 | #android.enableAapt2DaemonMode=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lizhangqu/AndroidGradlePluginCompat/d1e974aa0fadc4c6a211a5421427d465491e78e2/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Oct 31 20:49:58 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env 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 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':buildSrc' 2 | include ':app' 3 | --------------------------------------------------------------------------------