This commit is contained in:
327135569 2021-04-05 00:25:21 +08:00
parent c7bd67f0ec
commit fe0bb0f732
4 changed files with 66 additions and 109 deletions

View File

@ -4,6 +4,7 @@ dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile project(':axmlprinter')
compile project(':apksigner')
compile group: 'commons-io', name: 'commons-io', version: '2.8.0'
}
jar {

View File

@ -14,12 +14,15 @@ import com.wind.meditor.property.ModificationProperty;
import com.wind.meditor.utils.NodeValue;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;
import static org.apache.commons.io.FileUtils.copyFile;
public class MainCommand extends BaseCommand {
private String apkPath;
@ -72,8 +75,14 @@ public class MainCommand extends BaseCommand {
new MainCommand().doMain(args);
}
private void fuckIfFail(boolean b) {
if (!b) {
throw new IllegalStateException("wtf", new Throwable("DUMPBT"));
}
}
@Override
protected void doCommandLine() {
protected void doCommandLine() throws IOException {
if (remainingArgs.length != 1) {
if (remainingArgs.length == 0) {
System.out.println("Please choose one apk file you want to process. ");
@ -95,7 +104,7 @@ public class MainCommand extends BaseCommand {
return;
}
String currentDir = new File(".").getAbsolutePath(); // 当前命令行所在的目录
String currentDir = new File(".").getAbsolutePath();
System.out.println("currentDir: " + currentDir);
System.out.println("apkPath: " + apkPath);
@ -122,11 +131,9 @@ public class MainCommand extends BaseCommand {
String apkFileName = getBaseName(srcApkFile);
// 中间文件临时存储的位置
String tempFilePath = outputApkFileParentPath + File.separator +
currentTimeStr() + "-tmp" + File.separator;
// apk文件解压的目录
unzipApkFilePath = tempFilePath + apkFileName + "-" + UNZIP_APK_FILE_NAME + File.separator;
System.out.println("outputApkFileParentPath: " + outputApkFileParentPath);
@ -137,7 +144,6 @@ public class MainCommand extends BaseCommand {
new SaveApkSignatureTask(apkPath, unzipApkFilePath).run();
}
// 先解压apk到指定目录下
long currentTime = System.currentTimeMillis();
FileUtils.decompressZip(apkPath, unzipApkFilePath);
@ -166,15 +172,15 @@ public class MainCommand extends BaseCommand {
File manifestFile = new File(manifestFilePath);
String manifestFilePathNew = unzipApkFilePath + "AndroidManifest" + "-" + currentTimeStr() + ".xml";
File manifestFileNew = new File(manifestFilePathNew);
manifestFile.renameTo(manifestFileNew);
fuckIfFail(manifestFile.renameTo(manifestFileNew));
modifyManifestFile(manifestFilePathNew, manifestFilePath, applicationName);
// new manifest may not exist
if (manifestFile.exists() && manifestFile.length() > 0) {
manifestFileNew.delete();
fuckIfFail(manifestFileNew.delete());
} else {
manifestFileNew.renameTo(manifestFile);
fuckIfFail(manifestFileNew.renameTo(manifestFile));
}
// save original main application name to asset file
@ -196,9 +202,7 @@ public class MainCommand extends BaseCommand {
// copy origin apk to assets
// convenient to bypass some check like CRC
if (!FileUtils.copyFile(srcApkFile, new File(unzipApkFilePath, "assets/origin_apk.bin"))) {
throw new IllegalStateException("orignal apk copy fail");
}
copyFile(srcApkFile, new File(unzipApkFilePath, "assets/origin_apk.bin"));
// excute these tasks
for (Runnable executor : mXpatchTasks) {
@ -208,6 +212,8 @@ public class MainCommand extends BaseCommand {
System.out.println(executor.getClass().getSimpleName() + " cost time: "
+ (System.currentTimeMillis() - currentTime) + "ms");
}
System.out.println("Output APK: " + output);
}
private void modifyManifestFile(String filePath, String dstFilePath, String originalApplicationName) {

View File

@ -1,8 +1,9 @@
package com.storm.wind.xpatch.task;
import com.storm.wind.xpatch.util.FileUtils;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -79,27 +80,33 @@ public class SoAndDexCopyTask implements Runnable {
}
for (File mySoFile : files) {
File target = new File(apkSoFullPath, mySoFile.getName());
FileUtils.copyFile(mySoFile, target);
try {
FileUtils.copyFile(mySoFile, target);
} catch (Exception err) {
throw new IllegalStateException("wtf", err);
}
System.out.println("Copy " + mySoFile.getAbsolutePath() + " to " + target.getAbsolutePath());
}
}
}
private void copyDexFile(int dexFileCount) {
boolean copyed = false;
// copy all dex files in list-dex
File[] files = new File("list-dex").listFiles();
if (files == null || files.length == 0) {
System.out.println("Warning: Nothing dex file has been copied");
return;
}
for (File file : files) {
String copiedDexFileName = "classes" + (dexFileCount + 1) + ".dex";
File target = new File(unzipApkFilePath, copiedDexFileName);
FileUtils.copyFile(file, target);
System.out.println("Copy " + file.getAbsolutePath() + " to " + target.getAbsolutePath());
dexFileCount++;
copyed = true;
try {
// copy all dex files in list-dex
File[] files = new File("list-dex").listFiles();
if (files == null || files.length == 0) {
System.out.println("Warning: Nothing dex file has been copied");
return;
}
for (File file : files) {
String copiedDexFileName = "classes" + (dexFileCount + 1) + ".dex";
File target = new File(unzipApkFilePath, copiedDexFileName);
FileUtils.copyFile(file, target);
System.out.println("Copy " + file.getAbsolutePath() + " to " + target.getAbsolutePath());
dexFileCount++;
}
} catch (Exception err) {
throw new IllegalStateException("wtf", err);
}
}

View File

@ -1,5 +1,8 @@
package com.storm.wind.xpatch.util;
import org.apache.commons.io.FileSystemUtils;
import org.apache.commons.io.IOUtils;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
@ -36,64 +39,51 @@ public class FileUtils {
* @return 解压结果成功失败
*/
@SuppressWarnings("rawtypes")
public static boolean decompressZip(String zipPath, String descDir) {
public static void decompressZip(String zipPath, String descDir) throws IOException {
File zipFile = new File(zipPath);
boolean flag = false;
if (!descDir.endsWith(File.separator)) {
descDir = descDir + File.separator;
}
File pathFile = new File(descDir);
if (!pathFile.exists()) {
if(!pathFile.mkdirs()){
if (!pathFile.mkdirs()) {
throw new IllegalStateException("mkdir fail " + pathFile.getAbsolutePath());
}
}
ZipFile zip = null;
try {
try {
// api level 24 才有此方法
zip = new ZipFile(zipFile, Charset.forName("gbk"));//防止中文目录乱码
} catch (NoSuchMethodError e) {
// api < 24
zip = new ZipFile(zipFile);
}
try (ZipFile zip = new ZipFile(zipFile, Charset.forName("gbk"))) {
for (Enumeration entries = zip.entries(); entries.hasMoreElements(); ) {
ZipEntry entry = (ZipEntry) entries.nextElement();
String zipEntryName = entry.getName();
InputStream in = zip.getInputStream(entry);
//指定解压后的文件夹+当前zip文件的名称
String outPath = (descDir + zipEntryName).replace("/", File.separator);
//判断路径是否存在,不存在则创建文件路径
File file = new File(outPath.substring(0, outPath.lastIndexOf(File.separator)));
File file = new File(outPath);
if (!file.exists()) {
if(!file.mkdirs()){
if (entry.isDirectory()) {
if (!file.mkdirs()) {
throw new IllegalStateException("mkdir fail " + file.getAbsolutePath());
}
}
//判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压
if (new File(outPath).isDirectory()) {
continue;
}
//保存文件路径信息可利用md5.zip名称的唯一性来判断是否已经解压
// System.err.println("当前zip解压之后的路径为" + outPath);
OutputStream out = new FileOutputStream(outPath);
byte[] buf1 = new byte[2048];
int len;
while ((len = in.read(buf1)) > 0) {
out.write(buf1, 0, len);
try (InputStream in = zip.getInputStream(entry)) {
if (file.getParentFile() != null && !file.getParentFile().exists()) {
if (!file.getParentFile().mkdirs()) {
throw new IllegalStateException("mkdir fail " + file.getAbsolutePath());
}
if (System.getProperty("os.name", "").toLowerCase().contains("win")) {
Runtime.getRuntime().exec("fsutil file setCaseSensitiveInfo " + file.getParentFile().getAbsolutePath());
System.out.println("Enable setCaseSensitiveInfo for " + file.getParentFile().getAbsolutePath());
}
}
OutputStream out = new FileOutputStream(outPath);
IOUtils.copy(in, out);
out.close();
} catch (Exception err) {
throw new IllegalStateException("wtf", err);
}
close(in);
close(out);
}
flag = true;
close(zip);
} catch (IOException e) {
e.printStackTrace();
}
return flag;
}
private static InputStream getInputStreamFromFile(String filePath) {
@ -125,53 +115,6 @@ public class FileUtils {
}
}
public static void copyFile(String sourcePath, String targetPath) {
copyFile(new File(sourcePath), new File(targetPath));
}
public static boolean copyFile(File source, File target) {
FileInputStream inputStream = null;
FileOutputStream outputStream = null;
try {
inputStream = new FileInputStream(source);
outputStream = new FileOutputStream(target);
FileChannel iChannel = inputStream.getChannel();
FileChannel oChannel = outputStream.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (true) {
buffer.clear();
int r = iChannel.read(buffer);
if (r == -1) {
break;
}
buffer.limit(buffer.position());
buffer.position(0);
oChannel.write(buffer);
}
return true;
} catch (IOException e) {
e.printStackTrace();
} finally {
close(inputStream);
close(outputStream);
}
return false;
}
public static void deleteDir(File file) {
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null && files.length > 0) {
for (File f : files) {
deleteDir(f);
}
}
}
file.delete();
}
public static void compressToZip(String srcPath, String dstPath) {
File srcFile = new File(srcPath);
File dstFile = new File(dstPath);