예제 #1
0
def copy_libs(decompile_dir, sdk_dir):

    cpus = [
        'arm64-v8a', 'armeabi', 'armeabi-v7a', 'mips', 'mips64', 'x86',
        'x86_64'
    ]
    dest_dir = os.path.join(decompile_dir, 'lib')
    src_dir = os.path.join(sdk_dir, 'libs')
    if not os.path.exists(src_dir):
        return
    if os.path.exists(dest_dir):
        for f in os.listdir(dest_dir):
            if f.endswith('.jar'):
                continue
            source_file = os.path.join(src_dir, f)
            target_file = os.path.join(dest_dir, f)
            if os.path.exists(source_file):
                Utils.copy_file(source_file, target_file)
    else:
        os.mkdir(dest_dir)
        for fi in os.listdir(src_dir):
            if fi.endswith('.jar'):
                continue
            source_file = os.path.join(src_dir, fi)
            target_file = os.path.join(dest_dir, fi)
            Utils.copy_file(source_file, target_file)
예제 #2
0
    def save_data(self):
        if self.game_name_value.text().strip() == "":
            QMessageBox.warning(self, "警告", "游戏名称不能为空!")
            return False
        if self.keystore_path.text().strip() == "":
            QMessageBox.warning(self, "警告", "必须上传keystore签名文件!")
            return False
        if self.keystore_pwd_value.text().strip() == "":
            QMessageBox.warning(self, "警告", "keystore密码不能为空!")
            return False
        if self.keystore_alias_value.text().strip() == "":
            QMessageBox.warning(self, "警告", "alias不能为空!")
            return False
        if self.keystore_aliaspwd_value.text().strip() == "":
            QMessageBox.warning(self, "警告", "alias密码不能为空!")
            return False
        self.game['name'] = self.game_name_value.text().strip()
        self.game['desc'] = self.game_desc_value.toPlainText().strip()
        if self.keystore_exchanged:
            keystore = os.path.basename(self.keystore_path.text().strip())
            self.game['keystore'] = keystore
            self.game['keypwd'] = self.keystore_pwd_value.text().strip()
            self.game['alias'] = self.keystore_alias_value.text().strip()
            self.game['aliaspwd'] = self.keystore_aliaspwd_value.text().strip()
            keystore_path = Utils.get_full_path('games/' + self.game['id'] +
                                                '/keystore/' + keystore)
            if not os.path.exists(keystore_path):
                Utils.copy_file(self.keystore_path.text().strip(),
                                keystore_path)

        self.main_win.games[self.main_win.game_index] = self.game
        self.game_list_model.update_item(self.main_win.game_index, self.game)
        return Utils.update_games(Utils.get_full_path('games/games.xml'),
                                  self.game, self.main_win.game_index)
예제 #3
0
    def create(self):
        if self.game_name_value.text().strip() == "":
            QMessageBox.warning(self, "警告", "游戏名称不能为空!")
            return
        if self.game_appid_value.text().strip() == "":
            QMessageBox.warning(self, "警告", "游戏Id不能为空!")
            return
        if self.game_appkey_value.text().strip() == "":
            QMessageBox.warning(self, "警告", "客户端Key不能为空!")
            return
        if self.keystore_path.text().strip() == "":
            QMessageBox.warning(self, "警告", "必须上传keystore签名文件!")
            return
        if self.keystore_pwd_value.text().strip() == "":
            QMessageBox.warning(self, "警告", "keystore密码不能为空!")
            return
        if self.keystore_alias_value.text().strip() == "":
            QMessageBox.warning(self, "警告", "alias不能为空!")
            return
        if self.keystore_aliaspwd_value.text().strip() == "":
            QMessageBox.warning(self, "警告", "alias密码不能为空!")
            return
        self.game['name'] = self.game_name_value.text().strip()
        self.game['desc'] = self.game_desc_value.toPlainText().strip()
        self.game['id'] = self.game_appid_value.text().strip()
        self.game['key'] = self.game_appkey_value.text().strip()
        if os.path.exists(Utils.get_full_path('games/' + self.game['id'])):
            QMessageBox.warning(self, "警告", "游戏已存在!")
            return
        if not os.path.exists(Utils.get_full_path('games')):
            os.makedirs(Utils.get_full_path('games'))
        os.mkdir(Utils.get_full_path('games/' + self.game['id']))

        keystore = os.path.basename(self.keystore_path.text().strip())
        self.game['keystore'] = keystore
        self.game['keypwd'] = self.keystore_pwd_value.text().strip()
        self.game['alias'] = self.keystore_alias_value.text().strip()
        self.game['aliaspwd'] = self.keystore_aliaspwd_value.text().strip()
        os.mkdir(Utils.get_full_path('games/' + self.game['id'] + '/keystore'))
        keystore_path = Utils.get_full_path('games/' + self.game['id'] +
                                            '/keystore/' + keystore)
        Utils.copy_file(self.keystore_path.text().strip(), keystore_path)

        os.mkdir(Utils.get_full_path('games/' + self.game['id'] + '/icon'))
        if self.icon_path is not None:
            icon_file = Utils.get_full_path('games/' + self.game['id'] +
                                            '/icon/icon.png')
            Utils.copy_file(self.icon_path, icon_file)

        self.main_win.games.append(self.game)
        Utils.add_game(Utils.get_full_path('games/games.xml'), self.game)
        self.main_win.game_index = len(self.main_win.games) - 1
        self.main_win.set_game_list_widget(self.main_win.games)
