fix
This commit is contained in:
parent
c7bd67f0ec
commit
fe0bb0f732
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue