Giter Club home page Giter Club logo

vasdolly's Introduction

license Release Version PRs Welcome wiki

简介

VasDolly是一种快速多渠道打包工具,同时支持基于V1签名和V2,V3签名进行多渠道打包。插件本身会自动检测Apk使用的签名类别,并选择合适的多渠道打包方式,对使用者来说完全透明。

目前Gradle Plugin 2.2以上默认开启V2签名,所以如果想关闭V2签名,可将下面的v2SigningEnabled设置为false。 关于应用签名说明:见官方文档

signingConfigs {
        release {
            ...
            v1SigningEnabled true
            v2SigningEnabled false
        }

        debug {
            ...
            v1SigningEnabled true
            v2SigningEnabled false
        }
    }

接入流程

添加对VasDolly Plugin的依赖

在根工程的build.gradle中,添加对打包Plugin的依赖:

dependencies {
        classpath 'com.android.tools.build:gradle:7.0.3'
        classpath 'com.tencent.vasdolly:plugin:3.0.6'
}

引用VasDolly Plugin

在主App工程的build.gradle中,添加对VasDolly Plugin的引用:

apply plugin: 'com.tencent.vasdolly'

添加对VasDolly helper类库的依赖

在主App工程的build.gradle中,添加读取渠道信息的helper类库依赖:

dependencies {
    api 'com.tencent.vasdolly:helper:3.0.6'
}

配置渠道列表

目前有两种方式配置渠道列表,最终的渠道列表是两者的累加之和:

  1. gradle.properties文件指定渠道文件名称,该渠道文件必须位于根工程目录下,一行一个渠道信息。
channel_file=channel.txt
  1. channel或者rebuildChannel属性中通过channelFile属性指定渠道文件,一行一个渠道信息。
channel{
    //指定渠道文件
    channelFile = file("/Users/leon/Downloads/testChannel.txt")
}
rebuildChannel{
    //指定渠道文件
    channelFile = file("/Users/leon/Downloads/testReChannel.txt")
}

通过Gradle生成多渠道包

直接编译生成多渠道包

若是直接编译生成多渠道包,首先要配置渠道文件、渠道包的输出目录和渠道包的命名规则:

channel{
    //指定渠道文件
    channelFile = file("/Users/leon/Downloads/testChannel.txt")
     //多渠道包的输出目录,默认为new File(project.buildDir,"channel")
    outputDir = new File(project.buildDir,"xxx")
    //多渠道包的命名规则,默认为:${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}-${buildTime}
    apkNameFormat ='${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}'
    //快速模式:生成渠道包时不进行校验(速度可以提升10倍以上,默认为false)
    fastMode = false
    //buildTime的时间格式,默认格式:yyyyMMdd-HHmmss
    buildTimeDateFormat = 'yyyyMMdd-HH:mm:ss'
    //低内存模式(仅针对V2签名,默认为false):只把签名块、**目录和EOCD读取到内存,不把最大头的内容块读取到内存,在手机上合成APK时,可以使用该模式
    lowMemory = false
}

其中,多渠道包的命名规则中,可使用以下字段:

  • appName : 当前project的name
  • versionName : 当前Variant的versionName
  • versionCode : 当前Variant的versionCode
  • buildType : 当前Variant的buildType,即debug or release
  • flavorName : 当前的渠道名称
  • appId : 当前Variant的applicationId
  • buildTime : 当前编译构建日期时间,时间格式可以自定义,默认格式:yyyyMMdd-HHmmss

然后,通过gradle channelDebuggradle channelRelease命令分别生成Debug和Release的多渠道包。

为了方便临时生成渠道包进行测试,我们从v2.0.0开始支持添加渠道参数:gradle channelDebug(channelRelease) -Pchannels=yingyongbao,gamecenter,这里通过属性channels指定的渠道列表拥有更高的优先级,且和原始的文件方式是互斥的。

根据已有基础包重新生成多渠道包

若是根据已有基础包重新生成多渠道包,首先要配置渠道文件、基础包的路径和渠道包的输出目录:

