在做一个项目,需要实现一个APK自动打包的功能。
系统背景:移动教学平台,使学生熟练使用apk及电子商务网站。系统中包含不同班级,教师可以为不同班级分配不同的实验,每个实验都有对应的APK。每次分配实验时要进行实验的部署,主要完成数据库、文件系统及IIS的自动化部署。因此整个系统中,不同班级对应的IIS站点是不同的,不同班级的APK所要连接的后台服务器也是不同的,故需要对apk进行自动化反编译,修改相应字段后,重新打包。
反编译打包工具使用的是APKTool,流程图如下:
废话不说,上代码:
main() 代码:
string strFilePath = ConfigurationSettings.AppSettings["APKTool"]; //G:\开发\移动平台\Tools\ApkTool
string strBatPath = strFilePath + "/apk.bat"; //bat文件存储目录
string apkpath = Server.MapPath("../FileUpload/ExpApk");
string[] apknames = Directory.GetFiles(apkpath);
string str = classinfo.cid.ToString() + ".apk";
string apkname = "ChenniaoB2C"+"_"+str;
string[] name = { "ChenniaoB2C", "ChenniaoMap", "TravelhubMobile" };
bool tag = true; //标记是否存在同名文件存在
foreach (string item in apknames)
{
string [] s=item.Split('\\');
int index=s.Count();
if (apkname == s[index-1])
{
tag = false;
break;
}
}
if (tag)
{
#region 自动打包apk
CreateBAT(name[0], 0, str); //0:生成反编译bat
ExecuteBAT(strBatPath); //反编译apk
System.Threading.Thread.Sleep(13000);
UpdateConnectStr(); //修改链接字符串
CreateBAT(name[0], 1, str); //1:生成打包bat
ExecuteBAT(strBatPath); //打包apk
System.Threading.Thread.Sleep(30000);
CreateBAT(name[0], 2, str); //3:拷贝打包好的apk至FileUpload\ExpApk,并删除遗留文件
ExecuteBAT(strBatPath);
System.Threading.Thread.Sleep(5000);
#endregion
}
生成bat文件函数:
protected void CreateBAT(string apkname, int tag, string str)
{
string strFilePath = ConfigurationSettings.AppSettings["APKTool"];
string strBatPath = strFilePath + "/apk.bat";//bat文件存储目录
string strAPKPath = ConfigurationSettings.AppSettings["Client"]; //客户端目录
string apkpath = Server.MapPath("../FileUpload/ExpApk");
if (true)
{
string[] disknames = strFilePath.Split(':');
string diskname = "c";
if (disknames != null)
{
diskname = disknames[0]; //获取盘符
}
StringBuilder sBuilder = new StringBuilder();
//sBuilder.AppendLine(string.Format("@echo off"));
if (tag == 0)
{
sBuilder.AppendLine(string.Format("{0}", diskname + ":"));
sBuilder.AppendLine(string.Format("cd {0}", strFilePath));
sBuilder.AppendLine(string.Format("copy {0} 123.apk", strAPKPath + "\\" + apkname + ".apk")); //从客户端拷贝文件至APKTool
sBuilder.AppendLine(string.Format("decompile.vbs"));
//sBuilder.AppendLine(string.Format("pause"));
}
else if (tag == 1)
{
sBuilder.AppendLine(string.Format("{0}", diskname + ":"));
sBuilder.AppendLine(string.Format("cd {0}", strFilePath));
sBuilder.AppendLine(string.Format("build.vbs"));
}
else if (tag == 2)
{
sBuilder.AppendLine(string.Format("{0}", diskname + ":"));
sBuilder.AppendLine(string.Format("cd {0}", strFilePath + "\\APK\\build"));
sBuilder.AppendLine(string.Format("copy 已编译(已签名).apk {0}", apkpath + "\\" + apkname + "_" + str));
sBuilder.AppendLine(string.Format("cd ../.."));
sBuilder.AppendLine(string.Format("del 123.apk"));
sBuilder.AppendLine(string.Format("delete.vbs"));
}
Stream st = new FileStream(strBatPath.Replace("\\", "/"), FileMode.Create, FileAccess.Write);
using (StreamWriter sw = new StreamWriter(st, Encoding.GetEncoding("gb2312")))
{
sw.Write(sBuilder.ToString());
sw.Close();
st.Dispose();
st.Close();
}
}
}
执行bat文件函数:
protected string ExecuteBAT(string strBatPath) //文件路径;要执行bat文件的进程,返回执行结果
{
string mess = "";
Process pro = new Process();
try
{
pro.StartInfo.UseShellExecute = true;
pro.StartInfo.FileName = strBatPath.Replace("\\","/"); //strBatPath是bat文件路径
pro.StartInfo.CreateNoWindow = true;
if (pro.Start())
{
mess ="执行bat成功.";
}
else
{
mess ="生成失败.";
}
}
catch (Exception ex)
{
mess = ex.Message;
}
finally
{
pro.Close();
}
return mess;
}
对反编译好的apk文件进行修改,修改strings.xml中的连接字符串:
protected void UpdateConnectStr()
{
string FilePath= ConfigurationSettings.AppSettings["APKTool"]+"\\APK\\res\\values\\strings.xml";
string oldValue="www.chenniao.com";
string newValue=ConfigurationSettings.AppSettings["apkService"];
//string newValue = oldValue; //测试
ReplaceText(FilePath,oldValue,newValue);
}
public static void ReplaceText(string path, string oldValue, string newValue)
{
string text = string.Empty;
using (StreamReader reader = new StreamReader(path, Encoding.UTF8))//注意编码形式,xml为UTF8
{
text = reader.ReadToEnd();
reader.Close();
}
using (StreamWriter writer = new StreamWriter(path,false,Encoding.UTF8))
{
writer.Write(text.Replace(oldValue, newValue));
writer.Close();
}
}
bat批处理中使用到三个vbs文件,这三个文件用于模拟键盘输入,在目录APKTool下。
decompile.vbs:
set s = WScript.CreateObject("WScript.Shell")
app=s.Run ("APKTool.cmd")
WScript.Sleep 1000
s.AppActivate app
s.SendKeys "1"
s.SendKeys "{ENTER}"
WScript.Sleep 10000
s.SendKeys "{ENTER}"
s.SendKeys "0"
s.SendKeys "{ENTER}"
build.vbs:
set s = WScript.CreateObject("WScript.Shell")
app=s.Run ("APKTool.cmd")
WScript.Sleep 1000
s.AppActivate app
s.SendKeys "3"
s.SendKeys "{ENTER}"
WScript.Sleep 25000
s.SendKeys "{ENTER}"
WScript.Sleep 5000
s.SendKeys "0"
s.SendKeys "{ENTER}"
delete.vbs:
set s = WScript.CreateObject("WScript.Shell")
app=s.Run ("APKTool.cmd")
WScript.Sleep 1000
s.AppActivate app
s.SendKeys "7"
s.SendKeys "{ENTER}"
WScript.Sleep 2000
s.SendKeys "{ENTER}"
WScript.Sleep 2000
s.SendKeys "0"
s.SendKeys "{ENTER}"
模块完成中遇到的问题及解决:
•
Dos
命令不熟练,在文件的路径上反斜杠(
\
)与斜杠
(/)
混淆,在
dos
命令中使用反斜杠,在
C#
路径中使用斜杠,同时还要注意转义字符的使用;
•
C#
文件流操作中,要注意编码格式,创建
bat
文件时,由于路径中包含中文字,所以要使用
gb2312
编码;而在修改
strings.xml
时,注意到代码头部标出使用
UTF8
编码,故文件读写时需要使用
UTF8
编码;
•
v
bs
模拟键盘时需要让程序延迟发生,否则会产生错误。