app
apply plugin: 'com.android.application'
apply plugin: 'findbugs'
static def releaseTime() {
return new Date().format("yyMMdd-HHmm")
}
android {
compileSdkVersion 26
buildToolsVersion '26.0.2'
defaultConfig {
applicationId "com.guangyouqian.app"
minSdkVersion 15
targetSdkVersion 26
versionCode 1000100
versionName "1.0.1"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
manifestPlaceholders = [channel:"weiliu"]
}
signingConfigs {
release {
storeFile file("keystore.jks")
storePassword "xxxxxxxxxxxx"
keyAlias "xxxx"
keyPassword "xxxxxxxxxxx"
}
}
buildTypes {
release {
buildConfigField "boolean", "DEV", "false"
buildConfigField "String", "API_HOST", "\"https://api.gyq.v6h5.com/\""
signingConfig signingConfigs.release
minifyEnabled true
shrinkResources true
zipAlignEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
http {
matchingFallbacks = ['debug', 'release']
buildConfigField "boolean", "DEV", "true"
debuggable true
signingConfig signingConfigs.release
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
buildConfigField "boolean", "DEV", "true"
debuggable true
signingConfig signingConfigs.release
minifyEnabled false
shrinkResources false
}
}
lintOptions {
abortOnError false
lintConfig file('lint.xml')
}
externalNativeBuild {
ndkBuild {
path 'src/main/jni/Android.mk'
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile project(':library')
testCompile 'junit:junit:4.12'
}
static def getAppName() {
return "czsp"
}
static def originReleaseApk() {
return getAppName() + "-release.apk"
}
static def andResGuardApk() {
return "AndResGuard_app-release/app-release_aligned_signed.apk"
}
def timeReleaseApkName() {
String appVersion = project.android.defaultConfig.versionName
return String.format(getAppName() + "-%s-%s", appVersion, releaseTime())
}
afterEvaluate {
task dailyBuild(dependsOn: 'assemble', type: FindBugs) {
ignoreFailures = true
reportLevel = "medium"
classes = files("$project.buildDir/intermediates/classes")
excludeFilter = file("findbugs_exclude.xml")
source = fileTree(dir: '../', include: '*/src/main/**/*.java')
classpath = files()
reports {
xml.enabled = true
xml.withMessages = true
html.enabled = !xml.isEnabled()
xml.destination "$project.buildDir/outputs/findbugs/findbugs-output.xml"
html.destination "$project.buildDir/outputs/findbugs/findbugs-output.html"
}
}
task channelBuild {
String dir = "../repack/" + project.android.defaultConfig.versionName
String path = dir + "/" + getAppName() + ".apk";
println "-apkPath = " + file(path).getAbsolutePath()
boolean apkRebuild = project.hasProperty("apkRebuild") ? project.property("apkRebuild").toBoolean() : false
println "-apkRebuild = " + apkRebuild
boolean shouldRebuild = apkRebuild || !file(path).exists()
println "shouldRebuild = " + shouldRebuild
if (shouldRebuild) {
dependsOn 'assembleRelease'
}
doFirst {
println "doFirst shouldRebuild = " + shouldRebuild
println "doFirst path = " + path
if (shouldRebuild) {
if (file(path).exists()) {
if (!file(path).delete()) {
println "delete " + path + " failed"
throw new RuntimeException("delete " + path + " failed")
}
} else {
file(path).getParentFile().mkdirs()
}
if (file("$project.buildDir/outputs/apk/release/" + originReleaseApk()).renameTo(file(path))) {
println "renameTo " + path + " success"
} else {
println "renameTo " + path + "failed"
throw new RuntimeException("renameTo " + path + " failed")
}
}
}
doLast {
def localProperties = new File(rootDir, "local.properties")
Properties properties = new Properties()
localProperties.withInputStream { instr ->
properties.load(instr)
}
def sdkDir = properties.getProperty('sdk.dir')
String apktool = "apktool-cli.jar"
String apktoolDecodeDir = dir + "/apktool_decode"
if (shouldRebuild || !file(apktoolDecodeDir).exists()) {
if (!file(apktoolDecodeDir).exists()) {
if (!file(apktoolDecodeDir).mkdir()) {
println "mkdir " + apktoolDecodeDir + " failed"
throw new RuntimeException("mkdir " + apktoolDecodeDir + " failed")
}
}
println "apktool decode to " + apktoolDecodeDir + " starting......"
exec {
executable "java"
args "-jar", apktool, "d", "-f", "-r", "-s", "-o", apktoolDecodeDir, path
}
println "apktool decode to " + apktoolDecodeDir + " end"
}
if (!project.hasProperty("channels")) {
println "no channels1"
throw new StopExecutionException()
}
String[] channels = project.property("channels").split(",")
if (channels == null || channels.length == 0) {
println "no channels2"
throw new StopExecutionException()
}
String buildNo = project.hasProperty("buildNo") ? project.property("buildNo") : "undefined"
String buildNoDir = dir + "/" + buildNo
if (!file(buildNoDir).exists()) {
if (!file(buildNoDir).mkdir()) {
println "mkdir " + buildNoDir + " failed"
throw new RuntimeException("mkdir " + buildNoDir + " failed")
}
}
String finalName = timeReleaseApkName()
String apktoolBuildTempPath = dir + "/" + finalName + "_unsigned.apk"
String signTempPath = dir + "/" + finalName + "_unaligned.apk"
String[] paths = [apktoolBuildTempPath, signTempPath]
for (String filePath : paths) {
if (file(filePath).exists() && !file(filePath).delete()) {
println "delete " + filePath + " failed"
throw new RuntimeException("delete " + filePath + " failed")
}
}
for (String channel : channels) {
String finalApkPath = buildNoDir + "/" + finalName + "_" + channel + ".apk"
String channelFilePath = apktoolDecodeDir + "/assets/channel.ini"
println channel + " write to " + channelFilePath + " starting..."
file(channelFilePath).write channel
println apktoolBuildTempPath + " apktool build starting..."
exec {
executable "java"
args "-jar", apktool, "b", "-f", "-o", apktoolBuildTempPath, apktoolDecodeDir
}
println signTempPath + " jarsigner sign starting..."
exec {
executable "jarsigner"
args "-keystore", project.android.signingConfigs.release.storeFile,
"-storepass", project.android.signingConfigs.release.storePassword,
"-keypass", project.android.signingConfigs.release.keyPassword,
"-digestalg", "SHA1",
"-sigalg", "MD5withRSA",
"-signedjar", signTempPath,
apktoolBuildTempPath,
project.android.signingConfigs.release.keyAlias
}
println finalApkPath + " zipalign align starting..."
exec {
executable sdkDir + "/build-tools/26.0.2/zipalign"
args "-f", "4", signTempPath, finalApkPath
}
}
}
}
}
/**
* 通过过滤黑名单,从而得到白名单列表
* @param resNameArr 资源名<数组>
* @param blacklist 黑名单<名字开头>
* @return 返回白名单列表
*/
static Iterable disposeBlacklist(String[] resNameArr, String blacklist) {
Iterable arr = new ArrayList<>()
StringBuffer sb = new StringBuffer()
for (int j = 0; j < resNameArr.length; j++) {
for (int i = 0; i < blacklist.length(); i++) {
sb.setLength(0)
sb.append(blacklist.substring(0, i + 1))
sb.insert(i, "[^")
sb.insert(i + 3, "]")
arr.add("R." + resNameArr[j] + "." + sb.toString() + "*")
}
}
return arr
}
andResGuard {
mappingFile = null
use7zip = true
useSign = true
keepRoot = true
String[] resName = [
"anim",
"animator",
"color",
"drawable",
"layout",
"menu",
"mipmap",
"string",
"style",
"item",
"dimen",
"string-array",
"xml",
"id",
"raw"
]
whiteList = disposeBlacklist(resName, "gyq_")
compressFilePattern = [
"*.png",
"*.jpg",
"*.jpeg",
"*.gif",
"resources.arsc"
]
sevenzip {
artifact = 'com.tencent.mm:SevenZip:1.2.8'
}
/**
* 可选: 如果不设置则会默认覆盖assemble输出的apk
**/
/**
* 可选: 指定v1签名时生成jar文件的摘要算法
* 默认值为“SHA1”
**/
digestalg = "SHA1"
}
project
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.2.8' //mm:AndResGuard
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
maven {
url "http://repo.baichuan-android.taobao.com/content/groups/BaichuanRepositories/"
}
google()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}