Android multi-channel packaging details
In the interview, if the interviewer suddenly asked: "How did you play the channel bag?" If you say it is compiled with Gradle one, and then he despises that this efficiency is too low, you have written what script to hit the channel bag? You must be in the mind, lying in the groove, so gorgeous hanging fried days, write your own script packaging?! In fact, this is not too difficult at all!! Talk today about the fundamentals of multi-channel packaging and how to DIY multi-channel packaging tools!
Channel Pack appears
When a product to the release, we are engaged in Android will face a super awkward problem: the domestic so many channels, channel statistics is necessary to do, then more than 10 major channels plus an unlimited amount of ground push channel package becomes a giant pit! This piece of time is a bottomless pit AH!!!
List of ways
Here are a total of three ways to implement the channel package, namely:
1, the use of Gradle configuration directly compiled a different channel package.
2, the corresponding channel number is modified by anti-compilation.
3. Add a new file inside the Meta-inf.
Gradle Way
Whether it is the Union of statistics or other things, first of all must be some preparation work, because I have a better understanding of the Friends of the Union, so the UF league statistics to examples!
Friends of the league statistics provide two channels of statistical strategy, in fact, is an automatic block of a manual.
<meta-data
Android:name= "Umeng_appkey"
Android:value= "xxxxxxxx"/>
<meta-data
Android:name= "Umeng_channel"
Android:value= "${gradle_channel_value}"/>
The corresponding information is configured in the corresponding Build.gradle:
Productflavors.all {Flavor
Flavor.manifestplaceholders = [Gradle_channel_value:name]
}
productflavors {
dev {
}
Baidu {
Minsdkversion 18
ApplicationID "Com.test.michat"
}
}
If you manually set the channel number, the following method is called at the entrance of the program:
Mobclickagent. Startwithconfigure (umanalyticsconfig config)
Umanalyticsconfig (context context, string Appkey, String channelid)
Umanalyticsconfig (context context, string Appkey, String channelid, Escenariotype eType)
Umanalyticsconfig (context context, string Appkey, String channelid, Escenariotype Etype,boolean iscrashenable)
So how to get the corresponding channel number it?! This method will be used in all the way after the drop, in fact, regardless of which way, the end will call this method to read the relevant data!!
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_value");
} catch (Packagemanager.namenotfoundexception ignored) {
}
Return "";
}
Android multi-channel packaging details (top)
Buildvariants.png
Of course you can also use the command line: Gradlew Assemble assemble all the channel packs!!
Anti-compilation method
Gradle Way is also quite good, why do you want to do what anti-compilation so troublesome things? Because it has a big problem, that is, every package is to be compiled and packaged! This is quite time-consuming! Time is working overtime Ah! Who do not want to work overtime to play the Channel bag!! The way to decompile is to save every channel package to compile the time, but to compile good one channel package after the use of the channel package, through the anti-compilation dynamically modify the information inside the Androidmanifest.xml, and then repack the signature!
When it comes to anti-compilation, you have to mention the famous Apktool.jar! Nani, you said you never heard of it?! No matter, have not heard before, now will be used on the line!!
Then summarize the following series of routines:
Package---modification of relevant parameters--package--Signature->zipalign optimization
1. Unpacking
Apktool D your_original_apk Build
You're not mistaken, that's it! Because we are standing on the shoulders of giants to work, so a lot of work is different from doing it!
After executing the above command, if there is nothing unexpected, you will get a folder:
Android multi-channel packaging details (top)
Related code:
try {
Brut.apktool.Main.main (New string[]{"D", "-F", Apkfilepath, "-O", Outpath});
return true;
} catch (Exception e) {
E.printstacktrace ();
Callback ("Unpacking failed!!!!! \ r \ n "+ e.getmessage ());
}
2, modify the corresponding parameters
Open the corresponding androidmanifest.xml, you have not read the wrong, what is in the inside, directly modify just fine! Wait, XML parsing you won't?! No matter, here is dom4j.jar for you to use!!
To modify the Androidmanifest file-related code after the decompile
try {
File Androidmanifestfile = new file (appfoldername + file.separator + "Androidmanifest.xml");
Document document = new Saxreader (). read (androidmanifestfile);//sax parsing using dom4j
Element element = Document.getrootelement (). Element ("Application");
list<element> list = element.elements ("Meta-data");//Get all the "Meta-data"
list<metadata> MetaData = Manifest.getmetadata ();
Boolean isupdate = false;
for (MetaData Data:metadata) {
String name = Data.getname ();
String value = Data.getvalue ();
Callback ("Meta-data name=" + name + "' value= '" + Value + "'");
for (Element s:list) {
Attribute Attribute = S.attribute ("name");
Update related channel number
if ("Umeng_channel". Equals (name) && "Umeng_channel". Equals (Attribute.getvalue ())) {//replace the associated channel number
S.attribute ("value"). SetValue (value);
Isupdate = true;
Callback ("Update 1 androidmanifest.xml meta-data name= '" + attribute.getvalue () + "' value= '" + Value + "'");
Break
}
}
}
if (isupdate) {//re-write after update
XMLWriter writer = new XMLWriter (new FileOutputStream (Androidmanifestfile));
Writer.write (document);
Writer.close ();
Callback ("Update androidmanifest.xml complete ~");
}
} catch (Exception e) {
E.printstacktrace ();
return false;
}
3. Packing
Apktool B Build your_unsigned_apk
It's still so simple:
try {
Brut.apktool.Main.main (New string[]{"B", Buildapkfolderpath, "-O", Buildapkoutpath});
return true;
} catch (Exception e) {
E.printstacktrace ();
Callback ("Package failed!!!!! \ r \ n "+ e.getmessage ());
}
4. Signature
Jarsigner-sigalg md5withrsa-digestalg sha1-keystore your_keystore_path-storepass Your_storepass-signedjar your_ signed_apk, your_unsigned_apk, Your_alias
This is provided directly in the JDK, as long as your environment variables are configured, there is no problem! Re-signing related code
ExecuteCommand ("Jarsigner", "-verbose", "-sigalg", "Sha1withrsa", "-digestalg", "SHA1", "-keystore", Keystorefilepath , Apkfilepath, alias, "-storepass", password);
/**
* Execute command
*
* @param command
*/
Private Synchronized Boolean executecommand (String ... command) {
Process process = NULL;
BufferedReader reader = null;
try {
Processbuilder builder = new Processbuilder ();
Builder.command (command);
Builder.redirecterrorstream (TRUE);
Process = Builder.start ();
reader = new BufferedReader (New InputStreamReader (Process.getinputstream (), "UTF-8"));
String Line;
while (line = Reader.readline ()) = null) {
Callback (line);
if (Line.contains ("Exception") | | | line.contains ("Unable to open") {
return false;
}
}
return true;
} catch (IOException e) {
E.printstacktrace ();
Callback (E.getmessage ());
} finally {
Close (reader);
if (process! = null) {
Process.destroy ();
}
}
return false;
}
5, zipalign optimization
Android multi-channel packaging details (top)
, Sdk/build-tools inside each version has this thing, add to the environment variable is good!!!
Manuscripts: Diligent Learning qkxue.net
Extended reading:
Android multi-channel packaging details (top): http://qkxue.net/info/25417/Android
Android multi-channel packaging details (bottom): http://qkxue.net/info/25418/Android
Android multi-channel packaging details