分享一种最简单的Android打渠道包的方法

做Android开发一转眼就四年了,以前是用ant打包的,习惯了也没觉得慢。

今年年初加入了新公司,新公司用的是Android studio开发,用的是gradle构建项目。

由于gradle构建每次都是重新编译项目,所以打包时就特别慢了,16个渠道包要打一个小时吧。

然后我们的项目负责人就交给我一个任务,研究下有什么快的打包方法,

并发给我一篇参考文章:

我一边写代码一边测试,终于找到了一种很快的打渠道包的方法。

因为APK其实就是ZIP的格式,所以,解压apk后,会看到里面有个META-INF目录。

由于META-INF目录并不会影响到APK的签名和运行,所以我们可以在META-INF目录里添加一个空文件,

不同的渠道就添加不同的空文件,文件名代表不同的渠道。

代码是java写的:

public class Tool {private static final String CHANNEL_PREFIX = "/META-INF/";private static final String CHANNEL_PATH_MATCHER = "regex:/META-INF/mtchannel_[0-9a-zA-Z]{1,5}";private static String source_path;private static final String channel_file_name = "channel_list.txt";private static final String channel_flag = "channel_";public static void main(String[] args) throws Exception {if (args.length <= 0) {System.out.println("请输入文件路径作为参数");return;}final String source_apk_path = args[0];//main方法传入的源apk的路径,是执行jar时命令行传入的,不懂的往下看。int last_index = source_apk_path.lastIndexOf("/") + 1;source_path = source_apk_path.substring(0, last_index);final String source_apk_name = source_apk_path.substring(last_index, source_apk_path.length());System.out.println("包路径:" + source_path);System.out.println("文件名:" + source_apk_name);ArrayList<String> channel_list = getChannelList(source_path + channel_file_name);final String last_name = ".apk";for (int i = 0; i < channel_list.size(); i++) {final String new_apk_path = source_path + source_apk_name.substring(0, source_apk_name.length() – last_name.length()) //+ "_" + channel_list.get(i) + last_name;copyFile(source_apk_path, new_apk_path);changeChannel(new_apk_path, channel_flag + channel_list.get(i));}}/** * 修改渠道号,原理是在apk的META-INF下新建一个文件名为渠道号的文件 */public static boolean changeChannel(final String zipFilename, final String channel) {try (FileSystem zipfs = createZipFileSystem(zipFilename, false)) {final Path root = zipfs.getPath("/META-INF/");ChannelFileVisitor visitor = new ChannelFileVisitor();Files.walkFileTree(root, visitor);Path existChannel = visitor.getChannelFile();Path newChannel = zipfs.getPath(CHANNEL_PREFIX + channel);if (existChannel != null) {Files.move(existChannel, newChannel, StandardCopyOption.ATOMIC_MOVE);} else {Files.createFile(newChannel);}return true;} catch (IOException e) {System.out.println("添加渠道号失败:" + channel);e.printStackTrace();}return false;}private static FileSystem createZipFileSystem(String zipFilename, boolean create) throws IOException {final Path path = Paths.get(zipFilename);final URI uri = URI.create("jar:file:" + path.toUri().getPath());final Map<String, String> env = new HashMap<>();if (create) {env.put("create", "true");}return FileSystems.newFileSystem(uri, env);}private static class ChannelFileVisitor extends SimpleFileVisitor<Path> {private Path channelFile;private PathMatcher matcher = FileSystems.getDefault().getPathMatcher(CHANNEL_PATH_MATCHER);public Path getChannelFile() {return channelFile;}@Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {if (matcher.matches(file)) {channelFile = file;return FileVisitResult.TERMINATE;} else {return FileVisitResult.CONTINUE;}}}/** 得到渠道列表 */private static ArrayList<String> getChannelList(String filePath) {ArrayList<String> channel_list = new ArrayList<String>();try {String encoding = "UTF-8";File file = new File(filePath);if (file.isFile() && file.exists()) { // 判断文件是否存在InputStreamReader read = new InputStreamReader(new FileInputStream(file), encoding);// 考虑到编码格式BufferedReader bufferedReader = new BufferedReader(read);String lineTxt = null;while ((lineTxt = bufferedReader.readLine()) != null) {// System.out.println(lineTxt);if (lineTxt != null && lineTxt.length() > 0) {channel_list.add(lineTxt);}}read.close();} else {System.out.println("找不到指定的文件");}} catch (Exception e) {System.out.println("读取文件内容出错");e.printStackTrace();}return channel_list;}/** 复制文件 */private static void copyFile(final String source_file_path, final String target_file_path) throws IOException {File sourceFile = new File(source_file_path);File targetFile = new File(target_file_path);BufferedInputStream inBuff = null;BufferedOutputStream outBuff = null;try {// 新建文件输入流并对它进行缓冲inBuff = new BufferedInputStream(new FileInputStream(sourceFile));// 新建文件输出流并对它进行缓冲outBuff = new BufferedOutputStream(new FileOutputStream(targetFile));// 缓冲数组byte[] b = new byte[1024 * 5];int len;while ((len = inBuff.read(b)) != -1) {outBuff.write(b, 0, len);}// 刷新此缓冲的输出流outBuff.flush();} catch (Exception e) {System.out.println("复制文件失败:" + target_file_path);e.printStackTrace();} finally {// 关闭流if (inBuff != null)inBuff.close();if (outBuff != null)outBuff.close();}}}1、新建一个java工程,把上面的代码复制进去。

2、对着这个类点右键,选择Export-java-Runnable JAR file

3、在Launch configuration中,选择你所要导出的类(如果这里不能选择,那么你要run一下你的工程,run成功了才能选择你要导为jar的类),

假设导出的jar的名字是apktool.jar

路遥知马力,日久见人心。

分享一种最简单的Android打渠道包的方法

相关文章:

你感兴趣的文章:

标签云: