Files
walle_kit/android/walle_kit_v3.gradle
2022-11-11 11:55:57 +08:00

238 lines
8.4 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
//使用方法
//
//apply from: 'walle.gradle'
//
//android {
// productFlavors {
// prod {...}
// }
//
// walleConfigs {
// prod {
// enabled = true
//
// outputDir = file("${project.buildDir}/outputs/apk/${flavorName}/${buildType}/walle") // 默认file("${project.buildDir}/outputs/apk/${flavorName}/${buildType}/walle")
// fileNameFormat = '${appName}-${buildType}-${channelId}.apk' // 默认:'${appName}-${buildType}-${channelId}.apk'
//// channelType = 0 // 0默认1json
// channelFile = file('channel')
// }
// }
//}
//
//walle {
// enabled = false
//}
//
buildscript {
repositories {
google()
mavenCentral()
// 阿里云jcenter镜像
maven { url 'https://maven.aliyun.com/repository/jcenter' }
}
dependencies {
classpath 'com.android.tools.build:gradle:7.1.2'
classpath 'com.meituan.android.walle:payload_writer:1.1.7'
}
}
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
class Walle {
final String name
Boolean enabled
File outputDir
String fileNameFormat
Integer channelType
File channelFile
Walle(String name = 'default') {
this.name = name
}
// ---
void validate() {
if (enabled == null || !enabled.booleanValue()) {
return
}
if (channelType != null && channelType != 0 && channelType != 1) {
throw new RuntimeException("walle channel type is unsupported for variant '$name'")
}
if (channelFile == null) {
throw new RuntimeException("walle channel file is null for variant '$name'")
}
}
Walle mergeWith(Walle other) {
if (other == null) {
return this
}
def mergeWalle = new Walle(name == 'default' ? other.name : (other.name == 'default' ? name : "$name${other.name.capitalize()}"))
mergeWalle.enabled = other.enabled != null ? other.enabled : enabled
mergeWalle.outputDir = other.outputDir ?: outputDir
mergeWalle.fileNameFormat = other.fileNameFormat ?: fileNameFormat
mergeWalle.channelType = other.channelType ?: channelType
mergeWalle.channelFile = other.channelFile ?: channelFile
return mergeWalle
}
}
apply plugin: WallePlugin
class WallePlugin implements Plugin<Project> {
@Override
void apply(Project target) {
target.extensions.create('walle', Walle.class)
target.plugins.withId('com.android.application') {
def baseWalle = target.walle
def walleConfigs = target.container(Walle.class)
target.android.extensions.walleConfigs = walleConfigs
target.android.applicationVariants.whenObjectAdded { variant ->
def mergeWalle = null
List<Walle> flavorWalles = variant.productFlavors?.stream()?.map{flavor -> walleConfigs.findByName(flavor.name)}?.collect()?.toList() ?: Collections.emptyList()
def buildTypeWalle = walleConfigs.findByName(variant.buildType.name)
if (buildTypeWalle == null && (variant.buildType.name == 'debug' || variant.buildType.name == 'profile')) {
buildTypeWalle = new Walle(variant.buildType.name)
buildTypeWalle.enabled = false
}
// buildType > flavor > base
List<Walle> walles = []
walles.add(baseWalle)
walles.addAll(flavorWalles)
walles.add(buildTypeWalle)
for (def walle in walles) {
if (mergeWalle == null) {
mergeWalle = walle
} else {
mergeWalle = mergeWalle.mergeWith(walle)
}
}
mergeWalle?.validate()
variant.assemble.doLast {
walleWork(target, variant, mergeWalle)
}
}
}
target.afterEvaluate {
if (!target.plugins.hasPlugin('com.android.application')) {
target.logger.warn("The Android Gradle Plugin was not applied. Gradle Walle will not be configured.")
}
}
}
void walleWork(Project target, def variant, Walle walle) {
if (walle == null || walle.enabled == null || !walle.enabled.booleanValue()) {
target.logger.info("Gradle Walle is disabled for variant '${variant.name}'.")
return
}
if (!variant.signingReady && !variant.outputsAreSigned) {
target.logger.error("Signing not ready for Gradle Walle. Be sure to specify a signingConfig for variant '${variant.name}'.")
return
}
println '--- walle ---'
def apkFile = variant.outputs.first().outputFile as File
println "apk file: ${apkFile.path}"
def v2SigningEnabled = v2SigningEnabled(variant)
println "v2SigningEnabled: ${v2SigningEnabled}"
if (!v2SigningEnabled) {
throw new RuntimeException("${apkFile.path} has no v2 signature in Apk Signing Block!")
}
// 预备输出目录
def outputDir = walle.outputDir
if (outputDir == null) {
outputDir = new File(apkFile.parentFile, 'walle')
}
def channelsDir = new File(outputDir, 'channels')
if (!channelsDir.exists()) {
channelsDir.mkdirs()
}
def nameVariantMap = [
'appName' : target.name,
'projectName': target.rootProject.name,
'buildType' : variant.buildType.name,
'versionName': variant.versionName,
'versionCode': variant.versionCode,
'packageName': variant.applicationId,
'flavorName' : variant.flavorName,
'channelId': 'channel'
]
def fileNameFormat = walle.fileNameFormat ?: '${appName}-${buildType}-${channelId}.apk'
def targetApkFile = new File(outputDir, new groovy.text.SimpleTemplateEngine().createTemplate(fileNameFormat).make(nameVariantMap).toString())// new File(outputDir, apkFile.name)
// 复制
java.nio.file.Files.copy(apkFile.toPath(), targetApkFile.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING)
println "target apk file: ${targetApkFile.path}"
// 读取渠道信息
def channels = []
if (walle.channelType == 1) {
def slurper = new groovy.json.JsonSlurper()
channels = slurper.parse(walle.channelFile)
} else {
walle.channelFile.eachLine { line ->
def lineTrim = line.trim()
if (lineTrim.length() != 0 && !lineTrim.startsWith("#")) {
def channelId = line.split("#").first().trim()
if (channelId.length() != 0) {
channels.add(['alias': channelId, 'channelId': channelId])
}
}
}
}
channels.each { channel ->
nameVariantMap['channelId'] = channel.channelId
def storeDir = channelsDir
if (channel.storeDir != null) {
storeDir = new File(storeDir, channel.storeDir)
if (!storeDir.exists()) {
storeDir.mkdirs()
}
}
def channelApkFile = new File(storeDir, new groovy.text.SimpleTemplateEngine().createTemplate(fileNameFormat).make(nameVariantMap).toString())
def originalApkFile = targetApkFile
if (originalApkFile != targetApkFile) {
println "${channel.alias ?: channel.channelId} original apk file: ${originalApkFile.path}"
}
println "${channel.alias ?: channel.channelId} channel apk file: ${channelApkFile.path}"
writePayload(target, channel, originalApkFile, channelApkFile)
}
println '--- walle ---'
}
boolean v2SigningEnabled(variant) {
def signingConfig = variant.signingConfig
return signingConfig.v2SigningEnabled
}
void writePayload(Project target, def channel, File apkFile, File channelApkFile) {
java.nio.file.Files.copy(apkFile.toPath(), channelApkFile.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING)
com.meituan.android.walle.ChannelWriter.put(channelApkFile, channel.channelId, channel.extraInfo)
}
}