mirror of
https://github.com/RxReader/walle_kit.git
synced 2025-05-17 07:16:33 +08:00
移除 cli
This commit is contained in:
11
README.md
11
README.md
@ -44,9 +44,11 @@ zipalign -p -f -v 4 input.apk output.apk
|
||||
|
||||
```groovy
|
||||
// android/app/build.gradle
|
||||
apply from: "${project(":walle_kit").projectDir}/walle_kit_v2.gradle" // 推荐(非cli方式,不支持360加固)
|
||||
apply from: "${project(":walle_kit").projectDir}/walle_kit_v3.gradle" // 推荐(非cli方式,不支持360加固、不支持腾讯乐固)
|
||||
// 或
|
||||
apply from: "${project(":walle_kit").projectDir}/walle_kit.gradle" // 不推荐(cli方式,支持360加固)
|
||||
apply from: "${project(":walle_kit").projectDir}/walle_kit_v2.gradle" // 推荐(非cli方式,不支持360加固、支持腾讯乐固)
|
||||
// 或
|
||||
apply from: "${project(":walle_kit").projectDir}/walle_kit.gradle" // 不推荐(cli方式,支持360加固、支持腾讯乐固)
|
||||
```
|
||||
|
||||
* fileNameFormat
|
||||
@ -66,6 +68,11 @@ apply from: "${project(":walle_kit").projectDir}/walle_kit.gradle" // 不推荐
|
||||
* [配置文件示例 - channel](example/android/app/channel)
|
||||
* [配置文件示例 - channel.json](example/android/app/channel.json)
|
||||
|
||||
### walle_kit_v3.gradle
|
||||
|
||||
> 应用宝上架,已不再强制要求加固
|
||||
> 用法同 walle_kit_v2.gradle 一致,不同的是已不再支持腾讯乐固功能
|
||||
|
||||
### walle_kit_v2.gradle
|
||||
|
||||
* without flavors
|
||||
|
237
android/walle_kit_v3.gradle
Normal file
237
android/walle_kit_v3.gradle
Normal file
@ -0,0 +1,237 @@
|
||||
//
|
||||
//使用方法
|
||||
//
|
||||
//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:默认;1:json
|
||||
// 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)
|
||||
}
|
||||
}
|
@ -25,7 +25,7 @@ apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||
// walle
|
||||
apply from: "${project(":walle_kit").projectDir}/walle_kit_v2.gradle"
|
||||
apply from: "${project(":walle_kit").projectDir}/walle_kit_v3.gradle"
|
||||
|
||||
android {
|
||||
compileSdkVersion flutter.compileSdkVersion
|
||||
@ -59,15 +59,6 @@ android {
|
||||
release {
|
||||
enabled = true
|
||||
|
||||
// // [访问管理](https://console.cloud.tencent.com/cam/capi)
|
||||
// // [移动应用安全](https://console.cloud.tencent.com/ms/reinforce/list)
|
||||
// tencent {
|
||||
// secretId = 'xxx'
|
||||
// secretKey = 'xxx'
|
||||
//// region = 'ap-guangzhou' // 可选:'ap-guangzhou'、'ap-shanghai',默认:'ap-guangzhou'
|
||||
// channels = ['tencent', 'tencent-alias']
|
||||
// }
|
||||
|
||||
outputDir = file("${project.buildDir}/outputs/apk/walle") // 默认:file("${project.buildDir}/outputs/apk/${flavorName}/${buildType}/walle")
|
||||
fileNameFormat = '${appName}-${buildType}-${channelId}.apk' // 默认:'${appName}-${buildType}-${channelId}.apk'
|
||||
// channelType = 0 // 0:默认;1:json
|
||||
|
@ -13,6 +13,8 @@ tencent
|
||||
aliyun
|
||||
# 华为
|
||||
huawei
|
||||
# 荣耀
|
||||
honor
|
||||
# Oppo
|
||||
oppo
|
||||
# Vivo
|
||||
|
@ -36,6 +36,11 @@
|
||||
"channelId": "huawei",
|
||||
"storeDir": "market"
|
||||
},
|
||||
{
|
||||
"alias": "荣耀",
|
||||
"channelId": "honor",
|
||||
"storeDir": "market"
|
||||
},
|
||||
{
|
||||
"alias": "Oppo",
|
||||
"channelId": "oppo",
|
||||
|
@ -7,7 +7,7 @@ packages:
|
||||
name: async
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "2.8.2"
|
||||
version: "2.9.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -21,21 +21,14 @@ packages:
|
||||
name: characters
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: charcode
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
version: "1.2.1"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: clock
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.1.1"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -56,7 +49,7 @@ packages:
|
||||
name: fake_async
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.3.1"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@ -94,28 +87,28 @@ packages:
|
||||
name: matcher
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.12.11"
|
||||
version: "0.12.12"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.1.4"
|
||||
version: "0.1.5"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.7.0"
|
||||
version: "1.8.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.8.1"
|
||||
version: "1.8.2"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -134,7 +127,7 @@ packages:
|
||||
name: source_span
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.8.2"
|
||||
version: "1.9.0"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -155,21 +148,21 @@ packages:
|
||||
name: string_scanner
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
version: "1.1.1"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.2.1"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
url: "https://pub.flutter-io.cn"
|
||||
source: hosted
|
||||
version: "0.4.9"
|
||||
version: "0.4.12"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
Reference in New Issue
Block a user