更改已经签名的app中的内容

转载请说明出处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
plain
copy

  1. File file = new File("d:/app/assets/id.txt");
  2. OutputStream outputStream = new FileOutputStream(file);
  3. outputStream.write(user.getId().toString().getBytes());
  4. outputStream.flush();
  5. outputStream.close();

第三步:压缩写入渠道商id后的所有app文件

[java] view
plain
copy

  1. ZipCompressor zc = new  ZipCompressor("d:/play.apk");
  2. zc.compressExe("d:/app/");

具体的压缩代码如下:

[java] view
plain
copy

  1. package com.xyc.signSystem.utils;
  2. import java.io.BufferedInputStream;
  3. import java.io.File;
  4. import java.io.FileInputStream;
  5. import java.io.FileOutputStream;
  6. import java.util.zip.CRC32;
  7. import java.util.zip.CheckedOutputStream;
  8. import org.apache.tools.zip.ZipEntry;
  9. import org.apache.tools.zip.ZipOutputStream;
  10. /**
  11. * @ClassName: ZipCompressor
  12. * @author :andywuchuanlong   QQ:312037487
  13. * @Description: 压缩文件的通用工具类-采用org.apache.tools.zip.ZipOutputStream实现,较复杂。
  14. *
  15. */
  16. public class ZipCompressor {
  17. static final int BUFFER = 8192;
  18. private File zipFile;
  19. /**
  20. * 压缩文件构造函数
  21. *
  22. * @param pathName
  23. *            压缩的文件存放目录
  24. */
  25. public ZipCompressor(String pathName) {
  26. zipFile = new File(pathName);
  27. }
  28. /**
  29. * 执行压缩操作
  30. *
  31. * @param srcPathName
  32. *            被压缩的文件/文件夹
  33. */
  34. public void compressExe(String srcPathName) {
  35. File file = new File(srcPathName);
  36. if (!file.exists()) {
  37. throw new RuntimeException(srcPathName + "不存在!");
  38. }
  39. try {
  40. FileOutputStream fileOutputStream = new FileOutputStream(zipFile);
  41. CheckedOutputStream cos = new CheckedOutputStream(fileOutputStream,
  42. new CRC32());
  43. ZipOutputStream out = new ZipOutputStream(cos);
  44. String basedir = "";
  45. compressByType(file, out, basedir);
  46. out.close();
  47. } catch (Exception e) {
  48. e.printStackTrace();
  49. throw new RuntimeException(e);
  50. }
  51. }
  52. /**
  53. * 判断是目录还是文件,根据类型(文件/文件夹)执行不同的压缩方法
  54. *
  55. * @param file
  56. * @param out
  57. * @param basedir
  58. */
  59. private void compressByType(File file, ZipOutputStream out, String basedir) {
  60. if (basedir.equals("play/")) {
  61. basedir = "";
  62. }
  63. /* 判断是目录还是文件 */
  64. if (file.isDirectory()) {
  65. this.compressDirectory(file, out, basedir);
  66. } else {
  67. this.compressFile(file, out, basedir);
  68. }
  69. }
  70. boolean isFirst = true;
  71. /**
  72. * 压缩一个目录
  73. *
  74. * @param dir
  75. * @param out
  76. * @param basedir
  77. */
  78. private void compressDirectory(File dir, ZipOutputStream out, String basedir) {
  79. if (!dir.exists()) {
  80. return;
  81. }
  82. if (basedir.equals("play/")) {
  83. basedir = "";
  84. }
  85. File[] files = dir.listFiles();
  86. for (int i = 0; i < files.length; i++) {
  87. /* 递归 */
  88. compressByType(files[i], out, basedir + dir.getName() + "/");
  89. }
  90. }
  91. /**
  92. * 压缩一个文件
  93. *
  94. * @param file
  95. * @param out
  96. * @param basedir
  97. */
  98. private void compressFile(File file, ZipOutputStream out, String basedir) {
  99. if (!file.exists()) {
  100. isFirst = false;
  101. return;
  102. }
  103. if (basedir.equals("play/")) {
  104. basedir = "";
  105. }
  106. try {
  107. BufferedInputStream bis = new BufferedInputStream(
  108. new FileInputStream(file));
  109. ZipEntry entry = new ZipEntry(basedir + file.getName());
  110. out.putNextEntry(entry);
  111. int count;
  112. byte data[] = new byte[BUFFER];
  113. while ((count = bis.read(data, 0, BUFFER)) != -1) {
  114. out.write(data, 0, count);
  115. }
  116. bis.close();
  117. } catch (Exception e) {
  118. throw new RuntimeException(e);
  119. }
  120. }
  121. }

第四步:压缩完毕之后,此时的包是没有签名过的,所以还需要签名,签名可以使用jarsigner工具,首先我们要寻找到java的安装目录

[java] view
plain
copy

  1. <span style="white-space:pre">    </span>public  String getJavaPath() {
  2. String javaPath = (String) System.getenv("Path");
  3. String paths[]= javaPath.split(";");
  4. String myPath = null;
  5. for(String path:paths){
  6. if (path.contains("Java")&&!path.contains("jre")
  7. &&path.contains("bin") ){
  8. myPath = path;
  9. break;
  10. }
  11. }
  12. return myPath+"\\";
  13. }

签名:

[java] view
plain
copy

  1. <span style="white-space:pre">    </span>String javaPath = getJavaPath();
  2. Runtime rt = Runtime.getRuntime();
  3. String cmd = javaPath
  4. + "jarsigner -verbose"
  5. + " -keystore "+ keystorePath
  6. + " -storepass player"// 密码
  7. + " -signedjar "+signedApkPath // 签名后的apk存放位置
  8. + " -digestalg SHA1  -sigalg  MD5withRSA "
  9. + unsignedApkPath//未签名的apk
  10. + " player";// 别名
  11. Process child = rt.exec(cmd);