rebuildChannel {
  //指定渠道文件
  channelFile = file("/Users/leon/Downloads/testReChannel.txt")
  // 已有APK文件地址(必填),如new File(project.rootDir, "/baseApk/app_base.apk"),文件名中的base将被替换为渠道名
  baseApk = 已有APK文件地址(必填)
  //默认为new File(project.buildDir, "rebuildChannel")
  outputDir = 渠道包输出目录
  //快速模式:生成渠道包时不进行校验(速度可以提升10倍以上,默认为false)
  fastMode = false
  //低内存模式(仅针对V2签名,默认为false):只把签名块、**目录和EOCD读取到内存,不把最大头的内容块读取到内存,在手机上合成APK时,可以使用该模式
  lowMemory = false
}

然后,通过gradle rebuildChannel命令生成多渠道包。

为了方便临时生成渠道包进行测试,我们从v2.0.0开始支持添加渠道参数:gradle rebuildChannel -Pchannels=yingyongbao,gamecenter,这里通过属性channels指定的渠道列表拥有更高的优先级,且和原始的文件方式是互斥的。

通过命令行生成渠道包、读取渠道信息

V1.0.5版本开始支持命令行,具体使用文档可参考command目录下的README

读取渠道信息

通过helper类库中的ChannelReaderUtil类读取渠道信息。

String channel = ChannelReaderUtil.getChannel(getApplicationContext());

如果没有渠道信息,那么这里返回null,开发者需要自己判断。

Demo参考

详细的接入范式,可参考Demo

实现原理

具体原理可参考VasDolly实现原理

问题反馈

遇到任何问题或者有好的建议,欢迎提issues

TODO

  1. 增加单元测试
  2. 防渠道信息篡改
  3. 提供Python脚本

License

VasDolly is under the BSD license. See the LICENSE file for details.

vasdolly's People

Contributors

chengongguo avatar jigongdajiang avatar kassadin avatar liujingxing avatar ltlovezh avatar vincgao avatar xingstarx avatar yanyongshan avatar zysidea avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vasdolly's Issues

wiki

"6C 74 6C 6F 76 75 7A 68是魔数,04 00表示渠道信息长度为4,6C 65 6F 6E就是渠道信息leon了。0E 00就是APK注释长度了,正好是15。"

正好E,14吧

使用VasDolly生成的渠道包的渠道名是什么?

现在有个需求就是我用VasDolly生成的release版本提交给运营人员
但是运营人员随时还需要根据自己运营的需求对release包重新做一些临时的渠道包
目前他们用的360加固助手提供的渠道打包服务
但是多渠道配置的 统计平台并没有VasDolly的选项,就算选了InstallChannel 也没用,渠道打包出来的应用包还是没有渠道的
所以问题就是,渠道名应该填什么?
image

关于多渠道加固

以前用的Umeng多渠道,一般打包一个包并且签名,在乐固里配置签名,配置多渠道, 比较简单(只需打包 签名 加固一个包)

那么用这个的话打包出很多渠道再挨个去加固吗

channel.txt和productFlavors 冲突

比如channel.txt种有xiaomi,qihu,baidu三个渠道,productFlavors 也有这三个渠道,这种情况下如果执行Gradle命令channelxiaomiDebug只打包xiaomi渠道的,还是会生成xiaomi,qihu,baidu三个渠道包,并且这个三个渠道包在xiaomi的文件夹下。

有个无关紧要的问题,

rebuildChannel {        //多渠道打包task
        //    baseDebugApk = 已有Debug APK
        baseReleaseApk = new File(project.buildDir, "base-release.apk")
        println baseReleaseApk

        //默认为new File(project.buildDir, "rebuildChannel/release")
        releaseOutputDir = new File(project.buildDir, "release")//Release渠道包输出目录
    }

如果 baseApk 没有放在正确的目录,也就是找不到的情况下,gradle仍然提示任务完成

2017/9/6
14:53	Executing tasks: [reBuildChannel]

14:53	Gradle build finished in 1s 981ms

当时我就很奇怪为什么一直找不到完成后的输出,后来看了才发现是把baseApk放到了上一级目录,改回去就好了

安装包损坏

WIN7下面打出来的渠道包安装到手机上,应用宝提示安装包损坏,另外打出来的渠道包都不能删除,提示被其他程序占用,mac下面使用这个渠道打包工具没问题

