来源:http://hubingforever.blog.163.com/blog/static/1710405792013102954345842/
以下是对一个已经打包的Android应用程序的apk文件根据渠道号再进行批量打包的程序示例。
config.bat文件
set outDir=out
set rawDatadir=temp
set apk=SignatureChecker.apk
set channelName=A;B
set channelNo=1;2;3;4
set projectName=r
set versionCode=100
set stamp=%Date:~0,4%%Date:~5,2%%Date:~8,2%%Time:~0,2%%Time:~3,2%%Time:~6,2%
echo %stamp%_
build.bat文件
@echo off
call config.bat
Setlocal enabledelayedexpansion
set path=%path%;%cd%\lib
if exist %rawDatadir% (
call deleteDir %rawDatadir%
)
if not exist %outDir% (
md %outDir%
)
call apktool d -s %apk% %rawDatadir%
Setlocal enabledelayedexpansion
set /a cnt=0
for %%i in (%channelName%) do (
set name=%%i
set apkName=%projectName%_%versionCode%_!name!.apk
call getSubStr "%channelNo%" !cnt!
set no=!getSubStr~result!
set /a cnt+=1
java AndroidManifestModifier %rawDatadir%\AndroidManifest.xml %rawDatadir%\AndroidManifest.xml lenovo:channel !no!
call apktool b %rawDatadir% !apkName!
jarsigner -keystore robin.keystore -storepass GL2009 -keypass gl2009 !apkName! robin
move !apkName! %outDir%
)
endlocal
AndroidManifestModifier主要用于在对Android应用程序进行打包发布是修改渠道号。
AndroidManifestModifier.java文件
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
publicclassAndroidManifestModifier{
/**
* @param args
*/
publicstaticvoid main(String[] args){
// TODO Auto-generated method stub
String srcFilePath="AndroidManifest.xml";
String outFilePath="AndroidManifest.xml";
String metaDataName="youmi:channel";
String metaDataNewValue="newValue"+System.currentTimeMillis()%1000;
if(args!=null&&args.length>=4){
srcFilePath=args[0];
outFilePath=args[1];
metaDataName=args[2];
metaDataNewValue=args[3];
}
change(srcFilePath,outFilePath,metaDataName,metaDataNewValue);
}
publicstaticvoid change(String srcfilePath,String outFilePath,String metaDataName,String metaDataNewValue){
File f =newFile(srcfilePath);
DocumentBuilderFactory factory =DocumentBuilderFactory.newInstance();
DocumentBuilder builder =null;
finalString android_value="android:value";
try{
builder = factory.newDocumentBuilder();
Document doc = builder.parse(f);
NodeList nl = doc.getElementsByTagName("meta-data");
int len = nl.getLength();
org.w3c.dom.Node channelNode =null;
for(int i =0; i < len; i++){
org.w3c.dom.Node n = nl.item(i);
System.out.println(n.getNodeName());
NamedNodeMap nm = n.getAttributes();
boolean c=false;
for(int j =0; j < nm.getLength(); j++){
org.w3c.dom.Node n2 = nm.item(j);
System.out.println(n2.getNodeName()+"|"+ n2.getNodeValue());
if(metaDataName.equals(n2.getNodeValue()))
{
c=true;
break;
}
}
if(c){
for(int j =0; j < nm.getLength(); j++){
org.w3c.dom.Node n2 = nm.item(j);
if(android_value.equals(n2.getNodeName())){
channelNode=n2;
break;
}
}
}
}
if(channelNode !=null){
channelNode.setNodeValue(metaDataNewValue);
writeXMLFile(doc, outFilePath);
}
}catch(ParserConfigurationException e){
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
privatestaticvoid writeXMLFile(Document doc,String outfile){
try{
FileOutputStream fos =newFileOutputStream(outfile);
OutputStreamWriter outwriter =newOutputStreamWriter(fos);
writeXmlFile(doc, outwriter,"utf-8");
outwriter.close();
fos.close();
}catch(Exception e){
e.printStackTrace();
}
}
// 写入xml文件
public static void writeXmlFile(Document doc, Writer w, String encoding) {
try {
Source source = new DOMSource(doc);
Result result = new StreamResult(w);
Transformer xformer = TransformerFactory.newInstance().newTransformer();
xformer.setOutputProperty(OutputKeys.ENCODING, encoding);
xformer.transform(source, result);
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (TransformerException e) {
e.printStackTrace();
}
}
}
apktool.bat文件
请参考《Android反编译工具简介》
robin.keystore文件的制作
请参考《Android应用程序签名简介》
android应用程序的AndroidManifest.xml文件
<?xml version="1.0" encoding="utf-8"?>
<manifestxmlns:android="http://schemas.android.com/apk/res/android"
package="com.lenovo.robin"
android:versionCode="1"
android:versionName="1.0">
<uses-sdkandroid:minSdkVersion="8"/>
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name">
<meta-data
android:name="youmi:channel"
android:value="88888"/>
<activity
android:name=".SignatureCheckerActivity"
android:label="@string/app_name">
<intent-filter>
<actionandroid:name="android.intent.action.MAIN"/>
<categoryandroid:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".SignatureDetailActivity"
android:label="@string/app_name">
</activity>
</application>
</manifest>