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 fileTree(dir: 'libs', include: ['*.jar'])
compile project(':axmlprinter') compile project(':axmlprinter')
compile project(':apksigner') compile project(':apksigner')
compile group: 'commons-io', name: 'commons-io', version: '2.8.0'
} }
jar { jar {

View File

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

View File

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

View File

@ -1,5 +1,8 @@
package com.storm.wind.xpatch.util; 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.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.BufferedWriter; import java.io.BufferedWriter;
@ -36,64 +39,51 @@ public class FileUtils {
* @return 解压结果成功失败 * @return 解压结果成功失败
*/ */
@SuppressWarnings("rawtypes") @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); File zipFile = new File(zipPath);
boolean flag = false;
if (!descDir.endsWith(File.separator)) { if (!descDir.endsWith(File.separator)) {
descDir = descDir + File.separator; descDir = descDir + File.separator;
} }
File pathFile = new File(descDir); File pathFile = new File(descDir);
if (!pathFile.exists()) { if (!pathFile.exists()) {
if(!pathFile.mkdirs()){ if (!pathFile.mkdirs()) {
throw new IllegalStateException("mkdir fail " + pathFile.getAbsolutePath()); throw new IllegalStateException("mkdir fail " + pathFile.getAbsolutePath());
} }
} }
ZipFile zip = null; try (ZipFile zip = new ZipFile(zipFile, Charset.forName("gbk"))) {
try {
try {
// api level 24 才有此方法
zip = new ZipFile(zipFile, Charset.forName("gbk"));//防止中文目录乱码
} catch (NoSuchMethodError e) {
// api < 24
zip = new ZipFile(zipFile);
}
for (Enumeration entries = zip.entries(); entries.hasMoreElements(); ) { for (Enumeration entries = zip.entries(); entries.hasMoreElements(); ) {
ZipEntry entry = (ZipEntry) entries.nextElement(); ZipEntry entry = (ZipEntry) entries.nextElement();
String zipEntryName = entry.getName(); String zipEntryName = entry.getName();
InputStream in = zip.getInputStream(entry);
//指定解压后的文件夹+当前zip文件的名称
String outPath = (descDir + zipEntryName).replace("/", File.separator); String outPath = (descDir + zipEntryName).replace("/", File.separator);
//判断路径是否存在,不存在则创建文件路径 File file = new File(outPath);
File file = new File(outPath.substring(0, outPath.lastIndexOf(File.separator)));
if (!file.exists()) { if (entry.isDirectory()) {
if(!file.mkdirs()){ if (!file.mkdirs()) {
throw new IllegalStateException("mkdir fail " + file.getAbsolutePath()); throw new IllegalStateException("mkdir fail " + file.getAbsolutePath());
} }
}
//判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压
if (new File(outPath).isDirectory()) {
continue; continue;
} }
//保存文件路径信息可利用md5.zip名称的唯一性来判断是否已经解压
// System.err.println("当前zip解压之后的路径为" + outPath); try (InputStream in = zip.getInputStream(entry)) {
OutputStream out = new FileOutputStream(outPath); if (file.getParentFile() != null && !file.getParentFile().exists()) {
byte[] buf1 = new byte[2048]; if (!file.getParentFile().mkdirs()) {
int len; throw new IllegalStateException("mkdir fail " + file.getAbsolutePath());
while ((len = in.read(buf1)) > 0) { }
out.write(buf1, 0, len); 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) { 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) { public static void compressToZip(String srcPath, String dstPath) {
File srcFile = new File(srcPath); File srcFile = new File(srcPath);
File dstFile = new File(dstPath); File dstFile = new File(dstPath);