与AndResGuard的兼容问题

使用AndResGuard进行资源混淆后将资源混淆后生成的apk包再打多渠道包会报
not have precise channel package mode 错误。

如果有加固的需求的话,该怎么使用呢

看了你的文章介绍,如果有加固需求的话,这种改怎么弄了。

我们的场景如下,首先打出一个未签名的apk,然后使用梆梆加固,加固后添加渠道列表,得到10多个渠道包,然后再签名。这种场景下。怎么使用tinker的热修复呢。也就是我加固后的渠道包,他们的crc应该都不一样了吧。

请问本地仓库问题

你好,我想对插件做点修改,在本地测试,一直没有变化,需要修改哪个几地方?

如何生成基础包

1.是否通过grade assembleRelease命令生成基础包?
2.是否可以配置为grade channelRelease同时也生成一个基础包出来?以备还可以用命令行打一些不在channels.txt里的渠道

谢谢

报错SigningConfig is null , please check it

  • What went wrong:
    Execution failed for task ':app:channelRelease'.

SigningConfig is null , please check it
apply plugin: 'com.android.application'
apply plugin: 'channel'
android {
compileSdkVersion 27
defaultConfig {
applicationId "com.marsjiang.myapplicationtest"
minSdkVersion 15
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
signingConfigs {
release {
storeFile file("")
storePassword ""
keyAlias ""
keyPassword ""
v1SigningEnabled true
v2SigningEnabled false
}
debug {
storeFile file("")
storePassword ""
keyAlias ""
keyPassword ""
v1SigningEnabled true
v2SigningEnabled false
}
}

buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}
channel{
    //指定渠道文件
    channelFile = file("../channel.txt")
    //多渠道包的输出目录,默认为new File(project.buildDir,"channel")
    baseOutputDir = new File(project.buildDir,"channel")
    //多渠道包的命名规则,默认为:${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}
    apkNameFormat ='${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}'
    //快速模式:生成渠道包时不进行校验(速度可以提升10倍以上)
    isFastMode = true
}
rebuildChannel {
    baseDebugApk = new File(project.projectDir, "baseApk/v1-base-debug.apk")
    baseReleaseApk = new File(project.projectDir, "baseApk/v2-base-debug.apk")
    //isFastMode = true
}

}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'

api 'com.leon.channel:helper:1.1.7'

}

./gradlew reBuildChannel 执行不生效

根据#2 的提示,我创建了个demo,测试梆梆加固后的apk,用ApkChannelPackage生成渠道包

目前提示如下的结果

Executing task ':app:reBuildChannel' (up-to-date check took 0.0 secs) due to:
  Task has not declared any outputs.
baseDebugApk : null , it is not a valid file , so can not rebuild debug channel apk
baseReleaseApk : /Users/xiongxingxing/androidGithubProject/TinkerDemo/app/baseApk/tinkerdemo-base-signed.apk , it is not a valid file , so can not rebuild release channel apk
:app:reBuildChannel (Thread[Task worker,5,main]) completed. Took 0.001 secs.

app下的build.gradle 中的

rebuildChannel {
    baseReleaseApk = new File(project.projectDir, "baseApk/tinkerdemo-base-signed.apk")
}

channel.txt文件也配置了,并且有值

比较疑惑,不知道问题出在哪了? 请指教

建议提供获取当前Variant的方法,并将 apkNameFormat 中flavorName改名为channelName

当前项目有生成aaa, bbb, ccc三个不同产品的配置

   flavorDimensions "mode"

    productFlavors {
        aaa {
            dimension "mode"
            applicationId "com.example.aaa"
            signingConfig signingConfigs.aaa
        }

        bbb{
            dimension "mode"
            applicationId "com.example.bbb"
            signingConfig signingConfigs.bbb
        }

        ccc{
            dimension "mode"
            applicationId "com.example.ccc"
            signingConfig signingConfigs.ccc
        }
    }

多渠道包的命名规则,默认为:${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}

现需求为

