转载请说明出处http://blog.csdn.net/andywuchuanlong
记得上次在南昌中兴的一个项目中遇到过一个这样的需求:一个app可以给多个渠道商去运营,渠道商推广出去可以获得相应的推广金额。那么这种情况下就必须要使得这个app能够唯一的标志一个渠道商。那个时候我们在这个项目中的解决方案是:让用户在app中手动填入渠道商的工号,我现在想想这种方式也是醉了,真不知道那个时候项目经理是怎么想的,竟然会给出这样的方案。
这次的项目中又遇到了这个问题:需求是这个app能够给多个渠道商去推广,渠道商可以获得推广金额。这次我提出的解决方案是:先把打包后的app解压,然后在assets目录中写入渠道商的唯一标识id,然后压缩app,压缩完毕重新签名app,之后就大工告成。用户在第一次进入app的时候,会把assets中的id读出来,提交到服务器,就完美的解决了这个用户是此渠道商的推广所获得的用户。
首先第一步:把app解压,删除META-INF文件夹中的CERT.RSA和CERT.SF两个文件
第二步:读取解压后的assets目录中的id.txt文件,写入渠道商的id
-
File file = new File("d:/app/assets/id.txt");
-
OutputStream outputStream = new FileOutputStream(file);
-
outputStream.write(user.getId().toString().getBytes());
-
outputStream.flush();
-
outputStream.close();
第三步:压缩写入渠道商id后的所有app文件
-
ZipCompressor zc = new ZipCompressor("d:/play.apk");
-
zc.compressExe("d:/app/");
具体的压缩代码如下:
-
package com.xyc.signSystem.utils;
-
import java.io.BufferedInputStream;
-
import java.io.File;
-
import java.io.FileInputStream;
-
import java.io.FileOutputStream;
-
import java.util.zip.CRC32;
-
import java.util.zip.CheckedOutputStream;
-
-
import org.apache.tools.zip.ZipEntry;
-
import org.apache.tools.zip.ZipOutputStream;
-
-
-
-
-
-
-
-
public class ZipCompressor {
-
static final int BUFFER = 8192;
-
private File zipFile;
-
-
-
-
-
-
-
-
public ZipCompressor(String pathName) {
-
zipFile = new File(pathName);
-
}
-
-
-
-
-
-
-
-
public void compressExe(String srcPathName) {
-
File file = new File(srcPathName);
-
if (!file.exists()) {
-
throw new RuntimeException(srcPathName + "不存在!");
-
}
-
try {
-
FileOutputStream fileOutputStream = new FileOutputStream(zipFile);
-
CheckedOutputStream cos = new CheckedOutputStream(fileOutputStream,
-
new CRC32());
-
ZipOutputStream out = new ZipOutputStream(cos);
-
String basedir = "";
-
compressByType(file, out, basedir);
-
out.close();
-
} catch (Exception e) {
-
e.printStackTrace();
-
throw new RuntimeException(e);
-
}
-
}
-
-
-
-
-
-
-
-
-
private void compressByType(File file, ZipOutputStream out, String basedir) {
-
if (basedir.equals("play/")) {
-
basedir = "";
-
}
-
-
if (file.isDirectory()) {
-
this.compressDirectory(file, out, basedir);
-
} else {
-
this.compressFile(file, out, basedir);
-
}
-
}
-
-
boolean isFirst = true;
-
-
-
-
-
-
-
-
-
private void compressDirectory(File dir, ZipOutputStream out, String basedir) {
-
if (!dir.exists()) {
-
return;
-
}
-
if (basedir.equals("play/")) {
-
basedir = "";
-
}
-
File[] files = dir.listFiles();
-
for (int i = 0; i < files.length; i++) {
-
-
compressByType(files[i], out, basedir + dir.getName() + "/");
-
}
-
}
-
-
-
-
-
-
-
-
-
private void compressFile(File file, ZipOutputStream out, String basedir) {
-
if (!file.exists()) {
-
isFirst = false;
-
return;
-
}
-
if (basedir.equals("play/")) {
-
basedir = "";
-
}
-
try {
-
BufferedInputStream bis = new BufferedInputStream(
-
new FileInputStream(file));
-
ZipEntry entry = new ZipEntry(basedir + file.getName());
-
out.putNextEntry(entry);
-
int count;
-
byte data[] = new byte[BUFFER];
-
while ((count = bis.read(data, 0, BUFFER)) != -1) {
-
out.write(data, 0, count);
-
}
-
bis.close();
-
} catch (Exception e) {
-
throw new RuntimeException(e);
-
}
-
}
-
}
第四步:压缩完毕之后,此时的包是没有签名过的,所以还需要签名,签名可以使用jarsigner工具,首先我们要寻找到java的安装目录
-
<span style="white-space:pre"> </span>public String getJavaPath() {
-
String javaPath = (String) System.getenv("Path");
-
String paths[]= javaPath.split(";");
-
String myPath = null;
-
for(String path:paths){
-
if (path.contains("Java")&&!path.contains("jre")
-
&&path.contains("bin") ){
-
myPath = path;
-
break;
-
}
-
}
-
return myPath+"\\";
-
}
签名:
-
<span style="white-space:pre"> </span>String javaPath = getJavaPath();
-
Runtime rt = Runtime.getRuntime();
-
String cmd = javaPath
-
+ "jarsigner -verbose"
-
+ " -keystore "+ keystorePath
-
+ " -storepass player"
-
+ " -signedjar "+signedApkPath
-
+ " -digestalg SHA1 -sigalg MD5withRSA "
-
+ unsignedApkPath
-
+ " player";
-
Process child = rt.exec(cmd);
OK,签名成功。
更改已经签名的app中的内容
原文:http://blog.csdn.net/andywuchuanlong/article/details/46680635