转载请说明出处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
[java] view
plaincopy
- 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文件
[java] view
plaincopy
- ZipCompressor zc = new ZipCompressor("d:/play.apk");
- zc.compressExe("d:/app/");
具体的压缩代码如下:
[java] view
plaincopy
- 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;
- /**
- * @ClassName: ZipCompressor
- * @author :andywuchuanlong QQ:312037487
- * @Description: 压缩文件的通用工具类-采用org.apache.tools.zip.ZipOutputStream实现,较复杂。
- *
- */
- public class ZipCompressor {
- static final int BUFFER = 8192;
- private File zipFile;
- /**
- * 压缩文件构造函数
- *
- * @param pathName
- * 压缩的文件存放目录
- */
- public ZipCompressor(String pathName) {
- zipFile = new File(pathName);
- }
- /**
- * 执行压缩操作
- *
- * @param srcPathName
- * 被压缩的文件/文件夹
- */
- 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);
- }
- }
- /**
- * 判断是目录还是文件,根据类型(文件/文件夹)执行不同的压缩方法
- *
- * @param file
- * @param out
- * @param basedir
- */
- 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;
- /**
- * 压缩一个目录
- *
- * @param dir
- * @param out
- * @param basedir
- */
- 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() + "/");
- }
- }
- /**
- * 压缩一个文件
- *
- * @param file
- * @param out
- * @param basedir
- */
- 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的安装目录
[java] view
plaincopy
- <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+"\\";
- }
签名:
[java] view
plaincopy
- <span style="white-space:pre"> </span>String javaPath = getJavaPath();
- Runtime rt = Runtime.getRuntime();
- String cmd = javaPath
- + "jarsigner -verbose"
- + " -keystore "+ keystorePath
- + " -storepass player"// 密码
- + " -signedjar "+signedApkPath // 签名后的apk存放位置
- + " -digestalg SHA1 -sigalg MD5withRSA "
- + unsignedApkPath//未签名的apk
- + " player";// 别名
- Process child = rt.exec(cmd);
OK,签名成功。
时间: 2025-01-17 04:43:29