Skip to content

Commit

Permalink
支持V3版本签名,同时修复大于2G的apk渠道包生成错误的Bug
Browse files Browse the repository at this point in the history
  • Loading branch information
yanyongshan committed Jan 12, 2023
1 parent 6bc633b commit 95a1aaa
Show file tree
Hide file tree
Showing 6 changed files with 32 additions and 23 deletions.
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
[![license](http://img.shields.io/badge/license-BSD3-brightgreen.svg?style=flat)](https://github.com/Tencent/VasDolly/blob/master/LICENSE)
[![Release Version](https://img.shields.io/badge/release-3.0.4-red.svg)](https://github.com/Tencent/VasDolly/releases)
[![Release Version](https://img.shields.io/badge/release-3.0.5-red.svg)](https://github.com/Tencent/VasDolly/releases)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Tencent/VasDolly/pulls)
[![wiki](https://img.shields.io/badge/Wiki-open-brightgreen.svg)](https://github.com/Tencent/VasDolly/wiki)
---


# 简介
VasDolly是一种快速多渠道打包工具,同时支持基于V1签名和V2签名进行多渠道打包。插件本身会自动检测Apk使用的签名类别,并选择合适的多渠道打包方式,对使用者来说完全透明。
`V3.0.4`版本已支持Android Gradle Plugin 4.2.0以上版本,欢迎使用!
VasDolly是一种快速多渠道打包工具,同时支持基于V1签名和V2,V3签名进行多渠道打包。插件本身会自动检测Apk使用的签名类别,并选择合适的多渠道打包方式,对使用者来说完全透明。

目前Gradle Plugin 2.2以上默认开启V2签名,所以如果想关闭V2签名,可将下面的v2SigningEnabled设置为false。
关于应用签名说明:[见官方文档](https://source.android.com/security/apksigning)
Expand All @@ -34,7 +33,7 @@ signingConfigs {
``` groovy
dependencies {
classpath 'com.android.tools.build:gradle:7.0.3'
classpath 'com.tencent.vasdolly:plugin:3.0.4'
classpath 'com.tencent.vasdolly:plugin:3.0.5'
}
```
## 引用VasDolly Plugin
Expand All @@ -46,7 +45,7 @@ apply plugin: 'com.tencent.vasdolly'
在主App工程的`build.gradle`中,添加读取渠道信息的helper类库依赖:
``` groovy
dependencies {
   api 'com.tencent.vasdolly:helper:3.0.4'
   api 'com.tencent.vasdolly:helper:3.0.5'
}
```
## 配置渠道列表
Expand Down
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ buildscript {
google()
}
dependencies {
classpath "com.tencent.vasdolly:plugin:3.0.4"
classpath "com.tencent.vasdolly:plugin:3.0.5"
}
}

Expand Down Expand Up @@ -103,5 +103,5 @@ dependencies {

api 'androidx.appcompat:appcompat:1.4.0'
//api:同老版本compile作用一样,即本module将会向外暴露其依赖的module变化,即若'helper'库发生了改变,那么本module以及所有依赖于本module的module都要重新编译
api "com.tencent.vasdolly:helper:3.0.4"
api "com.tencent.vasdolly:helper:3.0.5"
}
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ext {

//VasDolly插件版本信息
GROUP = 'com.tencent.vasdolly'
VERSION = '3.0.4'
VERSION = '3.0.5'
}

buildscript {
Expand Down
Binary file modified command/jar/VasDolly.jar
Binary file not shown.
32 changes: 19 additions & 13 deletions command/src/main/java/com/tencent/vasdolly/command/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public static void writeChannel(File baseApk, List<String> channelList, File out
generateV1ChannelApk(baseApk, channelList, outputDir, isFastMode);
}
} else if (mode == V2_MODE || mode == V3_MODE) {
generateV2ChannelApk(baseApk, channelList, outputDir, isFastMode);
generateChannelApk(baseApk, channelList, outputDir, isFastMode);
} else {
throw new IllegalStateException("not support channel package mode:" + mode);
}
Expand Down Expand Up @@ -256,40 +256,40 @@ private static void generateV1ChannelApkMultiThread(File baseApk, List<String> c
}

/**
* V2方式写入渠道
* V2/V3签名方式写入渠道
*
* @param baseApk
* @param channelList
* @param outputDir
*/
private static void generateV2ChannelApk(File baseApk, List<String> channelList, File outputDir, boolean isFastMode) {
private static void generateChannelApk(File baseApk, List<String> channelList, File outputDir, boolean isFastMode) {
String apkName = baseApk.getName();
long startTime = System.currentTimeMillis();
System.out.println("------ File " + apkName + " generate v2 channel apk , begin ------");
System.out.println("------ File " + apkName + " generate channel apk , begin ------");

try {
// 获取Apk的各部分片段信息
ApkSectionInfo apkSectionInfo = IdValueWriter.getApkSectionInfo(baseApk, false);
for (String channel : channelList) {
File destFile = getDestinationFile(outputDir, apkName, channel);
System.out.println("generatedV2ChannelApk , channel = " + channel + " , apkChannelName = " + destFile.getName());
System.out.println("generatedChannelApk , channel = " + channel + " , apkChannelName = " + destFile.getName());
if (apkSectionInfo.lowMemory) {
copyFileUsingNio(baseApk, destFile);
}
ChannelWriter.addChannelByV2(apkSectionInfo, destFile, channel);
if (!isFastMode) {
//1. verify channel info
if (ChannelReader.verifyChannelByV2(destFile, channel)) {
System.out.println("generateV2ChannelApk destFile(" + destFile + ")add channel success");
System.out.println("generatedChannelApk destFile(" + destFile + ")add channel success");
} else {
throw new RuntimeException("generateV2ChannelApk destFile( " + destFile + ") add channel failure");
throw new RuntimeException("generatedChannelApk destFile( " + destFile + ") add channel failure");
}

//2. 检查生成的渠道包是否是合法的APK文件
if (VerifyApk.verifySignature(destFile)) {
System.out.println("generateV2ChannelApk , after add channel , " + destFile + " v2 verify success");
System.out.println("generatedChannelApk , after add channel , " + destFile + " verify success");
} else {
throw new RuntimeException("generateV2ChannelApk , after add channel , " + destFile + " verify failure");
throw new RuntimeException("generatedChannelApk , after add channel , " + destFile + " verify failure");
}
}
apkSectionInfo.rewind();
Expand All @@ -298,11 +298,11 @@ private static void generateV2ChannelApk(File baseApk, List<String> channelList,
}
}
} catch (Exception e) {
System.out.println("generateV2ChannelApk error , please check it and fix it ,and that you should generate all V2 Channel Apk again!");
System.out.println("generatedChannelApk error , please check it and fix it ,and that you should generate all Channel Apk again!");
e.printStackTrace();
}

System.out.println("------ File " + apkName + " generate v2 channel apk , end ------");
System.out.println("------ File " + apkName + " generate channel apk , end ------");
long cost = System.currentTimeMillis() - startTime;
System.out.println("------ total " + channelList.size() + " channel apk , cost : " + cost + " ------");
}
Expand All @@ -314,7 +314,7 @@ public static boolean removeChannel(File channelApk) {
if (mode == V1_MODE) {
ChannelWriter.removeChannelByV1(channelApk);
return true;
} else if (mode == V2_MODE) {
} else if (mode == V2_MODE || mode == V3_MODE) {
ChannelWriter.removeChannelByV2(channelApk, true);
return true;
} else {
Expand Down Expand Up @@ -410,7 +410,13 @@ public static void copyFileUsingNio(File source, File dest) throws IOException {
outStream = new FileOutputStream(dest, false);
in = inStream.getChannel();
out = outStream.getChannel();
in.transferTo(0, in.size(), out);
long pos = 0;
long count = in.size();
long copied = 0;
while (copied != count) {
// 特别注意,使用transferTo最多只能复制int.MAX_VALUE个字节(约2GB),因此需要多次操作
copied += in.transferTo(pos + copied, count - copied, out);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ public static void removeIdValue(ApkSectionInfo apkSectionInfo, File destApk, Li
try {
fIn = new RandomAccessFile(destApk, "rw");
if (apkSectionInfo.lowMemory) {
fIn.seek(apkSectionInfo.apkSigningBlock.getSecond());
long signBlockPos = apkSectionInfo.apkSigningBlock.getSecond();
System.out.println("seek to apk signing block pos:" + signBlockPos);
fIn.seek(signBlockPos);
} else {
ByteBuffer contentEntry = apkSectionInfo.contentEntry.getFirst();
fIn.seek(apkSectionInfo.contentEntry.getSecond());
Expand Down Expand Up @@ -145,7 +147,9 @@ public static void addIdValueByteBufferMap(ApkSectionInfo apkSectionInfo, File d
try {
fIn = new RandomAccessFile(destApk, "rw");
if (apkSectionInfo.lowMemory) {
fIn.seek(apkSectionInfo.apkSigningBlock.getSecond());
long signBlockPos = apkSectionInfo.apkSigningBlock.getSecond();
System.out.println("seek to apk signing block pos:" + signBlockPos + ",dest apk file len:" + fIn.length());
fIn.seek(signBlockPos);
} else {
ByteBuffer contentEntry = apkSectionInfo.contentEntry.getFirst();
fIn.seek(apkSectionInfo.contentEntry.getSecond());
Expand Down

0 comments on commit 95a1aaa

Please sign in to comment.