Beispiel #1
0
    def do_build(self):
        #各个渠道的打包
        for app_id in self.batch_info.keys():
            app_id = utils.non_unicode_str(app_id)
            channels = self.batch_info[app_id]
            for channel_id in channels:
                Logging.debug_msg('----------------')
                apk_rollback_obj = utils.FileRollback()
                try:
                    channel_str = self.get_string(channel_id)
                    self.build_result['%s_%s' % (app_id, channel_str)] = ''
                    self.build_one_apk(app_id, channel_str, apk_rollback_obj)
                except:
                    Logging.warn_msg('打包失败')
                finally:
                    Logging.debug_msg('finally :')
                    if not self.no_rollback:
                        apk_rollback_obj.do_rollback()
                Logging.debug_msg('----------------\n')

        Logging.debug_msg('\n打包结果汇总 :')
        for key in self.build_result.keys():
            ids = key.split('_')
            value = self.build_result[key]
            if value and os.path.isfile(utils.get_sys_encode_str(value)):
                Logging.debug_msg(
                    'APP_ID : %s, CHANNEL_ID : %s。打包成功。apk 路径 : %s' %
                    (ids[0], ids[1], value))
            else:
                Logging.debug_msg('APP_ID : %s, CHANNEL_ID : %s。打包失败。' %
                                  (ids[0], ids[1]))
        #打开目录
        os.system("start explorer %s" % self.output_path)
Beispiel #2
0
    def build_apk_gradle(self, rollback_obj, cfg_dir, apk_cfg_info, apk_name):
        # 最终 apk 文件名格式为:GAMENAME_PKGNAME_APPID_CHANNELID_VERNAME_VERCODE.apk
        # Logging.debug_msg('修改apk文件名 game_name=%s pkg_name=%s app_id=%s channel_id=%s ver_name=%s ver_code=%s' % (game_name, pkg_name, app_id, channel_id, ver_name, ver_code))

        # 修改签名文件
        Logging.debug_msg('修改签名文件')
        keystore_path = utils.flat_path(
            os.path.join(
                cfg_dir,
                apk_cfg_info[PackAPK.CFG_SIGN][PackAPK.CFG_SIGN_FILE]))
        keystore_pass = apk_cfg_info[PackAPK.CFG_SIGN][
            PackAPK.CFG_SIGN_PASSWORD]
        alias = apk_cfg_info[PackAPK.CFG_SIGN][PackAPK.CFG_SIGN_ALIAS]
        alias_pass = apk_cfg_info[PackAPK.CFG_SIGN][
            PackAPK.CFG_SIGN_ALIAS_PASSWORD]
        self._modify_gradle_config(rollback_obj, self.output_path, apk_name,
                                   keystore_path, keystore_pass, alias,
                                   alias_pass)

        gradle_cmd = "cd %s;gradle clean;gradle aR" % self.proj_androidStudio_path
        try:
            utils.run_shell(gradle_cmd)
        except:
            Logging.warn_msg('gradle 命令行打包失败')

        Logging.debug_msg('gradle配置文件修改完成')
Beispiel #3
0
    def _do_add_check_files(self, key, value):
        unix_key = key.replace('\\', '/')

        if unix_key not in self.check_files:
            self.check_files[unix_key] = value
        else:
            Logging.warn_msg("%s 冲突:%s 和 %s" % (unix_key, self.check_files[unix_key], value))
Beispiel #4
0
    def do_build(self):
        try:
            for app_id in self.batch_info.keys():
                app_id = utils.non_unicode_str(app_id)
                channels = self.batch_info[app_id]
                for channel_id in channels:
                    Logging.debug_msg('----------------')
                    apk_rollback_obj = utils.FileRollback()
                    try:
                        channel_str = self.get_string(channel_id)
                        self.build_result['%s_%s' % (app_id, channel_str)] = ''
                        self.build_one_apk(app_id, channel_str,
                                           apk_rollback_obj)
                    except:
                        Logging.warn_msg('打包失败')
                    finally:
                        if not self.no_rollback:
                            apk_rollback_obj.do_rollback()
                    Logging.debug_msg('----------------\n')

            Logging.debug_msg('\n打包结果汇总 :')
            for key in self.build_result.keys():
                ids = key.split('_')
                value = self.build_result[key]
                if value and os.path.isfile(utils.get_sys_encode_str(value)):
                    Logging.debug_msg(
                        'APP_ID : %s, CHANNEL_ID : %s。打包成功。apk 路径 : %s' %
                        (ids[0], ids[1], value))
                else:
                    Logging.debug_msg('APP_ID : %s, CHANNEL_ID : %s。打包失败。' %
                                      (ids[0], ids[1]))

        except Exception:
            raise
        finally:
            if os.path.isdir(self.temp_dir):
                shutil.rmtree(self.temp_dir)
