();
37 | for (String channel : channels) {
38 | channel = channel.trim().replace("\n", "");
39 | String appName = srcApkFile.getName().substring(0, srcApkFile.getName().lastIndexOf("."));
40 | String apkFileName = appName + "-" + channel + ".apk";
41 | File parentFile = srcApkFile.getParentFile();
42 | File apkTargetFile = new File(parentFile, apkFileName);
43 | //拷贝apk
44 | FileUtils.copy(srcApkFile, apkTargetFile);
45 | //修改渠道
46 | boolean b = buildChannel(apkTargetFile.getAbsolutePath(), channelPrefix, channel);
47 | if ( b ) {
48 | resultFileList.add(apkTargetFile);
49 | }
50 | }
51 | return resultFileList;
52 | }
53 |
54 | /**
55 | * 修改渠道号
56 | *
57 | * demo: changeChannel("xxx../../my.apk", "hiapk");
58 | *
59 | *
60 | * @param zipFilename apk文件
61 | * @param channel 新渠道号
62 | * @return true or false
63 | */
64 | public static boolean buildChannel(String zipFilename, String channelPrefix, String channel) {
65 | try (FileSystem zipfs = createZipFileSystem(zipFilename, false)) {
66 | String channelBegin = "/META-INF/" + channelPrefix;
67 | String channelFlagName = channelBegin + channel;
68 |
69 | final Path root = zipfs.getPath("/META-INF/");
70 | ChannelFileVisitor visitor = new ChannelFileVisitor(channelBegin);
71 | Files.walkFileTree(root, visitor);
72 |
73 | Path existChannel = visitor.getChannelFile();
74 | Path newChannel = zipfs.getPath(channelFlagName);
75 | if (existChannel!=null) {
76 | Files.move(existChannel, newChannel, StandardCopyOption.ATOMIC_MOVE);
77 | } else {
78 | Files.createFile(newChannel);
79 | }
80 |
81 | return true;
82 |
83 | } catch (IOException e) {
84 | e.printStackTrace();
85 | }
86 |
87 | return false;
88 | }
89 |
90 | private static FileSystem createZipFileSystem(String zipFilename, boolean create) throws IOException {
91 | final Path path = Paths.get(zipFilename);
92 | final URI uri = URI.create("jar:file:" + path.toUri().getPath());
93 |
94 | final Map env = new HashMap<>();
95 | if (create) {
96 | env.put("create", "true");
97 | }
98 | return FileSystems.newFileSystem(uri, env);
99 | }
100 |
101 | private static class ChannelFileVisitor extends SimpleFileVisitor {
102 | private Path channelFile;
103 | private PathMatcher matcher;
104 |
105 | public ChannelFileVisitor(String channelBegin) {
106 | String channelFlagNameMatcher = "regex:" + channelBegin + "[0-9a-zA-Z]{1,5}";
107 | matcher = FileSystems.getDefault().getPathMatcher(channelFlagNameMatcher);
108 | }
109 |
110 | public Path getChannelFile() {
111 | return channelFile;
112 | }
113 |
114 | @Override
115 | public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
116 | if (matcher.matches(file)) {
117 | channelFile = file;
118 | return FileVisitResult.TERMINATE;
119 | } else {
120 | return FileVisitResult.CONTINUE;
121 | }
122 | }
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/web-build/AndroidChannelBuild/src/cn/finalteam/androidchannelbuild/utils/FileUtils.java:
--------------------------------------------------------------------------------
1 | package cn.finalteam.androidchannelbuild.utils;
2 |
3 | import java.io.File;
4 | import java.io.FileInputStream;
5 | import java.io.FileOutputStream;
6 | import java.io.IOException;
7 | import java.nio.channels.FileChannel;
8 | /**
9 | *
10 | * @author pengjianbo
11 | *
12 | */
13 | public class FileUtils {
14 |
15 | public static String getFileExtension(String filePath) {
16 | if (filePath == null || filePath.trim().length() == 0) {
17 | return filePath;
18 | }
19 |
20 | int extenPosi = filePath.lastIndexOf(".");
21 | int filePosi = filePath.lastIndexOf(File.separator);
22 | if (extenPosi == -1) {
23 | return "";
24 | }
25 | return (filePosi >= extenPosi) ? "" : filePath.substring(extenPosi + 1);
26 | }
27 |
28 | public static boolean makeDirs(String filePath) {
29 | String folderName = getFolderName(filePath);
30 | if (folderName == null || folderName.trim().length() == 0) {
31 | return false;
32 | }
33 |
34 | File folder = new File(folderName);
35 | return (folder.exists() && folder.isDirectory()) ? true : folder.mkdirs();
36 | }
37 |
38 | public static String getFolderName(String filePath) {
39 |
40 | if (filePath == null || filePath.trim().length() == 0) {
41 | return filePath;
42 | }
43 |
44 | int filePosi = filePath.lastIndexOf(File.separator);
45 | return (filePosi == -1) ? "" : filePath.substring(0, filePosi);
46 | }
47 |
48 | public static String getFileNameWithoutExtension(String filePath) {
49 | if (filePath == null || filePath.trim().length() == 0) {
50 | return filePath;
51 | }
52 |
53 | int extenPosi = filePath.lastIndexOf(".");
54 | int filePosi = filePath.lastIndexOf(File.separator);
55 | if (filePosi == -1) {
56 | return (extenPosi == -1 ? filePath : filePath.substring(0, extenPosi));
57 | }
58 | if (extenPosi == -1) {
59 | return filePath.substring(filePosi + 1);
60 | }
61 | return (filePosi < extenPosi ? filePath.substring(filePosi + 1, extenPosi) : filePath.substring(filePosi + 1));
62 | }
63 |
64 | /**
65 | * 使用文件通道的方式复制文件
66 | * @param s 源文件
67 | * @param t复制到的新文件
68 | */
69 | public static void copy(File sourceFile, File targeFile) {
70 | FileInputStream fi = null;
71 | FileOutputStream fo = null;
72 | FileChannel in = null;
73 | FileChannel out = null;
74 | try {
75 | fi = new FileInputStream(sourceFile);
76 | fo = new FileOutputStream(targeFile);
77 | in = fi.getChannel();// 得到对应的文件通道
78 | out = fo.getChannel();// 得到对应的文件通道
79 | in.transferTo(0, in.size(), out);// 连接两个通道,并且从in通道读取,然后写入out通道
80 | } catch (IOException e) {
81 | e.printStackTrace();
82 | } finally {
83 | try {
84 | fi.close();
85 | in.close();
86 | fo.close();
87 | out.close();
88 | } catch (IOException e) {
89 | e.printStackTrace();
90 | }
91 | }
92 |
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/web-build/AndroidChannelBuild/src/cn/finalteam/androidchannelbuild/utils/MultiZipDownloadUtil.java:
--------------------------------------------------------------------------------
1 | package cn.finalteam.androidchannelbuild.utils;
2 |
3 | import java.io.BufferedInputStream;
4 | import java.io.BufferedOutputStream;
5 | import java.io.File;
6 | import java.io.FileInputStream;
7 | import java.io.FileOutputStream;
8 | import java.io.IOException;
9 | import java.io.InputStream;
10 | import java.io.OutputStream;
11 | import java.net.URLEncoder;
12 | import java.util.List;
13 | import java.util.zip.ZipEntry;
14 | import java.util.zip.ZipOutputStream;
15 |
16 | import javax.servlet.http.HttpServletRequest;
17 | import javax.servlet.http.HttpServletResponse;
18 | /**
19 | *
20 | * @author pengjianbo
21 | *
22 | */
23 | public class MultiZipDownloadUtil {
24 |
25 | /**
26 | * 文件打包下载
27 | * @param files
28 | * @param zipFile
29 | * @param request
30 | * @param response
31 | * @return
32 | * @throws Exception
33 | */
34 | public static HttpServletResponse downLoadFiles(List files,
35 | File zipFile, HttpServletRequest request,
36 | HttpServletResponse response) throws Exception {
37 | try {
38 |
39 | /**
40 | * 创建一个临时压缩文件, 我们会把文件流全部注入到这个文件中 这里的文件你可以自定义是.rar还是.zip
41 | */
42 | zipFile.delete();
43 | if (!zipFile.exists()) {
44 | zipFile.createNewFile();
45 | }
46 | response.reset();
47 | // response.getWriter()
48 | // 创建文件输出流
49 | FileOutputStream fous = new FileOutputStream(zipFile);
50 | /**
51 | * 打包的方法我们会用到ZipOutputStream这样一个输出流, 所以这里我们把输出流转换一下
52 | */
53 | ZipOutputStream zipOut = new ZipOutputStream(fous);
54 | /**
55 | * 这个方法接受的就是一个所要打包文件的集合, 还有一个ZipOutputStream
56 | */
57 | zipFile(files, zipOut);
58 | zipOut.close();
59 | fous.close();
60 | return downloadZip(zipFile, response);
61 | } catch (Exception e) {
62 | e.printStackTrace();
63 | }
64 | /**
65 | * 直到文件的打包已经成功了, 文件的打包过程被我封装在FileUtil.zipFile这个静态方法中,
66 | * 稍后会呈现出来,接下来的就是往客户端写数据了
67 | */
68 |
69 | return response;
70 | }
71 |
72 | /**
73 | * 把接受的全部文件打成压缩包
74 | *
75 | * @param List
76 | * ;
77 | * @param org
78 | * .apache.tools.zip.ZipOutputStream
79 | */
80 | public static void zipFile(List files, ZipOutputStream outputStream) {
81 | int size = files.size();
82 | for (int i = 0; i < size; i++) {
83 | File file = (File) files.get(i);
84 | zipFile(file, outputStream);
85 | }
86 | }
87 |
88 | public static HttpServletResponse downloadZip(File file,
89 | HttpServletResponse response) {
90 | try {
91 | // 以流的形式下载文件。
92 | InputStream fis = new BufferedInputStream(new FileInputStream(
93 | file.getPath()));
94 | byte[] buffer = new byte[fis.available()];
95 | fis.read(buffer);
96 | fis.close();
97 | // 清空response
98 | response.reset();
99 |
100 | OutputStream toClient = new BufferedOutputStream(
101 | response.getOutputStream());
102 | response.setContentType("application/octet-stream");
103 |
104 | // 如果输出的是中文名的文件,在此处就要用URLEncoder.encode方法进行处理
105 | response.setHeader("Content-Disposition", "attachment;filename="
106 | + URLEncoder.encode(file.getName(), "UTF-8"));
107 | toClient.write(buffer);
108 | toClient.flush();
109 | toClient.close();
110 | } catch (IOException ex) {
111 | ex.printStackTrace();
112 | } finally {
113 | try {
114 | File f = new File(file.getPath());
115 | f.delete();
116 | } catch (Exception e) {
117 | e.printStackTrace();
118 | }
119 | }
120 | return response;
121 | }
122 |
123 | /**
124 | * 根据输入的文件与输出流对文件进行打包
125 | *
126 | * @param File
127 | * @param org
128 | * .apache.tools.zip.ZipOutputStream
129 | */
130 | public static void zipFile(File inputFile, ZipOutputStream ouputStream) {
131 | try {
132 | if (inputFile.exists()) {
133 | /**
134 | * 如果是目录的话这里是不采取操作的, 至于目录的打包正在研究中
135 | */
136 | if (inputFile.isFile()) {
137 | FileInputStream IN = new FileInputStream(inputFile);
138 | BufferedInputStream bins = new BufferedInputStream(IN, 512);
139 | // org.apache.tools.zip.ZipEntry
140 | ZipEntry entry = new ZipEntry(inputFile.getName());
141 | ouputStream.putNextEntry(entry);
142 | // 向压缩文件中输出数据
143 | int nNumber;
144 | byte[] buffer = new byte[512];
145 | while ((nNumber = bins.read(buffer)) != -1) {
146 | ouputStream.write(buffer, 0, nNumber);
147 | }
148 | // 关闭创建的流对象
149 | bins.close();
150 | IN.close();
151 | } else {
152 | try {
153 | File[] files = inputFile.listFiles();
154 | for (int i = 0; i < files.length; i++) {
155 | zipFile(files[i], ouputStream);
156 | }
157 | } catch (Exception e) {
158 | e.printStackTrace();
159 | }
160 | }
161 | }
162 | } catch (Exception e) {
163 | e.printStackTrace();
164 | }
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/web-build/build-config.properties:
--------------------------------------------------------------------------------
1 | #配置渠道识别前缀
2 | channel.prefix = channel-
3 |
--------------------------------------------------------------------------------