예제 #4
0
def generate_r_file(package_name, decompile_dir):
    # check_value_resources(decompile_dir)
    temp_path = os.path.dirname(decompile_dir) + '/temp'
    LogUtils.debug('generate R:the temp path is %s', temp_path)
    if os.path.exists(temp_path):
        Utils.del_file(temp_path)
    os.makedirs(temp_path)
    res_path = decompile_dir + '/res'
    temp_res_path = temp_path + '/res'
    Utils.copy_file(res_path, temp_res_path)
    gen_path = temp_path + '/gen'
    os.makedirs(gen_path)

    aapt_path = Utils.get_full_path('tools/aapt2.exe')
    android_path = Utils.get_full_path('tools/android.jar')
    java = Utils.get_full_path('tools/jdk/bin/java')
    javac = Utils.get_full_path('tools/jdk/bin/javac')

    manifest_path = decompile_dir + '/AndroidManifest.xml'
    res_flat_path = temp_path + "/res_flat.zip"
    cmd = '%s compile -o %s --dir %s' % (aapt_path, res_flat_path,
                                         temp_res_path)
    ret = Utils.exec_cmd(cmd)
    if ret:
        return 1
    cmd = '%s link -o %s --manifest %s -I %s --java %s %s' % (
        aapt_path, temp_path + '/res.apk', manifest_path, android_path,
        gen_path, res_flat_path)
    ret = Utils.exec_cmd(cmd)
    if ret:
        return 1

    LogUtils.info('package_name:%s', package_name)
    r_path = package_name.replace('.', '/')
    r_path = gen_path + '/' + r_path + '/R.java'
    cmd = '%s -source 1.8 -target 1.8 -encoding UTF-8 %s' % (javac, r_path)
    ret = Utils.exec_cmd(cmd)
    if ret:
        return 1
    dex_path = temp_path + '/classes.dex'
    dex_tool_path = Utils.get_full_path('tools/dx.jar')
    cmd = '%s -jar %s --dex --output %s %s' % (java, dex_tool_path, dex_path,
                                               gen_path)
    ret = Utils.exec_cmd(cmd)
    if ret:
        return 1
    smali_path = decompile_dir + '/smali'
    ret = dex2smali(dex_path, smali_path, '')
    if ret:
        return 1
    return 0
