Ext.: http://tech.meituan.com/mt-apk-packaging.html
Android Automation Tour-Generate channel packs
Zhihu2014-06-13 10:06
Overview
Each time a new version is issued, the Android client will be distributed to various application markets, such as pea pods, 360 mobile phone assistants and so on. In order to count the effects of these markets (active number, next singular, etc.), there is a way to uniquely identify them.
The group purchase client is currently using the channel number ( channel
) to differentiate between different markets, and the code uses Config.channel
variables to record the channel number. For example, in the Pea pod market, the channel number for the U.S.-China application is the wandoujia
channel number for the 360 mobile phone assistant China-US group qihu360
. The client accesses the API with the channel number in the request parameter so that the background can then calculate the effect of the different channels.
Each time the release, the marketing department will provide a list of channels, and Android Rd will generate an equal amount of channel packages based on these channels. As the channels become more and more (more than 900 channels have been written as of this writing), the way the client hits the channel pack has been evolving, and this article details the package journey for the American mission.
Maven
MAVEN is a software project management and automated build tool, with the use of Android-maven-plugin plug-ins, as well as the Maven-resources-plugin plug-in can be easily generated channel package, below a brief introduction to the next packaging process, Please refer to the relevant documentation for more information on how to use Maven and plugins.
First, AndroidManifest.xml
add the <application>
following element to the node <meta-data>
to define the source of the channel:
<!-- 使用Maven打包时会用具体的渠道号替换掉${channel} --><meta-data android:name="channel" android:value="${channel}" />
Once you have defined the channel source, you can then read the channel number when the program starts:
private String getChannel(Context context) { try { PackageManager pm = context.getPackageManager(); ApplicationInfo appInfo = pm.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA); return appInfo.metaData.getString("channel"); } catch (PackageManager.NameNotFoundException ignored) { } return ""; }
To replace AndroidManifest.xml
the channel number defined by the file, you also need to pom.xml
configure the resources plug-in in the file:
<resources> <resource> <directory>${project.basedir}</directory> <filtering>true</filtering> <targetPath>${project.build.directory}/filtered-manifest</targetPath> <includes> <include>AndroidManifest.xml</include> </includes> </resource></resources>
The preparation has been completed, and what is needed now is the actual channel number. The following script iterates through the list of channels, replacing and packaging them individually:
#!/bin/bashpackage(){ while read line do mvn clean mvn -Dchannel=$line package done < $1}package $1
This approach is acceptable when there are few early channels, but the approach is no longer applicable as long as the channel grows slightly, because it is inefficient to execute the build process once per dozen packages.
Apktool
Apktool is a reverse engineering tool that you can use to decode (decode) and modify the resources in the APK. Next, you'll learn more about using Apktool to generate channel packages.
As with Maven packaging, you also need to AndroidManifest.xml
define elements in the file <meta-data>
and read the channel numbers in the manifest file when the app starts. Please refer to the above code for details.
Unlike Maven, it is no longer necessary to rebuild the project each time it is packaged. When packaging, just build an apk and build another channel package on top of that apk.
First, using the Apktool decode application, enter the following command in the terminal:
apktool d your_original_apk build
The above command decode the application file in the build directory, and the directory after decode is complete as follows:
Next, replace AndroidManifest.xml
the channel number defined in the file, following a Python script:
import redef replace_channel(channel, manifest): pattern = r‘(<meta-data\s+android:name="channel"\s+android:value=")(\S+)("\s+/>)‘ replacement = r"\g<1>{channel}\g<3>".format(channel=channel) return re.sub(pattern, replacement, manifest)
Then, use Apktool to build an unsigned apk:
apktool b build your_unsigned_apk
Finally, use Jarsigner to re-sign the APK:
jarsigner -sigalg MD5withRSA -digestalg SHA1 -keystore your_keystore_path -storepass your_storepass -signedjar your_signed_apk, your_unsigned_apk, your_alias
The above is a method of packaging using Apktool, which enables batch generation of channel packages by using scripts. Unlike Maven, every dozen packages require a build process that is built once and saves time.
But the last few days, our channel package more and more, there are nearly 900 channels, the completion of all the channel package needs nearly 3 hours. Is there a quicker way to pack? And look at the next section.
Meta-inf
If you can directly modify the APK channel number, and do not need to re-sign can save a lot of packaging time. Fortunately, we have found this way. Directly unzip the apk, the extracted root directory will have a META-INF
directory, as shown in:
If you META-INF
add an empty file within the directory, you can not re-sign the app. Therefore, you can uniquely identify a channel by adding different empty files for different channels of application.
The following Python code is used to add an empty channel file to the APK, with the prefix of the channel name mtchannel_
:
import zipfilezipped = zipfile.ZipFile(your_apk, ‘a‘, zipfile.ZIP_DEFLATED) empty_channel_file = "META-INF/mtchannel_{channel}".format(channel=your_channel)zipped.write(your_empty_file, empty_channel_file)
After adding the empty channel file directory, the META-INFO
directory has a more than one named mtchannel_meituan
empty file:
You can then read the empty channel file name in the Java code:
public static String Getchannel (context context) {ApplicationInfo appinfo = Context.getapplicationinfo (); String SourceDir = Appinfo.sourcedir; String ret = ""; ZipFile zipfile = null; try {zipfile = new ZipFile (SourceDir); enumeration<?> entries = Zipfile.entries (); while (Entries.hasmoreelements ()) {ZipEntry entry = ((ZipEntry) entries.nextelement ()); String entryName = Entry.getname (); if (Entryname.startswith ("Mtchannel")) {ret = EntryName; Break }}} catch (IOException e) {e.printstacktrace (); } finally {if (ZipFile! = null) {try {zipfile.close (); } catch (IOException e) {e.printstacktrace (); }}} string[] split = Ret.split ("_"); if (split!)= null && split.length >= 2) {return ret.substring (split[0].length () + 1); } else {return ""; } }
This way, each dozen a channel package only need to copy an apk, in the META-INF
add a channel number named empty file can be. This packaging is very fast, and more than 900 channels can be played in less than a minute.
Summarize
There are a total of three ways to hit the channel pack. At present, the Android team packaging basic use of a third way, the completion of packaging automation, freeing up the productivity of engineers, good and good.
The problem with packing is solved, but sometimes you need to customize the APK for different channels. Next talk about Android build tool Gradle, and how to use Gradle Custom channel package, please look forward to.
3 Ways to pack your Android multi-channel package