B/S模式实现批量打包apk

界面流程

界面如下:

这是一个使用html编写的界面,界面分为两半,两个frame,左边为操作栏,右边为控制台输出。

打包流程:
选择需要打包的渠道后,点击打包,等待服务器打包,并把日志输出到右边的frame。

打包完成后,点击”点击打开下载界面”链接,跳转到下载界面。
B/S模式实现批量打包apk_第1张图片

实现思路

环境说明

服务器使用的是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字符串传入,该方法会发送一个异步请求到服务端,并把服务器返回的数据显示在右边的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)命令更新工程。
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:
    // 工程所在目录
    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);
        }
    });

    // 首先更新工程
    // 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指服务器的ip,因为我在本地测试所以使用localhost)可以在浏览器访问该目录。通过ant命令生成的apk最后会被移动到该目录下。

最后,渠道包生成完成后,点击链接,浏览器跳转到渠道包列表网页下载渠道包。

相关文章

1.Ant开发总结
2.CGI编程

项目地址:https://coding.net/u/linchaolong/p/BSBatchPkgTool/git

你可能感兴趣的:(ant,批量打包,b-s模式)