OK,签名成功。

时间: 2025-01-17 04:43:29

更改已经签名的app中的内容的相关文章

嵌入式表单字段中的内容可能被服务器更改以删除不安全的内容。是否要重新加载您的页面以查看保存结果?

嵌入式表单字段中的内容可能被服务器更改以删除不安全的内容.是否要重新加载您的页面以查看保存结果? 最近有朋友问到,当他在SharePoint首页上进行编辑时,插入一段代码.完工后保存就遇到了这个问题. 无论选"是"或"否",保存完毕后在设计视图中都看不到效果,查看代码视图,对应的代码也被删除掉了. 这确实是很恼人,好不容易写了那么多东西,结果最后被SPD自己搞没了,如果之前备份了还好,否则,大半天的成果就不翼而飞了. 首先,关于这个问题的定性要清楚.它不是一个错误:

Python抓取手机APP中内容

首先下载Wireshark和模拟器(天天模拟器,夜神模拟器),天天模拟器在自带的应用商店里面能够登录微信. 然后打开Wireshark选择一个网卡开始抓包. 开始抓包后,在模拟器中要抓取的APP中对想要的资源进行点击访问,操作完成后停止捕捉,排除干扰. Filter用于过滤数据,在里面输入选择的过滤条件.相关的语法和设置可以在网上查找资料,这里干扰项较少,直接选出http协议的数据包. 点击所需要的数据进行分析,可以将里面的字段复制出来构造Header然后对资源进行访问. 1 # coding:

JSPatch来更新已上线的App中出现的BUG(超级详细)

JSPatch来更新已上线的App中出现的BUG(超级详细) 字数2858 阅读422 评论15 喜欢29 JSPatch的作用是什么呢? 简单来说:(后面有具体的操作步骤以及在操作过程中会出现的错误) 1.iOS应用程序上架到AppStore需要等待苹果公司的审核,一般审核时间需要1到2周.虽然程序在上架前会经过测试人员的测试,但有时候还是不免会发生新版本上线后出现严重的bug,导致用户刚升级到新版本就出现crash,严重影响用户体验. 2.这时能做的只是赶紧修复bug然后提交等待漫长的App

[Phonegap+Sencha Touch] 移动开发77 Cordova Hot Code Push插件实现自己主动更新App的Web内容

原文地址:http://blog.csdn.net/lovelyelfpop/article/details/50848524 插件地址:https://github.com/nordnet/cordova-hot-code-push 以下是我对GitHub项目readme的翻译 ---------------------------------------------- Cordova Hot Code Push Plugin 此插件提供了能够使cordova app自己主动更新web内容的功

自己动手去除app中谷歌广告

最近想去研究一下去除app中的谷歌广告,由于换了手机,且使用安卓6.0系统,暂时不能root安装辅助软件. 前言: 查看了很多网络文章,一般都是两种方法:把显示广告大小的参数改为0,或是修改广告访问的连接为无效连接,前一种比较通用且简单,后一种比较费功夫,但是更节省流量和系统资源 ,然后发现网络上的文章大多是转载的,且转载文章的人没有检测实际效果和实验环境,没有备注实验时间,这样很多转载的文章只是提供一个思路,但已经达不到效果了,所以只好重新研究一下,因为我没有系统学习java语言,只能看到什么

iOS利用HealthKit框架从健康app中获取步数信息

微信和QQ的每日步数最近十分火爆,我就想为自己写的项目中添加一个显示每日步数的功能,上网一搜好像并有相关的详细资料,自己动手丰衣足食. 统计步数信息并不需要我们自己去实现,iOS自带的健康app已经为我们统计好了步数数据 我们只要使用HealthKit框架从健康app中获取这个数据信息就可以了 这篇文章对HealthKit框架进行了简单的介绍:http://www.cocoachina.com/ios/20140915/9624.html 对HealthKit框架有了简单的了解后我们就可以开始了

在 C# App 中嵌入 Chrome 浏览器使用 CefSharp

介绍 以前曾试过在app中整合一个可靠又快速的web浏览器吗? 在本文中,你会学到如何轻松地将奇妙的CefSharp网页浏览器组件(基于Chromium)集成到你的C# app中. 然后,你可以使用此web浏览器: 给用户提供一个集成的浏览体验 用HTML / JavaScript编程添加嵌入式界面 用于web自动化 CefSharp可靠,快速,完全开源,不需要任何额外的依赖就可以安装到最终用户(除VC ++ Runtime 2013以外). 在本指南中,我们将使用WinForms项目,但Cef

总结XX网app中webapp常见的前端错误。

在2016年12月至2017年1月,这一个月的时间内,我参与了易政网app中webapp前端项目的工作,下面将我在此次项目中犯的错误总结起来,以防下次再犯. 注意点 一:复用 可复用的地方一定要复用,不然后期改样式会累死... 二:防止类名冲突 在写类名的时候最好加个前缀,不然在后期可能会有css文件合并,到时候有类名冲突就尴尬了... 三:外链导入 js和css文件最好用外链式导入,如果直接放在html中不好查看,(如果其中有的样式没有用到,jsp会报错). 四:跟标准 项目标准一定要统一好,

1.关于QT中的Graphics绘图,定时器,动画,将窗口中的内容打印到图片上,打印机,打印预览

 1 新建项目 A  修改pro中的内容如下: HEADERS += \ MyWidget.h SOURCES += \ MyWidget.cpp QT += gui widgets printsupport B  编写MyWidget.h #ifndef MYWIDGET_H #define MYWIDGET_H   #include <QWidget> #include <QGraphicsScene> #include <QGraphicsLineItem>