Android-用apktool实现多渠道自动打包
来源:互联网 发布:c语言左移一位 编辑:程序博客网 时间:2024/05/17 10:08
因为项目当中需要对apk的AndroidManifest.xml文件当中的meta-data中的数据进行更新跟替换,如果用其他方式打包的话非常麻烦,然后在网上找了一个教程实现一段代码就可以自动打包,简单而且粗暴。这个是原文:http://blog.csdn.net/h3c4lenovo/article/details/10007039。我做了一些修改跟补充。
需要用到的环境:jdk,sdk,还有apktool。因为我的电脑上已经有配置jdk跟sdk了。如果没有配置的话自行搜索。然后apktool这个工具的话可以可以点击这里下载。
有了工具就可以开始写代码了,实现自动打包的原理是这样的:
1.先得到apk文件(可以打签名包和未签名包,只要有apk就行)
2.用apktool 解包 (java -jar apktool.jar d xxx.apk),通过这个指令就会在apktool目录下生成一个apk同名的文件夹,其中文件夹里面就包括我们要修改的AndroidManifest.xml
3.写代码去修改AndroidManifest.xml中对应Channel_Id的地方
4.用apktool 打包 (java -jar apktool.jar b xxx.ap xxx_us.apk),通过这个指令会生成一个未签名的apk,注意,此指令需要依赖aapt,请在系统环境变量中引入aapt!
5.用jdk的jarsigner工具给apk签名(指令有很多,我用的是jarsigner -digestalg SHA1 -sigalg MD5withRSA -verbose -keystore abc.keystore -signedjar xxx_s.apk xxx_us.apk abc.keystore -storepass)
知道了这个步骤后我们先验证一下反编译,打包,签名这些会不会出现问题。如果没有出现问题再开始写代码去实现自动打包。
apktool工具解压后里面有三个文件:
反编译:把你需要反编译的apk文件跟这三个文件放在一起,然后运行cmd,进入当前这个文件夹,在控制台输入:java -jar apktool.jar d XXX.apk(xxx.apk你放入的apk文件名)然后会在你的当前文件夹下生成一个以apk的文件名。
打包:在控制台中输入java -jar apktool.jar b MyAndroidTest -o XXX.apk(打包后要命名的名称) -o表示新生成的apk文件放在当前文件夹。
签名:把签名的.keystore文件放到当前的文件夹当中,然后在控制台中输入jarsigner -digestalg SHA1 -sigalg MD5withRSA -tsa https://timestamp.geotrust.com/tsa -verbose -keystore XXX.keystore(你放入的.keystore文件) -signedjar XXXsign.apk(签名成功后apk文件名) XXX.apk(签名前的apk名称) XXX.keystore(你放入的.keystore文件) -storepass XXX(你放入的.keystore对应的密码)
public class AutoPack {public static void main(String[] args) {System.out.println("====**====By H3c=====**======"); if (args.length != 3) {// 传入3个参数 apk报名、签名文件、签名密码 System.out .println("==ERROR==usage:java -jar rePack.jar apkName keyFile keyPasswd======"); System.out .println("==INFO==Example: java -jar rePack.jar test.apk android.keystore 123456======"); return; } String apk = args[0]; String keyFile = args[1]; String keyPasswd = args[2]; System.out.println("apk名称:"+apk); SplitApk sp = new SplitApk(apk, keyFile, keyPasswd); sp.mySplit(); }}
SplitApk.java文件如下:
import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList;public class SplitApk { ArrayList<String> channel = new ArrayList<String>();//渠道号String curPath;// 当前文件夹路径 String apkName; //包名String keyFile; //签名文件String keyPasswd; //签名文件密码public SplitApk(String apkName, String keyFile, String keyPasswd) {// 构造函数接受参数 this.curPath = new File("").getAbsolutePath(); this.apkName = apkName; this.keyFile = keyFile; this.keyPasswd = keyPasswd; } public void mySplit() { getCannelFile();// 获得自定义的渠道号 modifyXudao();// 解包 - 打包 - 签名 } /** * 获得渠道号 */ private void getCannelFile() { File f = new File("channel.txt");// 读取当前文件夹下的channel.txt if (f.exists() && f.isFile()) { BufferedReader br = null; FileReader fr = null; try { fr = new FileReader(f); br = new BufferedReader(fr); String line = null; while ((line = br.readLine()) != null) { String[] array = line.split("\t");// 这里是Tab分割 channel.add(array[0]);} } catch (Exception e) { e.printStackTrace(); } finally { try { if (fr != null) { fr.close(); } if (br != null) { br.close(); } } catch (IOException e) { e.printStackTrace(); } } System.out.println("==INFO 1.==获取渠道成功,一共有" + channel.size() + "个渠道======"); } else { System.out.println("==ERROR==channel.txt文件不存在,请添加渠道文件======"); } } /** * apktool解压apk,替换渠道值 * * @throws Exception */ private void modifyXudao() { // 解压 /C 执行字符串指定的命令然后终断 String cmdUnpack = "cmd.exe /C java -jar apktool.jar d -f -s " + apkName; runCmd(cmdUnpack); //执行指令 cmd指令System.out.println("==INFO 2.==解压apk成功,准备移动======"); // 备份AndroidManifest.xml // 获取解压的apk文件名 String[] apkFilePath = apkName.split("\\\\"); String shortApkName = apkFilePath[apkFilePath.length - 1]; System.out.println("shortApkName = "+shortApkName);String dir = shortApkName.split(".apk")[0]; System.err.println("dir = "+dir);File packDir = new File(dir);//获得解压的apk目录 String f_mani = packDir.getAbsolutePath() + "\\AndroidManifest.xml"; String f_mani_bak = curPath + "\\AndroidManifest.xml"; //在当前文件夹下新建一个AndroidManifest.xml文件并把解压的apk文件里面的AndroidManifest.xml文件内容复制进来File manifest = new File(f_mani); File manifest_bak = new File(f_mani_bak); // 拷贝文件 -- 此方法慎用,详见http://xiaoych.iteye.com/blog/149328 manifest.renameTo(manifest_bak); for (int i = 0; i < 10; i++) { //当文件还没有创建成功的时候暂停等待if (manifest_bak.exists()) { break; } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } if (manifest_bak.exists()) { System.out.println("==INFO 3.==移动文件成功======"); } else { System.out.println("==ERROR==移动文件失败======"); } // 创建生成结果的目录 File f = new File("apk"); if (!f.exists()) { f.mkdir(); } /* * 遍历map,复制manifese进来,修改后打包,签名,存储在对应文件夹中 */ for (int i = 0; i < channel.size(); i++) { String id = channel.get(i); System.out.println("==INFO 4.1. == 正在生成包: " + id + " ======"); BufferedReader br = null; FileReader fr = null; FileWriter fw = null; try { fr = new FileReader(manifest_bak); br = new BufferedReader(fr); String line = null; StringBuffer sb = new StringBuffer(); while ((line = br.readLine()) != null) { //修改AndroidManifest.xml的meta-data字段if (line.contains("deacon_id")) { line = line.replaceAll("deacon_id", id); System.out.println("替换为渠道号"+id+"成功");} sb.append(line + "\n"); } // 写回文件 fw = new FileWriter(f_mani); fw.write(sb.toString()); } catch (Exception e) { e.printStackTrace(); } finally { try { if (fr != null) { fr.close(); } if (br != null) { br.close(); } if (fw != null) { fw.close(); } } catch (IOException e) { e.printStackTrace(); } } System.out.println("==INFO 4.2. == 准备打包: " + id + " ======"); // 打包 - 生成未签名的包 String unsignApk = id + "_" + dir + "_un.apk"; String cmdPack = String.format( "cmd.exe /C java -jar apktool.jar b %s -o %s", dir, unsignApk); runCmd(cmdPack); System.out.println("==INFO 4.3. == 开始签名: " + id + " ======"); // 签名 String signApk = "./apk/" + id + "_" + dir + ".apk"; String cmdKey = String .format("cmd.exe /C jarsigner -digestalg SHA1 -sigalg MD5withRSA -tsa https://timestamp.geotrust.com/tsa -verbose -keystore %s -signedjar %s %s %s -storepass %s", keyFile, signApk, unsignApk, keyFile, keyPasswd); runCmd(cmdKey); System.out.println("==INFO 4.4. == 签名成功: " + id + " ======"); // 删除未签名的包 File unApk = new File(unsignApk); unApk.delete(); } //删除中途文件 String cmdKey = String.format("cmd.exe /C rd /s/q %s", dir); runCmd(cmdKey); manifest_bak.delete(); System.out.println("==INFO 5 == 完成 ======"); } /** * 执行指令 cmd指令 * * @param cmd 指令内容 */ public void runCmd(String cmd) { Runtime rt = Runtime.getRuntime(); BufferedReader br = null; InputStreamReader isr = null; try { Process p = rt.exec(cmd); // p.waitFor(); isr = new InputStreamReader(p.getInputStream()); br = new BufferedReader(isr); String msg = null; while ((msg = br.readLine()) != null) { System.out.println(msg); } } catch (Exception e) { e.printStackTrace(); System.out.println("执行cmd命令出错");} finally { try { if (isr != null) { isr.close(); } if (br != null) { br.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
1、然后生成jar包,右击工程选择菜单中的Export - Java - Runnable JAR file,选择导出路径后就可以输出jar了。
(看过上面的代码就知道,你可以修改获取渠道号的文件名,可以修改mate-data中的替换的字段,反正可以改成满足自己需求的样子)
然后为了可以更简单省事,可以写一个批处理文件,这样就点击一下批处理文件就可以自动实现打包。而且一行代码都不用写。。
批处理文件:1、在当前文件夹下新建一个txt文件,然在文件中添加如下代码:
@echo off set /p var=请拖入apk: java -jar AutoPack.jar %var% game.keystore 123456 echo.&echo 请按任意键退出...&pause>nul exit2、把txt文件的后缀名改成bat,然后在打包的时候只要替换文件当中的apk文件,再点击这个.bat文件。这个时候会出现一个控制台,你只要把你要打包的apk文件拖到控制台上然后确定,就可以帮你完成所有的操作了。结果如下:
- Android-用apktool实现多渠道自动打包
- android 多渠道自动打包
- Android 多渠道自动打包
- Ant自动打包、多渠道打包的实现
- Android Stuido 实现多渠道打包
- Android sudio配置实现app多渠道打包,libary多渠道打包
- ant工具-多渠道自动打包android项目
- Android Studio使用Gradle多渠道自动打包
- android-多渠道自动打包之一秒五包
- Android 多渠道打包 用3步来实现
- apk多渠道自动打包
- Java实现Android APK多渠道打包
- Android多渠道打包实现不同的功能模块
- Gradle 实现 Android 多渠道定制化打包
- Gradle 实现 Android 多渠道定制化打包
- Android 使用Python实现多渠道打包实践
- Android多渠道打包实现不同的功能模块
- Android 使用Python实现多渠道打包
- Kaiwii
- JAVA 中BIO,NIO,AIO的理解
- 导出Excel方式汇总-- 第三种
- 杭电OJ2084-数塔
- VirtualBox安装CentOS 7(一)
- Android-用apktool实现多渠道自动打包
- Groovy入门教程
- python的函数参数传递
- jQuery UI使用总结
- 计算几何 欧拉定理应用
- Myeclipse环境下 Springmvc注解式与hibernate框架整合具体步骤!
- MatLab建模学习笔记1——二维绘图
- bash: 09: value too great for base (error token is 09)
- JavaSE初步学习笔记(17天)