(点击上方公众号,可快速关注)
来源:伯乐在线专栏作者 - joe
链接:http://android.jobbole.com/84758/
点击 → 了解如何加入专栏作者
接上文
美团方式
上面说的反编译要各种解包,打包,签名,相对也比较繁琐,然后我们可以发现,apk其实都是一个压缩包,我们直接在这个压缩包里添加对应的文件作为渠道号标记是不是又能省去上面繁琐的步奏呢?!打开一个APK文件之后你会看到META-INF这个文件夹!
apk压缩包.png
META-INF.png
美团的方式就是在这里面直接再添加一个文件,然后通过这个文件的名称来指定对应的渠道号!
话不多说,直接上代码!!
public static void addUmengChannel(String filepath, String channel) {
String channel_title = "umengchannel_";
if(filepath.substring(filepath.lastIndexOf(".") + 1).toLowerCase().equals("apk")) {
String path2 = "";
if(filepath.lastIndexOf(File.separator) >= 0) {
path2 = filepath.substring(0, filepath.lastIndexOf(File.separator) + 1);//得到父路径
}
if(path2.length() != 0) {
File s = new File(filepath);//原始的apk
File t = new File(filepath.substring(0, filepath.lastIndexOf(".")) + "_" + channel + ".apk");//目标apk
if(!t.exists()) {//不存在就创建
try {
t.createNewFile();
} catch (IOException var12) {
var12.printStackTrace();
}
}
Utils.fileChannelCopy(s, t);//拷贝原始apk到目标apk
File addFile = new File(path2 + channel_title + channel);//需要添加的渠道文件
if(!addFile.exists()) {
try {
addFile.createNewFile();
} catch (IOException var11) {
var11.printStackTrace();
}
}
try {
Utils.addFileToExistingZip(t, addFile);//将新加的渠道文件添加到目标apk文件中
addFile.delete();
} catch (IOException var10) {
var10.printStackTrace();
}
}
}
}
public static void addFileToExistingZip(File zipFile, File file) throws IOException {
File tempFile = File.createTempFile(zipFile.getName(), (String)null);
tempFile.delete();
boolean renameOk = zipFile.renameTo(tempFile);//拷贝
if(!renameOk) {
throw new RuntimeException("could not rename the file " + zipFile.getAbsolutePath() + " to " + tempFile.getAbsolutePath());
} else {
byte[] buf = new byte[1024];
ZipInputStream zin = new ZipInputStream(new FileInputStream(tempFile));
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile));
for(ZipEntry entry = zin.getNextEntry(); entry != null; entry = zin.getNextEntry()) {
String in = entry.getName();
if(in.contains("umengchannel")) {//如果有重复的就不复制回去了!
continue;
}
out.putNextEntry(new ZipEntry(in));
int len1;
while((len1 = zin.read(buf)) > 0) {
out.write(buf, 0, len1);
}
}
zin.close();
FileInputStream in1 = new FileInputStream(file);
out.putNextEntry(new ZipEntry("META-INF/" + file.getName()));//创建对应的渠道文件
int len2;
while((len2 = in1.read(buf)) > 0) {
out.write(buf, 0, len2);
}
out.closeEntry();
in1.close();
out.close();
tempFile.delete();
}
}
渠道包完成.png
最后送上读取相关的方法:
public static String getChannel(Context context) {
ApplicationInfo appinfo = context.getApplicationInfo();
String sourceDir = appinfo.sourceDir;
String ret = "";
ZipFile zipfile = null;
try {
zipfile = new ZipFile(sourceDir);
Enumeration> entries = zipfile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = ((ZipEntry) entries.nextElement());
String entryName = entry.getName();
//这里需要替换成你的那个key
if (entryName.startsWith(YOUR_CHNANNEL_NAME)) {
ret = entryName;
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (zipfile != null) {
try {
zipfile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
String[] split = ret.split("_");
if (split != null && split.length >= 2) {
return ret.substring(split[0].length() + 1);
} else {
return "";
}
}
当然你肯定要手动设置了,这个没法直接在清单文件中去配置了!!
小结
主要的方式就是这三种了!可以说一个比一个快,一个比一个的定制也要高,效率提高了,灵活性似乎就会下降的,至于到底使用哪种方式,还是根据实际情况灵活选择吧,反正到现在,这些方案都是很成熟的,没有什么坑!一不小心又说了几句废话啊!
参考文档及Demo
1、美团Android自动化之旅—生成渠道包
2、GRADLE构建最佳实践 gradle也是很厉害的!
3、Android逆向之旅—反编译利器Apktool和Jadx源码分析以及错误纠正
4、github-AndroidUmengMultiChannelBuildTool
5、github-ApkCustomizationTool
6、github-AndroidMultiChannels
如有问题,欢迎拍砖 ~~~
—- Edit By Joe —-
专栏作者简介( 点击 → 加入专栏作者 )
joe:90后程序猿。。
打赏支持作者写出更多好文章,谢谢!
关注「安卓开发精选」
看更多精选安卓技术文章
↓↓↓