1. 程式人生 > >B/S模式實現批量打包apk

B/S模式實現批量打包apk

fad tle tdi inpu 控制臺輸出 dir static ams fine

界面流程

界面例如以下:
技術分享
這是一個使用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