예제 #5
0
 def exchange_icon(self):
     fname = QFileDialog.getOpenFileName(
         self, '选择icon',
         Utils.get_full_path('games/' + self.game['id'] + '/icon/'),
         ("Images (*.png)"))
     if fname[0]:
         pix = QPixmap(fname[0])
         if pix.width() != 512 or pix.height() != 512:
             QMessageBox.warning(self, "警告", "必须上传512*512.png图片")
             return
         self.icon_img.setPixmap(pix)
         current_icon = Utils.get_full_path('games/' + self.game['id'] +
                                            '/icon/icon.png')
         if os.path.exists(current_icon):
             if os.path.samefile(os.path.dirname(fname[0]),
                                 os.path.dirname(current_icon)):
                 if not os.path.samefile(
                         fname[0], current_icon
                 ):  # 如果选中的,在game的icon目录下,但不是当前icon,则进行重命名
                     count = 0
                     temp = 'icon0.png'
                     while os.path.exists(
                             Utils.get_full_path('games/' +
                                                 self.game['id'] +
                                                 '/icon/' + temp)):
                         count += 1
                         temp = 'icon' + str(count) + '.png'
                     os.renames(
                         current_icon,
                         Utils.get_full_path('games/' + self.game['id'] +
                                             '/icon/' + temp))
                     os.renames(fname[0], current_icon)
                 else:  # 如果所选的是当前icon,不做处理
                     return
             else:  # 如果选中的不在game的icon目录下,则重命名当前icon,并将选中的icon复制到目录下作为当前icon
                 count = 0
                 temp = 'icon0.png'
                 while os.path.exists(
                         Utils.get_full_path('games/' + self.game['id'] +
                                             '/icon/' + temp)):
                     count += 1
                     temp = 'icon' + str(count) + '.png'
                 os.renames(
                     current_icon,
                     Utils.get_full_path('games/' + self.game['id'] +
                                         '/icon/' + temp))
                 Utils.copy_file(fname[0], current_icon)
         else:
             Utils.copy_file(fname[0], current_icon)
