A scheme for dynamically writing information to an APK

Source: Internet
Author: User

Ext.: http://mp.weixin.qq.com/s?__biz=MzA4MjA0MTc4NQ==&mid=2651573362&idx=1&sn= 13efa1c620fdad6d61494d04ffa78525&scene=23&srcid=0512rv3jrjyhnf3kdcwgqpmt#rd

1. Background

We may encounter the following scenarios in our daily use of the app.


Scenario 1: When users browse the H5 page, download the install App via the page download link, and launch the H5 page that will go to the homepage instead of the user, resulting in a fragmented use of the scene.
Scenario 2: The user through the QR code to share a page, no cat guest users if the direct installation after the launch, unable to return to the shared page.

If the user downloads the app on the current page, the installation jumps directly to the interface you just browsed, which will not only bring this part of traffic back to the client, but also give the user a complete user experience. A scenario is presented below to meet this business requirement.

2. Principle

Android APK Package compression method is zip, and zip has the same file structure, at the end of the zip file has a central Directory Record area, the end of which contains a file comment area, can hold some data, so File comment is a part of the zip file, if you can correctly modify this section, you can not destroy the package, without repackaging the premise of quickly write to the APK file the data you want.

Comment is stored at the end of the central Directory Record and can be written directly here, and the following table is the structure at the end of the header.



You can see from the table that the field defining the comment length is before comment, and when we start reading from the last file, since the comment data is indeterminate, we cannot know its length and thus cannot get comment length directly from the zip.

Here we need to customize the comment to add the length of a region stored comment after the custom comment content, such as the structure.



Here, you can write a fixed structure in comment, and then get the contents of each section based on the custom length partition, and add other data, such as checksum, version, and so on.

3. Implement 1 server to write data to APK comment

This section can be done locally or on the server, need to define a length of 2 byte[] to store the length of the comment, directly using the Java API can write comment and comment length to the end of the APK, the code is as follows:


read comment data in 2 Apk

First get the APK path, through the context of the Getpackagecodepath () method can be obtained, the code is as follows:

After getting the APK path, you can read the contents of the comment, and it is not possible to get comment directly using the Getcomment () method in ZipFile, because this method is a method in Java7, android4.4 is not supported before JAVA7 , so we need to read the comment in the Apk file ourselves. First, according to the previous custom structure, first read the length of the last comment, according to this length, can get the real comment content, the code is as follows:

The Stream2short () and Short2stream () here refer to the methods in Multichannelpackagetool.

4. Testing

After the APK is generated, call the following code to write the data we want,

After installing this Apk run, let comment display on the screen, run the result as follows.


The running result is expected and the installation package is not damaged and can be installed properly.

5. Conclusion

It is possible to modify the comment to pass the data to the APP, because it modifies the APK's own data and does not cause damage to the APK, which can be installed properly after modification.


This solution does not need to repackage the APK, and on the server is just writing file operations, high efficiency, can be used to dynamically generate the APK scene.

Through this program can be H5 to the application of drainage, user operation will not create a sense of fragmentation, to ensure the unity of user experience.

6. Reference

Https://github.com/mcxiaoke/packer-ng-plugin

Https://github.com/seven456/MultiChannelPackageTool

Test code:

Write apk

/** * */package com.writeapk;import java.io.bytearrayoutputstream;import java.io.file;import java.io.IOException; Import Java.io.randomaccessfile;import Java.io.unsupportedencodingexception;import Java.net.urlencoder;import Java.nio.bytebuffer;import Java.nio.byteorder;import java.util.zip.zipfile;/** * Class Description: * @author Lizy * @date 2016-  5-12 * @version 1.0.0 */public class writeapk {/** * @param args */public static void main (string[] args) {String FilePath = ".. /APP-DEBUG.APK "; String comment = "Hello comment!";  try {comment = Urlencoder.encode (comment, "Utf-8"),} catch (Unsupportedencodingexception e) {//TODO auto-generated catch Blocke.printstacktrace ();} writeapk (New File (FilePath), comment);} public static void writeapk (File file,string comment) {ZipFile zipfile = null; Bytearrayoutputstream Outputstrean = null; Randomaccessfile Accessfile = null;try {zipfile = new ZipFile (file); String zipcomment = Zipfile.getcomment (); if (zipcomment! = null) {return;} byte[] Bytecomment = COMMENT.GEtbytes (); Outputstrean = new Bytearrayoutputstream (); Outputstrean.write (bytecomment); Outputstrean.write ( Short2stream (short) bytecomment.length); byte[] data = Outputstrean.tobytearray (); accessfile = new Randomaccessfile ( File, "RW"); Accessfile.seek (File.length ()-2); Accessfile.write (Short2stream ((short) data.length)); Accessfile.write (data);} catch (IOException e) {e.printstacktrace ();} Finally{try {if (ZipFile! = null) {Zipfile.close ();} if (Outputstrean! = null) {Outputstrean.close ();} if (accessfile! = null) {Accessfile.close ();}} catch (Exception e) {e.printstacktrace ();}}} /** * Short converted to byte array (small end order) * @param data * @return */private static short Stream2short (byte[] stream, int offset) {by        Tebuffer buffer = bytebuffer.allocate (2);        Buffer.order (Byteorder.little_endian);        Buffer.put (Stream[offset]);        Buffer.put (Stream[offset + 1]);    Return Buffer.getshort (0); }/** * byte array converted to short (small endian) * @param stream * @param offset * @return */private static byte[] Short2stream (ShoRT data) {Bytebuffer buffer = bytebuffer.allocate (2);        Buffer.order (Byteorder.little_endian);        Buffer.putshort (data);        Buffer.flip ();    return Buffer.array (); }}

  

Read comment

   private void Showcomment (TextView TextView) {if (TextView = = null) {return;        } String FilePath = Getpackagepath (this);        String comment = readapk (new File (FilePath));        try {comment = Urldecoder.decode (comment, "utf-8");        } catch (Unsupportedencodingexception e) {e.printstacktrace ();    } textview.settext (comment); public static String Getpackagepath (context context) {if (context! = null) {return CONTEXT.GETPACKAG        Ecodepath ();    } return null;        public static String readapk (file file) {byte[] bytes = NULL;            try {randomaccessfile accessfile = new Randomaccessfile (file, "R");            Long index = Accessfile.length ();            bytes = new Byte[2];            index = index-bytes.length;            Accessfile.seek (index);            accessfile.readfully (bytes);            int contentlength = Stream2short (bytes,0); bytes = newByte[contentlength];            index = index-bytes.length;            Accessfile.seek (index);            accessfile.readfully (bytes);        return new String (bytes, "Utf-8");        } catch (Exception e) {e.printstacktrace ();    } return null; }/** * Short converted to byte array (small end order) * @param data * @return */private static short Stream2short (byte[] Stream        , int offset) {Bytebuffer buffer = bytebuffer.allocate (2);        Buffer.order (Byteorder.little_endian);        Buffer.put (Stream[offset]);        Buffer.put (Stream[offset + 1]);    Return Buffer.getshort (0); }/** * byte array converted to short (small endian) * @param stream * @param offset * @return */private static byte[] Sho        Rt2stream (short data) {Bytebuffer buffer = bytebuffer.allocate (2);        Buffer.order (Byteorder.little_endian);        Buffer.putshort (data);        Buffer.flip ();    return Buffer.array (); }

  

A scheme for dynamically writing information to an APK

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.