阿里云服务器免费领卷啦。

捡代码论坛-最全的游戏源码下载技术网站!

 找回密码
 立 即 注 册

QQ登录

只需一步,快速开始

搜索
关于源码区的附件失效或欺骗帖, 处理办法
查看: 2341|回复: 0

一种动态为apk写入信息的方案

[复制链接]

4208

主题

210

回帖

12万

积分

管理员

管理员

Rank: 9Rank: 9Rank: 9

积分
126180
QQ
发表于 2016-6-23 12:09:19 | 显示全部楼层 |阅读模式
背景

我们在日常使用应用可能会遇到以下场景。 场景1: 用户浏览h5页面时看到一个页面,下载安装app后启动会来到首页而不是用户之前浏览的页面,造成使用场景的割裂。

场景2: 用户通过二维码把一个页面分享出去,没有装猫客的用户如果直接安装启动之后无法回到分享的页面。

如果用户在当前页面下载了应用,安装之后直接跳转到刚才浏览的界面,不仅可以将这一部分流量引回客户端,还可以让用户获得完整的用户体验。下面提出一种方案来满足这个业务需求。

原理

android使用的apk包的压缩方式是zip,与zip有相同的文件结构,在zip的Central directory file header中包含一个File comment区域,可以存放一些数据。File comment是zip文件如果可以正确的修改这个部分,就可以在不破坏压缩包、不用重新打包的的前提下快速的给apk文件写入自己想要的数据。

comment是在Central directory file header末尾储存的,可以将数据直接写在这里,下是header末尾的结构。 header.png


由于数据是不确定的,我们无法知道comment的长度,从表中可以看到zip定义comment的长度的位置在comment之前,所以无法从zip中直接获取comment的长度。这里我们需要自定义comment的长度,在自定义comment内容的后面添加一个区域储存comment的长度,结构如下图。

comment.png




这里可以将一个固定的结构写在comment中,然后根据自定义的长度分区获取每个部分的内容,还可以添加其它数据,如校验码、版本等。

实现1.将数据写入comment

这一部分可以在本地进行,需要定义一个长度为2的byte[]来储存comment的长度,直接使用Java的api就可以把comment和comment的长度写到apk的末尾,代码如下。


  1. public static void writeApk(File file, String comment) {
  2.     ZipFile zipFile = null;
  3.     ByteArrayOutputStream outputStream = null;
  4.     RandomAccessFile accessFile = null;
  5.     try {
  6.         zipFile = new ZipFile(file);
  7.         String zipComment = zipFile.getComment();
  8.         if (zipComment != null) {
  9.             return;
  10.         }

  11.         byte[] byteComment = comment.getBytes();
  12.         outputStream = new ByteArrayOutputStream();

  13.         outputStream.write(byteComment);
  14.         outputStream.write(short2Stream((short) byteComment.length));

  15.         byte[] data = outputStream.toByteArray();

  16.         accessFile = new RandomAccessFile(file, "rw");
  17.         accessFile.seek(file.length() - 2);
  18.         accessFile.write(short2Stream((short) data.length));
  19.         accessFile.write(data);
  20.     } catch (IOException e) {
  21.         e.printStackTrace();
  22.     } finally {
  23.         try {
  24.             if (zipFile != null) {
  25.                 zipFile.close();
  26.             }
  27.             if (outputStream != null) {
  28.                 outputStream.close();
  29.             }
  30.             if (accessFile != null) {
  31.                 accessFile.close();
  32.             }
  33.         } catch (Exception e) {

  34.         }

  35.     }
  36. }
复制代码
2.读取apk包中的comment数据

首先获取apk的路径,通过context中的getPackageCodePath()方法就可以获取,代码如下。


  1. public static String getPackagePath(Context context) {
  2.     if (context != null) {
  3.         return context.getPackageCodePath();
  4.     }
  5.     return null;
  6. }
复制代码

获取路径之后就可以读取comment的内容了,这里不能直接使用ZipFile中的getComment()方法直接获取comment,因为这个方法是Java7中的方法,在android4.4之前是不支持Java7的,所以我们需要自己去读取apk文件中的comment。首先根据之前自定义的结构,先读取写在最后的comment的长度,根据这个长度,才可以获取真正comment的内容,代码如下。


  1. public static String readApk(File file) {
  2.     byte[] bytes = null;
  3.     try {
  4.         RandomAccessFile accessFile = new RandomAccessFile(file, "r");
  5.         long index = accessFile.length();

  6.         bytes = new byte[2];
  7.         index = index - bytes.length;
  8.         accessFile.seek(index);
  9.         accessFile.readFully(bytes);

  10.         int contentLength = stream2Short(bytes, 0);

  11.         bytes = new byte[contentLength];
  12.         index = index - bytes.length;
  13.         accessFile.seek(index);
  14.         accessFile.readFully(bytes);

  15.         return new String(bytes, "utf-8");
  16.     } catch (FileNotFoundException e) {
  17.         e.printStackTrace();
  18.     } catch (IOException e) {
  19.         e.printStackTrace();
  20.     }
  21.     return null;
  22. }
复制代码

这里的stream2Short()和short2Stream()参考了MultiChannelPackageTool中的方法。

测试

在生成apk后,调用下面的代码写入我们想要的数据,


  1. File file = new File("/Users/zhaolin/app-debug.apk");
  2. writeApk(file, "test comment");
复制代码

安装这个apk之后运行,让comment显示在屏幕上,运行结果如下。


screen.png

运行结果符合预期,安装包也没有被破坏,可以正常安装。
结论
  • 通过修改comment将数据传递给APP的方案是可行的,由于是修改apk自有的数据,并不会对apk造成破坏,修改后可以正常安装。
  • 这种方案不用重新打包apk,并且在服务端只是写文件的操作,效率很高,可以适用于动态生成apk的场景。
  • 可以通过这个方案进行h5到APP的引流,用户操作不会产生割裂感,保证用户体验的统一。
参考

捡代码论坛-最全的游戏源码下载技术网站! - 论坛版权郑重声明:
1、本主题所有言论和图片纯属会员个人意见,与本论坛立场无关
2、本站所有主题由该帖子作者发表,该帖子作者与捡代码论坛-最全的游戏源码下载技术网站!享有帖子相关版权
3、捡代码论坛版权,详细了解请点击。
4、本站所有内容均由互联网收集整理、网友上传,并且以计算机技术研究交流为目的,仅供大家参考、学习,不存在任何商业目的与商业用途。
5、若您需要商业运营或用于其他商业活动,请您购买正版授权并合法使用。 我们不承担任何技术及版权问题,且不对任何资源负法律责任。
6、如无法链接失效或侵犯版权,请给我们来信:jiandaima@foxmail.com

回复

使用道具 举报

*滑块验证:
您需要登录后才可以回帖 登录 | 立 即 注 册

本版积分规则

技术支持
在线咨询
QQ咨询
3351529868

QQ|手机版|小黑屋|捡代码论坛-专业源码分享下载 ( 陕ICP备15015195号-1|网站地图

GMT+8, 2024-4-26 12:52

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表