예제 #6
0
    def run(self):
        # 开启任务,发送打包信号
        self.signal.signal.emit(self.channel['channelId'], 0, "正在打包......", 0)
        # 清空已有的workspace
        work_dir = Utils.get_full_path('workspace/' + self.game['id'] + '/' +
                                       self.channel['channelId'])
        Utils.del_file(work_dir)
        os.makedirs(work_dir)
        # 生成当前打包任务的logger,添加到字典
        LogUtils.add_logger(work_dir)

        LogUtils.info('Current Selected Game ID is : %s, with SDK is : %s',
                      self.game['id'], self.channel['sdk'])
        LogUtils.info('game:\n%s', self.game)
        LogUtils.info('channel:\n%s', self.channel)

        src_apk_path = work_dir + '/songshu.apk'
        # 复制上传母包到workspace
        result = Utils.copy_file(self.apk, src_apk_path)
        if self.flag(result, "打包失败:复制母包文件失败,详情查看log.log", 5):
            return

        # 反编译母包
        decompile_dir = work_dir + '/decompile'
        frame_work_dir = work_dir + '/framework'
        result = ApkUtils.decompile_apk(src_apk_path, decompile_dir,
                                        frame_work_dir)
        if self.flag(result, "打包失败:反编译母包异常,详情查看log.log", 15):
            return

        # 复制sdk资源到工作目录
        sdk_source_dir = Utils.get_full_path('channelsdk/' +
                                             self.channel['sdk'])
        sdk_dest_dir = work_dir + '/sdk'
        result = Utils.copy_file(sdk_source_dir, sdk_dest_dir)
        if self.flag(result, "打包失败:复制SDK文件夹失败,详情查看log.log", 18):
            return

        # 将插件里的jar资源转dex
        result = ApkUtils.jar2dex(sdk_source_dir,
                                  sdk_dest_dir + '/classes.dex')
        if self.flag(result, "打包失败:渠道jar转dex异常,详情查看log.log", 25):
            return

        # 将插件里的dex资源转smali,合并到母包反编译目录中
        result = ApkUtils.dex2smali(sdk_dest_dir + '/classes.dex',
                                    decompile_dir + '/smali', '')
        if self.flag(result, "打包失败:渠道dex转smali异常,详情查看log.log", 28):
            return

        # 合并manifest文件
        result = ApkUtils.merge_manifest(decompile_dir, sdk_dest_dir)
        if self.flag(result, "打包失败:合并manifest文件失败,详情查看log.log", 30):
            return

        # 复制插件libs里的so库
        ApkUtils.copy_libs(decompile_dir, sdk_dest_dir)
        if self.flag(0, "", 33):
            return

        # 复制插件assets文件夹
        result = Utils.copy_file(sdk_dest_dir + '/assets',
                                 decompile_dir + '/assets')
        if self.flag(result, "打包失败:复制assets文件夹失败,详情查看log.log", 35):
            return

        # 复制插件res文件夹
        result = Utils.copy_file(sdk_dest_dir + '/res', decompile_dir + '/res')
        if self.flag(result, "打包失败:复制res文件夹失败,详情查看log.log", 38):
            return

        # 复制渠道特殊配置资源,比如,针对个别渠道设置的loading页或logo
        ApkUtils.copy_ext_res(self.game, decompile_dir)
        if self.flag(0, "", 40):
            return

        # 将游戏原来的包名替换成渠道里面的包名,四大组件也会按照相关规则替换包名
        package_name = ApkUtils.rename_package_name(decompile_dir,
                                                    self.channel['package'])
        if self.flag(0, "", 45):
            return

        # 给对应的icon添加角标
        ApkUtils.append_channel_mark(self.game, sdk_dest_dir, decompile_dir)
        if self.flag(0, "", 50):
            return

        # 配置参数写入
        result = ApkUtils.write_develop_info(self.game, self.channel,
                                             decompile_dir)
        if self.flag(result, "打包失败:写入配置参数失败,详情查看log.log", 52):
            return

        # 如果主sdk有特殊的逻辑。执行特殊的逻辑脚本。
        result = ApkUtils.do_sdk_script(self.channel, decompile_dir,
                                        package_name, sdk_dest_dir)
        if self.flag(result, "打包失败:执行渠道脚本异常,详情查看log.log", 55):
            return

        # 修改游戏名称,并将meta-data写入manifest文件
        ApkUtils.modify_manifest(self.channel, decompile_dir, package_name)
        if self.flag(0, "", 60):
            return

        # 重新生成R文件,并导入到包名下
        result = ApkUtils.generate_r_file(package_name, decompile_dir)
        if self.flag(result, "打包失败:重新生成R文件异常,详情查看log.log", 75):
            return

        # 防止方法数超65535,判断是否分dex
        result = ApkUtils.classes_split(decompile_dir, sdk_dest_dir)
        if self.flag(result, "打包失败:分dex出现异常,详情查看log.log", 78):
            return

        # 修改apktool.yml里的压缩配置,防止包体变大
        ApkUtils.edit_yml(self.channel, decompile_dir)
        if self.flag(0, "", 80):
            return

        # 回编译生成apk
        target_apk = work_dir + '/output.apk'
        result = ApkUtils.recompile_apk(decompile_dir, target_apk,
                                        frame_work_dir)
        if self.flag(result, "打包失败:回编译APK异常,详情查看log.log", 90):
            return

        # 复制添加资源到apk
        result = ApkUtils.copy_root_ext_files(target_apk, decompile_dir)
        if self.flag(result, "打包失败:母包其余资源导入异常,详情查看log.log", 92):
            return

        # apk签名(v1签名)
        result = ApkUtils.sign_apk(self.game, target_apk)
        if self.flag(result, "打包失败:渠道包签名异常,详情查看log.log", 98):
            return

        # apk对齐
        time_str = QDateTime.currentDateTime().toString("yyyyMMddhhmm")
        dest_apk_name = self.game['name'] + '-' + self.channel[
            'name'] + '-' + time_str + '.apk'
        dest_apk_dir = Utils.get_full_path('output/' + self.game['id'] + '/' +
                                           self.channel['channelId'])
        if not os.path.exists(dest_apk_dir):
            os.makedirs(dest_apk_dir)
        dest_apk = dest_apk_dir + '/' + dest_apk_name
        result = ApkUtils.align_apk(target_apk, dest_apk)
        if self.is_close:
            pass
        else:
            if result == 0:
                self.signal.signal.emit(self.channel['channelId'], 1,
                                        "打包成功:双击打开出包目录", 100)
            else:
                self.signal.signal.emit(self.channel['channelId'], result,
                                        "打包失败:apk包体4k对齐异常,详情查看log.log", 100)
        LogUtils.close()
예제 #7
0
def copy_ext_res(game, decompile_dir):
    ext_res_path = 'games/' + game['id'] + '/ext'
    ext_res_path = Utils.get_full_path(ext_res_path)
    if os.path.exists(ext_res_path):
        LogUtils.warning('the game ext res path: %s', ext_res_path)
        Utils.copy_file(ext_res_path, decompile_dir)