B/S模式實現批量打包apk
界面流程
界面例如以下:
這是一個使用html編寫的界面,界面分為兩半。兩個frame。左邊為操作欄,右邊為控制臺輸出。
打包流程:
選擇須要打包的渠道後,點擊打包,等待server打包,並把日誌輸出到右邊的frame。
打包完畢後。點擊”點擊打開下載界面”鏈接。跳轉到下載界面。
實現思路
環境說明
server使用的是apache server2.4.12,所以與瀏覽器的交互是使用cgi,關於cgi能夠參考這裏。
自己主動化的實現使用ant。關於ant能夠參考這裏。
開發工具:vs2013
開發語言:html、javascript、C++
系統:win7 x64
瀏覽器與服務端的交互。
服務端結構:
在主界面左邊的frame中有一個渠道列表,每一個渠道相應一個id。
<fieldset align="left" >
<legend>渠道列表:</legend>
<label class="labelChnnel">Debug<input class="btnChnnel" name="chnnel" type="checkbox" value="1" /></label>
<label class ="labelChnnel">小米<input class="btnChnnel" name="chnnel" type="checkbox" value="2" /></label>
<label class="labelChnnel">360<input class="btnChnnel" name="chnnel" type="checkbox" value="3" /></label>
<label class="labelChnnel">安智<input class ="btnChnnel" name="chnnel" type="checkbox" value="4" /></label>
<label class="labelChnnel">應用匯<input class="btnChnnel" name="chnnel" type="checkbox" value="5" /></label>
<label class="labelChnnel">中國移動<input class="btnChnnel" name="chnnel" type="checkbox" value="6" /></label>
<label class="labelChnnel">中國聯通<input class="btnChnnel" name="chnnel" type="checkbox" value="7" /></label>
<label class="labelChnnel">中國電信<input class="btnChnnel" name="chnnel" type="checkbox" value="8" /></label>
<label class="labelChnnel">九遊<input class="btnChnnel" name="chnnel" type="checkbox" value="9" /></label>
</fieldset>
當點擊打包的時候,會先獲取當前選擇的全部的渠道id並連接成一個字符串。
// 獲取選擇的渠道列表
function getChnnelList()
{
//getElementsByTagName:依據標簽名獲取元素集合
//getElementById:依據id獲取元素
//getElementsByName:依據名稱(name屬性值)獲取元素集合
var checkboxes = document.getElementsByName(‘chnnel‘);
var len = checkboxes.length;
var chnnelList = "";
for(var i=0; i<len; ++i)
{
if(checkboxes[i].checked)
{
chnnelList = chnnelList + checkboxes[i].value + " "; //把渠道id連接成字符串
}
}
return chnnelList;
}
接著調用requestPkg方法並把渠道id字符串傳入,該方法會發送一個異步請求到服務端。並把server返回的數據顯示在右邊的frame中。
// 打包
function requestPkg( data )
{
var img = document.getElementById("loadingImg");
// 防止連續點擊
if(‘inline‘ == img.style.display){
return
}
//顯示loading
showLoading();
var xmlHttp = new XMLHttpRequest();
// 1.提交方式(GET/POST)
// 2.url
// 3.是否異步
xmlHttp.open( "POST", "http://localhost/cgi-bin/apkpkg.cgi", true );
xmlHttp.overrideMimeType(‘text/plain; charset=gbk‘); // 解決frame中文亂碼問題
// response handler
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == XMLHttpRequest.DONE) {
if (xmlHttp.status == 200) {
// 把返回數據顯示在右邊的frame
var doc = parent.right_frame.document;
//加入html文本
var html = doc.createElement("div");
html.className = "description";
html.innerHTML = xmlHttp.responseText;
doc.body.appendChild(html);
// 加入普通文本
//var txt=doc.createTextNode(xmlHttp.responseText)
//doc.body.appendChild(txt)
//自己主動向下滾動
parent.right_frame.scrollBy(0, html.scrollHeight);
} else if (xmlHttp.status == 400) {
console.log(‘There was an error 400‘);
} else {
console.log(‘something else other than 200 was returned‘);
}
//隱藏loading
hideLoading();
}
};
// 發送請求
xmlHttp.send( data );
}
服務端處理流程例如以下:
1.服務端接受到渠道id字符串後,對字符串進行切割並轉換為整數,加入到chnnelList
2.然後調用git pull(假設是svn則運行svn update)命令更新project。
3.叠代chnnelList,依據渠道id運行不同的命令(ant能夠把一系列操作簡化成運行一個命令。事實上打包的過程。無非是對文件的一些操作。如刪除、拷貝、移動、替換文件內容等,或者是運行一些命令,這些都能夠通過ant實現,假設真遇到ant庫提供的功能實現不了的需求,ant也提供了擴展的接口,詳細可參考這裏。能夠的話也跟我說說吧。
)
4.輸出運行結果。
//main.cpp
#include <stdio.h>
#include <iostream>
#include "cmdlib.h"
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>
using namespace std;
//常量
class Constant{
public:
// project所在文件夾
static const char* ProjectDir; //聲明靜態變量
};
// 靜態變量的初始化
const char* Constant::ProjectDir = "D:/AndroidDeveloper/workspace2/AntTest";
// 依據渠道id運行不同的命令
void exeCmd(int &id){
switch (id)
{
//Debug
case 1:
cmd::exec_atdir(Constant::ProjectDir, "ant buildDebug", true);
break;
//小米
case 2:
cmd::exec_atdir(Constant::ProjectDir, "ant buildXiaoMi", true);
break;
//360
case 3:
break;
//安智
case 4:
break;
//應用匯
case 5:
break;
//中國移動
case 6:
break;
//中國聯通
case 7:
break;
//中國電信
case 8:
break;
//九遊
case 9:
break;
}
}
void main(){
cout<<"Context-type:text/html; charset=UTF-8 \n\n";
cout<<"<html>";
cout<<"<body>";
// 獲取提交的參數
char params[256] = { 0 };
gets_s(params);//獲取輸入
cout << "<p>params=" << params << "</p>";
vector<string> chnnelStrList;
istringstream iss(params);
// 對字符串進行切割,並復制到渠道列表
copy(istream_iterator<string>(iss), // 開始位置
istream_iterator<string>(), // 結束位置
back_inserter<vector<string>>(chnnelStrList)); // push_back到vector
// 把字符串轉換成整數
vector<int> chnnelLlist;
int chnnel = 0;
for_each(chnnelStrList.begin(), chnnelStrList.end(), [&chnnel, &chnnelLlist](string & str){
chnnel = atoi(str.c_str());
if (chnnel != 0)
{
chnnelLlist.push_back(chnnel);
}
});
// 首先更新project
// svn update / git pull
cmd::exec_atdir(Constant::ProjectDir, "git pull", false);
// 依據id運行相應的命令
for_each(chnnelLlist.begin(), chnnelLlist.end(), [](int & id){
exeCmd(id);
});
cout<<"</body>";
cout<<"</html>";
}
// cmdlib.h
#ifndef __CMDLIB_H__
#define __CMDLIB_H__
#include <iostream>
#include <stdlib.h>
#include <string.h>
using namespace std;
namespace cmd{
// 運行命令並輸出
bool exec_output(const char* cmd){
// 運行命令,並打印輸出
FILE* pipe = _popen(cmd, "r"); // 第一個參數是指令字符串。第二個參數是模式(r:讀,w:寫)
// _popen函數用於運行一條指令並把結果輸出到內存中的文件對象
if (!pipe)
{
return false;
}
cout << "<p>";
// 把運行結果輸出到網頁
char ch = 0;
while (!feof(pipe)){
ch = fgetc(pipe);
// 把‘\n‘換行符換成網頁中的換行符<br />
if (ch == ‘\n‘)
{
cout<<"<br />";
}
else{
putchar(ch);
}
}
cout << "</p>";
return true;
}
// 在指定文件夾下運行一個命令
// dir:文件夾路徑
// cmd:命令
// is_out:是否輸出運行結果
void exec_atdir(const char* dir, const char* cmd, bool is_out = false){
char buff[1024] = { 0 };
#if _WIN32
sprintf_s(buff, "cd /d %s & %s", dir, cmd);
#else
sprintf_s(buff, "cd %s & %s", dir, cmd);
#endif
if (is_out)
{
exec_output(buff);
}
else{
system(buff);
}
}
};
#endif
在Apache Server安裝文件夾下有一個htdocs文件夾,是站點的根文件夾。我在這裏新建了一個apk文件夾。用於存放所以自己主動生成的apk。通過http://localhost/apk(這裏的localhost指server的ip。由於我在本地測試所以使用localhost)能夠在瀏覽器訪問該文件夾。
通過ant命令生成的apk最後會被移動到該文件夾下。
最後,渠道包生成完畢後,點擊鏈接。瀏覽器跳轉到渠道包列表網頁下載渠道包。
相關文章
1.Ant開發總結
2.CGI編程
項目地址:https://coding.net/u/linchaolong/p/BSBatchPkgTool/git
B/S模式實現批量打包apk