Beispiel #5
0
    def do_build(self):
        #各个游戏,各个渠道
        for game in self.batch_info.keys():
            game = utils.non_unicode_str(game)
            channels = self.batch_info[game]
            for channel_id in channels:
                Logging.debug_msg('----------------' + channel_id)
                try:
                    channel_str = utils.non_unicode_str(channel_id)
                    apk_cfg_file = os.path.join(self.root_dir, game,
                                                channel_str, 'package.json')
                    if not os.path.isfile(apk_cfg_file):
                        Logging.warn_msg('未找到 %s 文件' % apk_cfg_file)
                        return
                    pack_cfg_info = self.parse_json(apk_cfg_file)
                    if pack_cfg_info is None:
                        Logging.warn_msg('解析文件 %s 出错' % apk_cfg_file)
                        return

                    strResPath = utils.non_unicode_str(
                        pack_cfg_info['res_path'])
                    res_path = utils.flat_path(
                        os.path.join(self.root_dir, game, channel_str,
                                     strResPath))

                    strTargetpath = utils.non_unicode_str(
                        pack_cfg_info['target_path'])
                    target_path = utils.flat_path(
                        os.path.join(self.root_dir, strTargetpath))

                    copy_cfg = {
                        'from': '.',
                        'to': '.',
                        'exclude': ['**/.DS_Store']
                    }
                    excopy.copy_files_with_config(copy_cfg, res_path,
                                                  target_path)
                except:
                    Logging.warn_msg('资源拷贝失败')
                finally:
                    Logging.debug_msg('finally :')
                Logging.debug_msg('----------------\n')
Beispiel #6
0
def needCompress(key):
    global PngMap
    # folder, basename = os.path.split(key)
    # pattern = r"([a-f0-9\-]+)\.[a-f0-9\-]{5}\.png"
    # m = re.match(pattern, basename)
    # if not m:
    #     Logging.warn_msg("The file path %s is not in right format." % key)
    #     return False
    #
    # checkKey = os.path.join(folder, "%s.png" % m.group(1))
    checkKey = key.replace('\\', '/')
    if PngMap.has_key(checkKey):
        srcPath = os.path.dirname(PngMap[checkKey])
        srcPath = srcPath.lstrip("db://assets/")
        base, ext = os.path.splitext(srcPath)
        if (ext == ".plist"):
            srcPath = base + '.png'

        # 检查不需要压缩的文件夹
        unDirs = Uncompress.get('dirs', [])
        for d in unDirs:
            if srcPath.startswith(d):
                Logging.warn_msg("%s in uncompress dir : %s" % (key, d))
                return False

        # 检查不需要压缩的文件
        unFiles = Uncompress.get('files', [])
        for f in unFiles:
            if srcPath == f:
                Logging.warn_msg("%s is uncompress file %s" % (key, f))
                return False

        Logging.debug_msg("Compress image : %s (%s)" % (key, srcPath))
        return True
    else:
        Logging.warn_msg("%s is not found in PngMap.json" % checkKey)
        return False