def getCurrentFlavorName= "${getCurrentFlavorName()}"
apkNameFormat = getCurrentFlavorName + '-${buildType}-V${versionName}-C${versionCode}-${buildTime}-${flavorName}'
import java.util.regex.Matcher
import java.util.regex.Pattern
def getCurrentFlavorName() {
    Gradle gradle = getGradle()
    String  tskReqStr = gradle.getStartParameter().getTaskRequests().toString()

    Pattern pattern;

    if( tskReqStr.contains( "assemble" ) )
        pattern = Pattern.compile("assemble(\\w+)(Release|Debug)")
    else if(tskReqStr.contains( "channel" ))
        pattern = Pattern.compile("channel(\\w+)(Release|Debug)")
    else
        pattern = Pattern.compile("generate(\\w+)(Release|Debug)")

    Matcher matcher = pattern.matcher( tskReqStr )

    if( matcher.find() )
        return matcher.group(1).toLowerCase()
    else
    {
        println "NO MATCH FOUND"
        return "";
    }
}

现在获取getCurrentFlavorName 比较麻烦,希望提供简易方法获取mVariant,并将 apkNameFormat 中flavorName改名为channelName

 def keyValue = [
                'appName'    : project.name,
                'flavorName' : channel,  //----------->channelName
                'buildType'  : mVariant.buildType.name,
                'versionName': mVariant.versionName,
                'versionCode': mVariant.versionCode,
                'appId'      : mVariant.applicationId,
                'buildTime'  : buildTime
               'mVariant' : mVariant,  // add
               'flavorName' : mVariant.name,  //add

        ]

多次执行生成渠道包,会将前一次生成的渠道包删除,可有设置不删除的配置?

如何配置channel文件

我看项目的配置,channel文件是每行一个渠道,我现在是有一个渠道名,有一个渠道Code,如何让这个配置在channel文件中?

使我在打包的时候,通过flavorName拿到我配置的渠道名,String channel = ChannelReaderUtil.getChannel(getApplicationContext());能拿到我其他的渠道信息

AndroidManifest.xml 中<application android:allowBackup="false" 编译报错

  • What went wrong:
    Execution failed for task ':app:processDebugManifest'.

Manifest merger failed : Attribute application@allowBackup value=(true) from AndroidManifest.xml:6:9-35
is also present at [com.leon.channel:helper:1.0.2] AndroidManifest.xml:12:9-36 value=(false).
Suggestion: add 'tools:replace="android:allowBackup"' to element at AndroidManifest.xml:5:5-19:19 to override.

增量更新是否会受影响呢

用bspatch 做增量更新是否会受影响呢,生成差分包是使用的不带渠道信息的原始包。在合成的时候是否会有问题呢?

打包完成未释放资源

1.1.7版本
打包完成后,生成的文件或文件夹没有释放,导致资源无法移动或复制

使用rebuildChannel 根据已有基础包重新生成多渠道包有问题

channel{
    //指定渠道文件
    channelFile = file("../channel.txt")
    //多渠道包的输出目录,默认为new File(project.buildDir,"channel")
    baseOutputDir = new File(project.buildDir,"channel")
    //多渠道包的命名规则,默认为:${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}
    apkNameFormat ='${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}'
}

rebuildChannel {
    //指定渠道文件
    channelFile = new File("../channel.txt")
    baseReleaseApk = new File(project.buildDir, "outputs/apk/app-release.apk")
    //默认为new File(project.buildDir, "rebuildChannel/release")
    releaseOutputDir = new File(project.buildDir, "rebuildChannel/release")
}

上面是我的配置,但是执行rebuildChannel之后只有一个渠道包(rebuildChannel\release目录下只有一个app-release.apk文件)生成,是怎么回事呢?ps:执行channel命令打渠道包是正常的

Bug: rebuildChannel releaseOutputDir can't use exist folder

When releaseOutputDir is already exist in filesystem.
I get the following exception

* What went wrong:
Execution failed for task ':passenger:reBuildChannel'.
> java.lang.NullPointerException (no error message)

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

If releaseOutputDir doesn't exist, everything works fine.

一些信息写入的问题

用这种打包方式如何写入除了渠道其他的信息呢,写入的信息是否会被人看见?

Feature request: channel.txt location can be configurable

Is it possible we config the channel.txt in channel's closure:

