Android multi-channel packaging solution and Android packaging Solution
Regular Build
Let's review the multi-channel batch packaging through Ant or Gradle, which is usually configured in AndroidManifest:
<meta-data android:name="CHANNEL" android:value="xxx" />
Meta-data dynamically changes the Channel name by configuring the value, and then we can get the Channel name in the Code as follows:
private String getChannelNameFromManifest(){try { return (String) mContext.getPackageManager().getApplicationInfo(mContext.getPackageName(), PackageManager.GET_META_DATA).metaData.get("CHANNEL"); } catch (NameNotFoundException e) { e.printStackTrace(); }}
Ant configuration on multi-channel packages is a little more troublesome. If you are interested, you can refer to this blog modest world-"App automation using Ant compilation Project multi-channel packaging".
Gradle, as the official Android build tool, batch packaging will naturally be relatively simple, just like the following simple configuration:
/** * ------------------------------------------------------- * Flavors * -------------------------------------------------------- */productFlavors { intl { applicationId "com.smartphone.linux1s1s.international" versionName createVersionName(versionNameInit) manifestPlaceholders = [deeplinkScheme: "nlbtn2goint"] } gloav { applicationId "com.smartphone.linux1s1s.android" versionName createVersionName(versionNameInit) manifestPlaceholders = [deeplinkScheme: "nlbtn2go"] }}
The configuration can be so simple, but the process of creating a new package in batches is still difficult. In plain words, if I need 1000 channel packages, each channel package will take 5 minutes, it will take 5000 minutes to complete these packages in batches. Android may not be able to think of this problem when developing Gradle, because in addition to the multi-channel market that tianchao has, other countries all look at it, we still have to face the reality and solve this time-consuming Packaging Problem.
Here we will start from the simplest case. If such a Channel is used only to distinguish different channels, the others will be the same. If there are other subtle differences, we will not consider them for the time being. In other words, even these subtle differences may be just some channels, so the most stupid solution is to create new channels, other solutions can be implemented through shortcuts.
What is this shortcut? Of course, we should avoid building a new Build. If we do not Build a new Build, what if we want to differentiate different channels?
Optimize Build
Let's take a look at the APK construction.
In principle, the files in the META-INF directory in this compressed directory do not participate in the signature, so we can escape the re-build by placing Channel labels in the file, in this way, we can directly package files in batches through file operations. The time consumed by file copy, decompression, and compression is negligible compared with the time consumed by the new build, the above is the core idea of the entire packaging solution. Next we will implement the above core idea.
Actual Operation
Add an empty file named xxx_channelName_channelId to the META-INF directory and use the xiaomi channel as an example:
Then, compress the corresponding file into a file in the .apk format. The above work is complete. Next, the file adding process is complete. Here, a Python script is provided for your reference.
Python script
#! /Usr/bin/python # coding = utf-8import zipfileimport shutilimport OS # empty file to facilitate writing this empty file to the apk package as the channel file src_empty_file = 'xxxxx.txt '# create an empty file (if it does not exist create) with open (src_empty_file, 'w') as f: pass # obtain all apk source packages in the current directory src_apks = [] # python3: OS. listdir (). The Python 2-compatible OS is used here. listdir ('. ') for file in OS. listdir ('. '): if OS. path. isfile (file): extension = OS. path. splitext (file) [1] [1:] if extension in 'apk ': src_apks.append (file) # obtain channel list channel_file = 'channelConfig.txt' with open (channel_file) as f: for src_apk in src_apks: # file name (with extension) src_apk_file_name = OS. path. basename (src_apk) # split the file name and suffix temp_list = OS. path. splitext (src_apk_file_name) # name without extension src_apk_name = temp_list [0] # suffix name, including. example :". apk "src_apk_extension = temp_list [1] # create a generated directory. if not OS is created if the file name output_dir = 'output _ '+ src_apk_name +'/'# does not exist. path. exists (output_dir): OS. mkdir (output_dir) # traverse the channel number and create the apk file for line in f. readlines (): # obtain the current channel number because \ n is obtained from the channel file. For all strip, target_channel = line. strip () # obtain the channel number and separate the channel name from the channel id target_channel_split = target_channel.split ('_') target_channel_name = token [0] # target_channel_id = target_channel_split [1] # splice the apk target_apk = output_dir + src_apk_name + '-release-' + target_channel_name + token # copy and create a new apk. copy (src_apk, target_apk) # zip to get the newly created apk file zipped = zipfile. zipFile (target_apk, 'A', zipfile. ZIP_DEFLATED) # initialize the channel information empty_channel_file = "META-INF/xxxx _ {channel }". format (channel = target_channel) # Write channel information zipped. write (src_empty_file, empty_channel_file) # Close zip stream zipped. close ()
If you have any questions, please contact us.
Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.