Beispiel #7
0
    def build_one_apk(self, app_id, channel_id, rollback_obj):
        apk_cfg_file = os.path.join(self.root_dir, app_id, channel_id,
                                    'package.json')
        if not os.path.isfile(apk_cfg_file):
            Logging.warn_msg('未找到 %s 文件,打包失败1' % apk_cfg_file)
            return

        Logging.debug_msg('开始使用配置文件 %s 打包' % apk_cfg_file)
        apk_cfg_info = self._parse_json(apk_cfg_file)
        if apk_cfg_info is None:
            Logging.warn_msg('解析文件 %s 出错,打包失败2' % apk_cfg_file)
            return

        cfg_dir = os.path.dirname(apk_cfg_file)

        check_ret = self._check_cfg_info(apk_cfg_info, cfg_dir)
        if check_ret:
            Logging.warn_msg(check_ret + ',打包失败5')
            return

        # gradle需要修改 package.json 配置文件
        rollback_obj.record_file(apk_cfg_file)
        game_name = utils.non_unicode_str(apk_cfg_info[PackAPK.CFG_GAME_NAME])
        pkg_name = utils.non_unicode_str(apk_cfg_info[PackAPK.CFG_PKG_NAME])
        ver_name = utils.non_unicode_str(
            apk_cfg_info[PackAPK.CFG_VERSION_NAME])
        ver_code = utils.non_unicode_str(
            apk_cfg_info[PackAPK.CFG_VERSION_CODE])
        app_scheme = utils.non_unicode_str(
            apk_cfg_info[PackAPK.CFG_APP_SCHEME])

        # 修改 strings.xml
        self._modify_strings_xml(game_name, app_scheme)
        # 修改渠道号
        isThirdPart = apk_cfg_info.get(PackAPK.CFG_THIRD_PART, False)
        self._modify_apihelper(apk_cfg_info[PackAPK.CFG_CHANNEL_ID],
                               isThirdPart, rollback_obj)
        # 修改 java 文件中 R 的包名
        self._modify_java_files(pkg_name, rollback_obj)

        # 修改 AndroidManifest.xml
        self._modify_manifest(pkg_name, ver_name, ver_code, rollback_obj)

        # 替换 res
        self._modify_res(apk_cfg_info, cfg_dir, rollback_obj)

        # 替换 libs
        self._modify_libs(apk_cfg_info, cfg_dir, rollback_obj)

        # 最终 apk 文件名格式为:GAMENAME_PKGNAME_APPID_CHANNELID_VERNAME_VERCODE.apk
        Logging.debug_msg('生成apk文件名')
        name_infos = [
            game_name, pkg_name, app_id, channel_id, ver_name, ver_code
        ]

        # 文件名增加时间戳
        Logging.debug_msg('文件名增加时间戳')
        cur_time_str = datetime.datetime.fromtimestamp(
            time.time()).strftime('%Y%m%d_%H%M%S')
        name_infos.append(cur_time_str)

        apk_name = '_'.join(name_infos) + '.apk'
        out_file_path = os.path.join(self.output_path, apk_name)
        if not os.path.isdir(self.output_path):
            os.makedirs(self.output_path)

        # 进行 gradle 打包
        Logging.debug_msg('进行 gradle 打包')
        try:
            self.build_apk_gradle(rollback_obj, cfg_dir, apk_cfg_info,
                                  apk_name)
            self.build_result['%s_%s' % (app_id, channel_id)] = out_file_path
        except:
            print 'traceback.format_exc():\n%s' % traceback.format_exc()
            return