channel {
   channel_file 'channel.txt'
    baseOutputDir = new File(project.buildDir,"xxx")
    apkNameFormat ='${appName}-${versionName}-${versionCode}-${flavorName}-${buildType}'
}

关于设置多个基准包的建议

case如下:

  • 部分渠道的apk有定制需求,这部分是采用gradle脚本实现(只有包的构建,没有加入渠道信息)
  • 一个普通包
  • 然后有部分包需要使用360加固

经过以上3步之后,会发现,有一个普通包,有多个定制包,有多个加固包,然后我要使用VasDolly构建多渠道,但是VasDolly貌似只能设置一个基础包,不能满足我的需求,请问有什么好的办法解决这个问题吗?

命令行工具能写入信息,但是验证失败

日志如下:
find V2 signature block Id : 1896449818
baseApk : C:\Users...\app-release.apk , ChannelPackageMode : V2 Mode
------ File app-release.apk generate v2 channel apk , begin ------
baseApk : C:\Users...\app-release.apk , ApkSectionInfo = mContentEntry : first = java.nio.HeapByteBuffer[pos=0 lim=2572932 cap=2572932] , second = 0 , mSchemeV2Block : first = java.nio.HeapByteBuffer[pos=0 lim=1569 cap=1569] , second = 2572932 , mCentralDir : first = java.nio.HeapByteBuffer[pos=0 lim=43224 cap=43224] , second = 2574501 , mEocd : first = java.nio.HeapByteBuffer[pos=0 lim=22 cap=22] , second = 2617725
generateV2ChannelApk , channel = store_xiaomi , apkChannelName = store_xiaomi-app-release.apk
destApk = C:\Users...\out\store_xiaomi-app-release.apk , channel = store_xiaomi
addIdValueByteBufferMap , idValueMap = {-2012129793=java.nio.HeapByteBuffer[pos=0 lim=12 cap=12]}
find V2 signature block Id : 1896449818
addIdValueByteBufferMap , existentIdValueMap = {1896449818=java.nio.HeapByteBuffer[pos=0 lim=1525 cap=1525]}
addIdValueByteBufferMap , finalIdValueMap = {1896449818=java.nio.HeapByteBuffer[pos=0 lim=1525 cap=1525], -2012129793=java.nio.HeapByteBuffer[pos=0 lim=12 cap=12]}
addIdValueByteBufferMap , oldApkSigningBlock size = 1569 , newApkSigningBlock size = 1593
addIdValueByteBufferMap , after add channel , new apk is C:\Users...\out\store_xiaomi-app-release.apk , length = 2617771
try to read channel info from apk : C:\Users...\out\store_xiaomi-app-release.apk
find V2 signature block Id : 1896449818
getByteBufferValueById , destApk C:\Users...\out\store_xiaomi-app-release.apk IdValueMap = {1896449818=java.nio.HeapByteBuffer[pos=0 lim=1525 cap=1525], -2012129793=java.nio.HeapByteBuffer[pos=0 lim=12 cap=12]}
getByteValueById , id = -2012129793 , value = java.nio.HeapByteBuffer[pos=0 lim=12 cap=12]
generateV2ChannelApk , .\out\store_xiaomi-app-release.apk add channel success
verified : false
generateV2ChannelApk error , please check it and fix it ▒▒and that you should generate all V2 Channel Apk again!
java.lang.RuntimeException: generateV2ChannelApk , after add channel , .\out\store_xiaomi-app-release.apk v1 verify failure
at com.leon.channel.command.Util.generateV2ChannelApk(Util.java:241)
at com.leon.channel.command.Util.writeChannel(Util.java:92)
at com.leon.channel.command.Main.main(Main.java:110)
------ File app-release.apk generate v2 channel apk , end ------
------ total 1 channel apk , cost : 136 ------

渠道value 是否和walle一样容易被修改

我现在用的是walle 打的渠道包; 但是渠道包很容易就被修改成另一个渠道;而且已经上线的应用,下载下来渠道也变成了另一个渠道的值; 我想问 vasdolly 的机制和walle 一模一样吗;打出来的包会不会也这么容易就被修改了渠道value

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.