def __init__(self, main, channels, default_channel=None): super(ChannelAddWidget, self).__init__() self.setObjectName("ChannelAddWidget") self.main_win = main self.channels = channels self.default_channel = default_channel self.channel = {} self.linedit_list = [] self.game = self.main_win.games[self.main_win.game_index] combox_items = os.listdir(Utils.get_full_path('channelsdk')) v_layout = QVBoxLayout() v_layout.addSpacing(30) select_channel_combox = QComboBox() select_channel_combox.addItems(combox_items) select_channel_combox.activated[str].connect(self.select_channel) v_layout.addWidget(select_channel_combox, alignment=Qt.AlignHCenter) v_layout.addSpacing(30) h_layout1 = QHBoxLayout() form_layout1 = QFormLayout() form_layout1.setContentsMargins(10, 10, 10, 0) game_appid_value = QLabel(self.game['id']) form_layout1.addRow("游戏ID:", game_appid_value) game_appid_value.setTextInteractionFlags(Qt.TextSelectableByMouse) self.channel_id_value = QLineEdit() self.channel_id_value.setPlaceholderText("必填参数") form_layout1.addRow("渠道ID:", self.channel_id_value) self.game_name_value = QLineEdit() self.game_name_value.setText(self.game['name']) form_layout1.addRow("游戏名称:", self.game_name_value) self.game_package_value = QLineEdit() form_layout1.addRow("游戏包名:", self.game_package_value) self.game_vcode_value = QLineEdit() form_layout1.addRow("游戏版本号:", self.game_vcode_value) self.game_vname_value = QLineEdit() form_layout1.addRow("游戏版本名:", self.game_vname_value) self.debug_value = QLineEdit("false") form_layout1.addRow("打印日志:", self.debug_value) h_layout1.addLayout(form_layout1) self.form_layout2 = QFormLayout() self.form_layout2.setContentsMargins(10, 10, 10, 0) h_layout1.addLayout(self.form_layout2) v_layout.addLayout(h_layout1) h_layout2 = QHBoxLayout() back_btn = QPushButton("返 回") back_btn.setFixedWidth(100) back_btn.clicked.connect(self.back) h_layout2.addWidget(back_btn, alignment=Qt.AlignLeft) add_btn = QPushButton("添 加") add_btn.setFixedWidth(100) add_btn.clicked.connect(self.add) h_layout2.addWidget(add_btn, alignment=Qt.AlignRight) v_layout.addSpacing(50) v_layout.addLayout(h_layout2) self.setLayout(v_layout) # 默认松鼠SDK select_channel_combox.setCurrentText("songshu") self.select_channel("songshu")
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)
def decompile_apk(apk_file, target_dir, frame_work_dir): java = Utils.get_full_path('tools/jdk/bin/java') apk_tool = Utils.get_full_path('tools/apktool.jar') os.makedirs(target_dir) os.makedirs(frame_work_dir) cmd = "%s -jar %s d %s -o %s -p %s -f" % (java, apk_tool, apk_file, target_dir, frame_work_dir) return Utils.exec_cmd(cmd)
def dex2smali(dex_file, target_dir, path): """ Transfer the dex to smali. """ if not os.path.exists(dex_file): LogUtils.error('the dexfile is not exists. path:%s', dex_file) return 1 if not os.path.exists(target_dir): os.makedirs(target_dir) smali_tool = Utils.get_full_path('tools/baksmali.jar') java = Utils.get_full_path('tools/jdk/bin/java') cmd = '%s -jar %s -o %s %s' % (java, smali_tool, target_dir, dex_file) return Utils.exec_cmd(cmd)
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
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)
def copy_root_ext_files(apk_file, decompile_dir): aapt = Utils.get_full_path('tools/aapt2.exe') ignore_files = [ 'AndroidManifest.xml', 'apktool.yml', 'smali', 'res', 'original', 'lib', 'libs', 'build', 'assets', 'unknown', 'kotlin', 'smali_classes2', 'smali_classes3', 'smali_classes4', 'smali_classes5' ] ignore_file_paths = [] for file in ignore_files: path = os.path.join(decompile_dir, file) ignore_file_paths.append(path) add_files = [] add_files = Utils.list_files(decompile_dir, add_files, ignore_file_paths) if len(add_files) <= 0: return 0 cmd = '%s add %s' for f in add_files: name = f[len(decompile_dir) + 1:] cmd = cmd + ' ' + name cmd = cmd % (aapt, apk_file) curr_path = os.getcwd() os.chdir(decompile_dir) ret = Utils.exec_cmd(cmd) os.chdir(curr_path) return ret
def add(self): if self.channel_id_value.text().strip() == "": QMessageBox.warning(self, "警告", "渠道ID不能为空!") return self.channel['channelId'] = self.channel_id_value.text().strip() for channel in self.channels: if self.channel['channelId'] == channel['channelId']: QMessageBox.warning(self, "警告", "渠道已存在!") return self.channel['gameName'] = self.game_name_value.text().strip() self.channel['package'] = self.game_package_value.text().strip() self.channel['gameVersionCode'] = self.game_vcode_value.text().strip() self.channel['gameVersionName'] = self.game_vname_value.text().strip() self.channel['debug'] = self.debug_value.text().strip() for i in range(len(self.linedit_list)): if self.linedit_list[i].text().strip() == "": QMessageBox.warning(self, "警告", "渠道参数不能为空!") return self.channel['sdkParams'][i]['value'] = self.linedit_list[i].text( ).strip() self.channels.append(self.channel) Utils.add_channel( Utils.get_full_path('games/' + self.game['id'] + '/config.xml'), self.channel) self.main_win.set_channel_list_widget(self.channels)
def jar2dex(src_dir, dex_path): """ compile jar files to dex. """ dex_tool_path = Utils.get_full_path('tools/dx.jar') java = Utils.get_full_path('tools/jdk/bin/java') cmd = '%s -jar %s --dex --output %s' % (java, dex_tool_path, dex_path) for f in os.listdir(src_dir): if f.endswith('.jar'): cmd = cmd + ' ' + os.path.join(src_dir, f) for f in os.listdir(os.path.join(src_dir, 'libs')): if f.endswith('.jar'): cmd = cmd + ' ' + os.path.join(src_dir, 'libs', f) return Utils.exec_cmd(cmd)
def select_list(self): index = self.qpb_list_widget.currentIndex().row() channel_id = self.channels[self.indexs[index]]['channelId'] success = self.lbps[channel_id]['success'] dest_apk_dir = Utils.get_full_path('output/' + self.game['id'] + '/' + channel_id) if success: os.startfile(dest_apk_dir) else: QMessageBox.warning(self, "警告", "打包成功了吗?")
def sign_apk(game, apk_file): key_path = Utils.get_full_path('games/' + game['id'] + '/keystore/' + game['keystore']) if not os.path.exists(key_path): LogUtils.info('the keystore file not exists: %s', key_path) return 1 LogUtils.info('the keystore file is %s', key_path) aapt = Utils.get_full_path('tools/aapt.exe') lcmd = "%s list %s" % (aapt, apk_file) out = Utils.exec_cmd2(lcmd) if out is not None and len(out) > 0: for filename in out.split('\n'): if filename.find('META-INF') == 0: rmcmd = "%s remove %s %s" % (aapt, apk_file, filename) Utils.exec_cmd(rmcmd) jar_signer = Utils.get_full_path('tools/jdk/bin/jarsigner') sign_cmd = "%s -keystore %s -storepass %s -keypass %s %s %s -sigalg SHA1withRSA -digestalg SHA1" % ( jar_signer, key_path, game['keypwd'], game['aliaspwd'], apk_file, game['alias']) return Utils.exec_cmd(sign_cmd)
def select_ketstore(self): fname = QFileDialog.getOpenFileName( self, '选择签名文件', Utils.get_full_path('games/' + self.game['id'] + '/keystore/')) if fname[0]: if os.path.samefile( fname[0], Utils.get_full_path('games/' + self.game['id'] + '/keystore/' + self.game['keystore'])): self.keystore_path.setText(self.game['keystore']) self.keystore_pwd_value.setText(self.game['keypwd']) self.keystore_alias_value.setText(self.game['alias']) self.keystore_aliaspwd_value.setText(self.game['aliaspwd']) self.keystore_exchanged = False else: self.keystore_path.setText(fname[0]) self.keystore_pwd_value.clear() self.keystore_alias_value.clear() self.keystore_aliaspwd_value.clear() self.keystore_exchanged = True
def next(self): if not self.save_data(): return channels = Utils.get_channels( Utils.get_full_path('games/' + self.game['id'] + '/config.xml')) if channels is None: if not os.path.exists(Utils.get_full_path('channelsdk')): QMessageBox.warning( self, "警告", os.path.dirname(os.getcwd()) + " 没有channelsdk文件夹") return elif len(os.listdir(Utils.get_full_path('channelsdk'))) <= 0: QMessageBox.warning( self, "警告", "本地没有渠道sdk,请手动添加sdk文件夹到" + Utils.get_full_path('channelsdk')) return channels = [] self.main_win.set_add_channel_widget(channels) else: self.main_win.set_channel_list_widget(channels)
def set_game_info(self): self.game_name_value.setText(self.game['name']) self.game_desc_value.setText(self.game['desc']) self.game_appid_value.setText(self.game['id']) self.game_appkey_value.setText(self.game['key']) self.keystore_path.setText(self.game['keystore']) self.keystore_pwd_value.setText(self.game['keypwd']) self.keystore_alias_value.setText(self.game['alias']) self.keystore_aliaspwd_value.setText(self.game['aliaspwd']) icon = Utils.get_full_path('games/' + self.game['id'] + '/icon/icon.png') if not os.path.exists(icon): icon = 'icon.png' self.icon_img.setPixmap(QPixmap(icon))
def __init__(self): super(MainWindow, self).__init__() LogUtils.add_logger() self.games = Utils.get_games(Utils.get_full_path('games/games.xml')) self.game_index = 0 self.setObjectName("MainWindow") self.resize(960, 540) size_policy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) size_policy.setHorizontalStretch(0) size_policy.setVerticalStretch(0) size_policy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) self.setSizePolicy(size_policy) self.setWindowIcon(QIcon('pack.ico')) self.set_main_widget()
def save_data(self): self.channel['gameName'] = self.game_name_value.text().strip() self.channel['package'] = self.game_package_value.text().strip() self.channel['gameVersionCode'] = self.game_vcode_value.text().strip() self.channel['gameVersionName'] = self.game_vname_value.text().strip() self.channel['debug'] = self.debug_value.text().strip() i = 0 while i < len(self.linedit_list): if self.linedit_list[i].text().strip() == "": QMessageBox.warning(self, "警告", "渠道参数不能为空!") return False self.channel['sdkParams'][i]['value'] = self.linedit_list[i].text( ).strip() i += 1 self.channels[self.channel_index] = self.channel game_id = self.main_win.games[self.main_win.game_index]['id'] return Utils.update_channels( Utils.get_full_path('games/' + game_id + '/config.xml'), self.channel, self.channel_index)
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)
def select_game(self, p_int): self.game_index = p_int if 'apk' in self.main_win.games[self.game_index]: self.apk_path.setText(self.main_win.games[self.game_index]['apk']) else: self.apk_path.setText("<h3><font color=%s>%s</font></h3>" % ('red', "请浏览选择本地母包路径")) # self.apk_path.setText("请浏览选择本地母包路径") # 当前选中的game,其下的所有渠道列表 self.channels = Utils.get_channels( Utils.get_full_path('games/' + self.main_win.games[p_int]['id'] + '/config.xml')) channel_ids = [] for channel in self.channels: channel_ids.append(channel['channelId']) list_model = QStringListModel() list_model.setStringList(channel_ids) self.clv = self.tool_box.currentWidget() self.clv.doubleClicked.connect(self.select_channel) self.clv.setModel(list_model)
def data(self, index, role): if index.isValid() or (0 <= index.row() < len(self.ListItemData)): if role == Qt.DisplayRole: return QVariant(self.games[index.row()]['id']) elif role == Qt.DecorationRole: icon = self.games[index.row()]['id'] icon = Utils.get_full_path('games/' + icon + '/icon/icon.png') if not os.path.exists(icon): icon = 'icon.png' return QVariant(QIcon(icon)) elif role == Qt.SizeHintRole: return QVariant(QSize(80, 80)) elif role == Qt.TextAlignmentRole: return QVariant(int(Qt.AlignHCenter | Qt.AlignVCenter)) elif role == Qt.FontRole: font = QFont() font.setPixelSize(16) font.setFamily("Microsoft YaHei") return QVariant(font) else: return QVariant()
def del_channel(self): reply = QMessageBox.warning(self, "警告", "确定删除当前渠道?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: # 更新listview self.channel_ids.pop(self.channel_index) self.list_model.setStringList(self.channel_ids) # 更新表单view(index前移一位) self.channel = self.channels[self.channel_index - 1] self.set_info() # 更新本地数据 self.channels.pop(self.channel_index) game_id = self.main_win.games[self.main_win.game_index]['id'] Utils.del_channel( Utils.get_full_path('games/' + game_id + '/config.xml'), self.channel_index) # 重置index,防止 index out of range self.channel_index = self.channel_index - 1 if self.channel_index < 0: reply = QMessageBox.warning(self, "警告", "当前游戏未添加渠道,将返回游戏列表界面!", QMessageBox.Yes) if reply == QMessageBox.Yes: self.back()
def align_apk(apk_file, target_file): align = Utils.get_full_path('tools/zipalign.exe') cmd = '%s -f 4 %s %s' % (align, apk_file, target_file) return Utils.exec_cmd(cmd)
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)
def recompile_apk(source_folder, apk_file, frame_work_dir): java = Utils.get_full_path('tools/jdk/bin/java') apk_tool = Utils.get_full_path('tools/apktool.jar') cmd = "%s -jar %s b %s -o %s -p %s" % (java, apk_tool, source_folder, apk_file, frame_work_dir) return Utils.exec_cmd(cmd)
def append_channel_mark(game, sdk_dest_dir, decompile_dir): game_icon_path = 'games/' + game['id'] + '/icon/icon.png' game_icon_path = Utils.get_full_path(game_icon_path) if not os.path.exists(game_icon_path): LogUtils.info('The game %s icon is not exists : %s', game['id'], game_icon_path) return LogUtils.info('The game %s icon path : %s', game['id'], game_icon_path) game_icon_name = get_app_icon_name(decompile_dir) if game_icon_name is None: return game_icon_name = game_icon_name + '.png' LogUtils.info('The game icon name: %s', game_icon_name) icon_img = Image.open(game_icon_path) mark_path = sdk_dest_dir + '/mark.png' if not os.path.exists(mark_path): LogUtils.info('The mark path is not exists : %s', mark_path) else: LogUtils.info('The mark path : %s', mark_path) mark_img = Image.open(mark_path) icon_img = merge_icon_mark(icon_img, mark_img, (0, 0)) ldpi_icon = icon_img.resize((36, 36), Image.ANTIALIAS) mdpi_icon = icon_img.resize((48, 48), Image.ANTIALIAS) hdpi_icon = icon_img.resize((72, 72), Image.ANTIALIAS) xhdpi_icon = icon_img.resize((96, 96), Image.ANTIALIAS) xxhdpi_icon = icon_img.resize((144, 144), Image.ANTIALIAS) xxxhdpi_icon = icon_img.resize((192, 192), Image.ANTIALIAS) icons = (ldpi_icon, mdpi_icon, hdpi_icon, xhdpi_icon, xxhdpi_icon, xxxhdpi_icon) drawables = ('drawable-ldpi', 'drawable-mdpi', 'drawable-hdpi', 'drawable-xhdpi', 'drawable-xxhdpi', 'drawable-xxxhdpi') mipmaps = ('mipmap-ldpi', 'mipmap-mdpi', 'mipmap-hdpi', 'mipmap-xhdpi', 'mipmap-xxhdpi', 'mipmap-xxxhdpi') for drawable in drawables: icon_dir = decompile_dir + '/res/' + drawable Utils.del_file(icon_dir + '/' + game_icon_name) if os.path.exists(icon_dir) and len(os.listdir(icon_dir)) <= 0: os.rmdir(icon_dir) icon_dir = decompile_dir + '/res/' + drawable + '-v4' Utils.del_file(icon_dir + '/' + game_icon_name) if os.path.exists(icon_dir) and len(os.listdir(icon_dir)) <= 0: os.rmdir(icon_dir) if not os.path.exists(decompile_dir + '/res/drawable'): os.mkdir(decompile_dir + '/res/drawable') xxhdpi_icon.save(decompile_dir + '/res/drawable/' + game_icon_name, 'PNG') for i in range(len(mipmaps)): icon_dir = decompile_dir + '/res/' + mipmaps[i] + '-v4' Utils.del_file(icon_dir + '/' + game_icon_name) if os.path.exists(icon_dir) and len(os.listdir(icon_dir)) <= 0: os.rmdir(icon_dir) icon_dir = decompile_dir + '/res/' + mipmaps[i] if not os.path.exists(icon_dir): os.makedirs(icon_dir) icons[i].save(os.path.join(icon_dir, game_icon_name), 'PNG')
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()