Beispiel #8
0
    def build_one_apk(self, app_id, channel_id, rollback_obj):
        apk_cfg_file = os.path.join(self.root_dir, app_id, channel_id,
                                    'package.json')
        if not os.path.isfile(apk_cfg_file):
            Logging.warn_msg('未找到 %s 文件,打包失败' % apk_cfg_file)
            return

        Logging.debug_msg('开始使用配置文件 %s 打包' % apk_cfg_file)
        apk_cfg_info = self._parse_json(apk_cfg_file)
        if apk_cfg_info is None:
            Logging.warn_msg('解析文件 %s 出错,打包失败' % apk_cfg_file)
            return

        cfg_dir = os.path.dirname(apk_cfg_file)

        check_gt_ret = self._check_gt_info(apk_cfg_info, cfg_dir)
        if check_gt_ret:
            Logging.warn_msg(check_gt_ret + ', 打包失败')
            return

        check_ret = self._check_cfg_info(apk_cfg_info, cfg_dir)
        if check_ret:
            Logging.warn_msg(check_ret + ',打包失败')
            return

        # 备份文件和文件夹
        rollback_obj.record_file(utils.flat_path(self.library_manifest))
        rollback_obj.record_file(utils.flat_path(self.manifest))
        rollback_obj.record_folder(os.path.join(self.proj_android_path, 'res'))

        game_name = utils.non_unicode_str(apk_cfg_info[PackAPK.CFG_GAME_NAME])
        pkg_name = utils.non_unicode_str(apk_cfg_info[PackAPK.CFG_PKG_NAME])
        gaode_key = utils.non_unicode_str(apk_cfg_info[PackAPK.CFG_GAODE_KEY])
        ver_name = utils.non_unicode_str(
            apk_cfg_info[PackAPK.CFG_VERSION_NAME])
        ver_code = utils.non_unicode_str(
            apk_cfg_info[PackAPK.CFG_VERSION_CODE])
        app_scheme = utils.non_unicode_str(
            apk_cfg_info[PackAPK.CFG_APP_SCHEME])
        need_remove_agora = True  # Android 去掉视频 SDK apk_cfg_info.get(PackAPK.CFG_NO_AGORA, False)

        # 修改 java 文件中 R 的包名
        self._modify_java_files(pkg_name, rollback_obj)

        # 对需要修改包名的文件进行包名替换
        self._change_pkg_name(pkg_name, rollback_obj)

        # 修改 bugly appid
        if apk_cfg_info.has_key(PackAPK.CFG_BUGLY_ID):
            bugly_appid = utils.non_unicode_str(
                apk_cfg_info[PackAPK.CFG_BUGLY_ID])
        else:
            bugly_appid = ""
        if len(bugly_appid) > 0:
            self._modify_bugly(self.library_manifest, bugly_appid, channel_id)

        # 修改高德 key
        if len(gaode_key) > 0:
            self._modify_gaode_key(self.library_manifest, gaode_key)

        # 修改 Agora id
        if apk_cfg_info.has_key(PackAPK.CFG_AGORA_ID):
            self._modify_agora_id(self.library_manifest,
                                  apk_cfg_info[PackAPK.CFG_AGORA_ID])

        # 修改 AndroidManifest.xml
        self._modify_manifest(pkg_name, ver_name, ver_code)

        # 替换 java res
        for p in apk_cfg_info[PackAPK.CFG_JAVA_RES].split(','):
            java_res_path = utils.flat_path(os.path.join(cfg_dir, p.strip()))
            copy_cfg = {'from': '.', 'to': 'res', 'exclude': ['**/.DS_Store']}
            excopy.copy_files_with_config(copy_cfg, java_res_path,
                                          self.proj_android_path)

        # 替换 个推通知图标push.png
        # isTurnOffPush = apk_cfg_info.get(PackAPK.CFG_TURNOFF_PUSH, None)
        # if isTurnOffPush != "1":
        push_res_path = utils.flat_path(os.path.join(cfg_dir, "../pushRes"))
        proj_getui_path = utils.flat_path(
            os.path.join(self.proj_android_path,
                         '../library.pushgetui.android'))
        if not os.path.isdir(proj_getui_path):
            raise_known_error("未找到 getui 工程文件夹 %s" % proj_getui_path)
        copy_cfg = {'from': '.', 'to': 'res', 'exclude': ['**/.DS_Store']}
        rollback_obj.record_folder(os.path.join(proj_getui_path, "res"))
        if os.path.isdir(push_res_path):
            excopy.copy_files_with_config(copy_cfg, push_res_path,
                                          proj_getui_path)
        else:
            # raise_known_error('文件夹 %s 不存在,放置个推通知图标pushRes/drawable-xxhdpi/push.png|push_small.png' % push_res_path, KnownError.ERROR_PATH_NOT_FOUND)
            res_path = utils.flat_path(
                os.path.join(self.proj_android_path, "res"))
            pushSmallSrc_path = utils.flat_path(
                os.path.join(res_path, "mipmap-hdpi/ic_launcher.png"))
            pushSrc_path = utils.flat_path(
                os.path.join(res_path, "mipmap-xxxhdpi/ic_launcher.png"))
            pushDes_path = utils.flat_path(
                os.path.join(proj_getui_path, "res/drawable-xxhdpi/push.png"))
            pushSmallDes_path = utils.flat_path(
                os.path.join(proj_getui_path,
                             "res/drawable-xxhdpi/push_small.png"))
            # excopy.copy_files_with_config(copy_cfg, push_res_path, proj_getui_path)
            shutil.copyfile(pushSrc_path, pushDes_path)
            shutil.copyfile(pushSmallSrc_path, pushSmallDes_path)

        Logging.debug_msg('个推通知图标替换完成')

        # 修改 strings.xml
        self._modify_strings_xml(game_name, app_scheme)

        # 获取并清理临时的 assets 文件夹
        temp_assets_path = os.path.join(self.temp_dir,
                                        '%s_%s_assets' % (app_id, channel_id))
        if os.path.isdir(temp_assets_path):
            shutil.rmtree(temp_assets_path)

        Logging.debug_msg('开始处理资源文件')

        # 拷贝大厅的资源文件
        for p in PackAPK.DEFAULT_HALL_DIRS:
            copy_cfg = {
                'from': p,
                'to': p,
                'exclude': ['**/.DS_Store', 'LuaDebugjit.lua']
            }
            excopy.copy_files_with_config(copy_cfg, self.res_root_path,
                                          temp_assets_path)

        # 拷贝游戏通用组件的各个部分
        game_common_parts = apk_cfg_info.get(PackAPK.CFG_GAME_COMMON_PARTS,
                                             None)
        self._copy_game_common_parts(game_common_parts, temp_assets_path)

        # 拷贝指定的游戏文件
        games_dirs = []
        games = apk_cfg_info.get(PackAPK.CFG_GAMES, None)
        if isinstance(games, list) and len(games) > 0:
            games_dirs.extend(games)

        if len(games_dirs) > 0:
            if not os.path.isdir(self.games_root_path):
                raise_known_error('文件夹 %s 不存在' % self.games_root_path,
                                  KnownError.ERROR_PATH_NOT_FOUND)

            for game in games_dirs:
                copy_cfg = {
                    'from': '%s' % game,
                    'to': 'games/%s' % game,
                    'exclude': ['**/.DS_Store', '*.git']
                }
                excopy.copy_files_with_config(copy_cfg, self.games_root_path,
                                              temp_assets_path)

        # 替换游戏配置文件
        for p in apk_cfg_info[PackAPK.CFG_FILES].split(','):
            cfg_path = utils.flat_path(os.path.join(cfg_dir, p.strip()))
            copy_cfg = {'from': '.', 'to': 'src', 'exclude': ['**/.DS_Store']}
            excopy.copy_files_with_config(copy_cfg, cfg_path, temp_assets_path)

        # cfg_package.lua文件末尾写入打包文件夹名称时间戳
        tmpFile = open(os.path.join(temp_assets_path, "src/cfg_package.lua"),
                       'a')
        tmpFile.write('\nPACKAGE_TIMESTAMP=' + '\"' + self.packageTimestamp +
                      '\"')
        tmpFile.close()

        # 替换 res 文件夹
        if apk_cfg_info.has_key(PackAPK.CFG_RES_FILES):
            for p in apk_cfg_info[PackAPK.CFG_RES_FILES].split(','):
                res_path = utils.flat_path(os.path.join(cfg_dir, p.strip()))
                copy_cfg = {
                    'from': '.',
                    'to': 'res',
                    'exclude': ['**/.DS_Store']
                }
                excopy.copy_files_with_config(copy_cfg, res_path,
                                              temp_assets_path)

        # 删除不需要的品牌资源文件夹
        for brand in utils.get_support_brands():
            brand_path = utils.flat_path(
                os.path.join(temp_assets_path, 'res', brand))
            if brand != self.brand and os.path.isdir(brand_path):
                shutil.rmtree(brand_path)

        # 删除不属于该地区的地图资源文件
        if apk_cfg_info.has_key(PackAPK.CFG_REGION) and apk_cfg_info[
                PackAPK.CFG_REGION] != 'all':
            region_list = []
            new_list = apk_cfg_info[PackAPK.CFG_REGION].split(',')
            for r in new_list:
                if r.strip() != '':
                    region_list.append(r)

            # 超过1个地区时需要带上全国地图
            if len(region_list) > 1:
                region_list.append('0')

            keep_name_list = []
            for region in region_list:
                keep_name = 'map_%s' % region
                keep_name_list.append(keep_name)

            map_path = utils.flat_path(
                os.path.join(temp_assets_path, 'res/hall/map'))
            if os.path.isdir(map_path):
                for f in os.listdir(map_path):
                    full_path = os.path.join(map_path, f)
                    if f not in keep_name_list and os.path.isdir(full_path):
                        shutil.rmtree(full_path)

                # 如果不显示全国地图,则删除云动画的图片
                if len(region_list) <= 1:
                    cloud1_path = os.path.join(map_path, "yun1.png")
                    cloud2_path = os.path.join(map_path, "yun2.png")
                    os.remove(cloud1_path)
                    os.remove(cloud2_path)

        # 清理 assets 文件夹,只保留需要的文件
        assets_path = os.path.join(self.proj_android_path, 'assets')
        file_recorder = utils.FileRollback()
        for f in PackAPK.NEED_BACKUP_ASSETS:
            file_recorder.record_file(
                utils.flat_path(os.path.join(assets_path, f)))
        if os.path.isdir(assets_path):
            shutil.rmtree(assets_path)
        if not self.no_rollback:
            file_recorder.do_rollback()

        # 进行加密或者直接拷贝资源文件
        if os.path.isdir(temp_assets_path):
            # 生成 native 环境信息文件
            params = None
            if need_remove_agora:
                # 需要移除 agora
                params = {"no_agora": "true"}
            utils.write_native_info(
                os.path.join(temp_assets_path, 'src/NativeInfo.lua'), params)
            if not self.no_encrypt:
                self._do_encrypt(temp_assets_path, assets_path)
            else:
                copy_cfg = {
                    'from': '.',
                    'to': '.',
                    'exclude': ['**/.DS_Store']
                }
                excopy.copy_files_with_config(copy_cfg, temp_assets_path,
                                              assets_path)
                f = open(os.path.join(assets_path, 'src/myflag'), 'w')
                f.write('')
                f.close()

        Logging.debug_msg('资源文件处理结束')

        # 处理 SDK 相关的配置
        Logging.debug_msg('处理 SDK 相关的配置开始')
        sdks_cfg = apk_cfg_info.get(PackAPK.CFG_SDKS, {})
        remove_weixin = apk_cfg_info.get(PackAPK.CFG_REMOVE_WEIXIN, False)
        remove_youqu = apk_cfg_info.get(PackAPK.CFG_REMOVE_YOUQU, False)
        sdk_mgr = SDKManager.SDKManager(rollback_obj, pkg_name, sdks_cfg,
                                        remove_weixin, remove_youqu,
                                        self.build_gradle,
                                        self.proj_android_path,
                                        self.proj_androidStudio_path)
        sdk_mgr.prepare_sdk()
        Logging.debug_msg('处理 SDK 相关的配置结束')

        # 检查是否需要删除 agora 的库文件
        if need_remove_agora:
            self._do_remove_agora(rollback_obj)

        # 最终 apk 文件名格式为:GAMENAME_PKGNAME_APPID_CHANNELID_VERNAME_VERCODE.apk
        Logging.debug_msg('生成apk文件名')
        name_infos = [pkg_name, app_id, channel_id, ver_name, ver_code]
        remark = utils.non_unicode_str(apk_cfg_info.get(
            PackAPK.CFG_REMARK, ""))
        if len(remark) is not 0:
            name_infos.append(remark)

        if self.no_encrypt:
            name_infos.append('NO_ENCRYPT')

        # 是否删除 agora
        # if need_remove_agora:
        #     name_infos.append("NO_AGORA")

        # 文件名增加时间戳
        Logging.debug_msg('文件名增加时间戳')
        cur_time_str = datetime.datetime.fromtimestamp(
            time.time()).strftime('%Y%m%d_%H%M%S')
        name_infos.append(cur_time_str)

        apk_name = '_'.join(name_infos) + '.apk'
        out_file_path = os.path.join(self.output_path, apk_name)
        if not os.path.isdir(self.output_path):
            os.makedirs(self.output_path)

        if self.build_gradle:
            # 进行 gradle 打包
            Logging.debug_msg('进行 gradle 打包')
            try:
                self.build_apk_gradle(rollback_obj, cfg_dir, apk_cfg_info,
                                      apk_name)
                self.build_result['%s_%s' %
                                  (app_id, channel_id)] = out_file_path
            except:
                print 'traceback.format_exc():\n%s' % traceback.format_exc()
                return
        else:
            # 进行 ant 打包
            Logging.debug_msg('进行 ant 打包')
            keystore_path = utils.flat_path(
                os.path.join(
                    cfg_dir,
                    apk_cfg_info[PackAPK.CFG_SIGN][PackAPK.CFG_SIGN_FILE]))
            keystore_pass = apk_cfg_info[PackAPK.CFG_SIGN][
                PackAPK.CFG_SIGN_PASSWORD]
            alias = apk_cfg_info[PackAPK.CFG_SIGN][PackAPK.CFG_SIGN_ALIAS]
            alias_pass = apk_cfg_info[PackAPK.CFG_SIGN][
                PackAPK.CFG_SIGN_ALIAS_PASSWORD]
            ant_cmd = PackAPK.ANT_CMD_FMT % (self.ant_bin, self.build_xml,
                                             self.sdk_root, keystore_path,
                                             alias, keystore_pass, alias_pass)
            try:
                utils.run_shell(ant_cmd)
            except:
                Logging.warn_msg('打包失败')
                return
            # 将 apk 包拷贝到指定位置
            build_path = utils.flat_path(
                os.path.join(self.proj_android_path,
                             'bin/%s-release.apk' % self.proj_name))
            shutil.copy(utils.get_sys_encode_str(build_path),
                        utils.get_sys_encode_str(out_file_path))
            Logging.debug_msg('生成的 apk 文件路径:%s' % out_file_path)
            self.build_result['%s_%s' % (app_id, channel_id)] = out_file_path
        try:
            shutil.rmtree(temp_assets_path)
        except:
            pass