This commit is contained in:
		
							parent
							
								
									b8ddea3a9a
								
							
						
					
					
						commit
						eb9da1489d
					
				| 
						 | 
					@ -9,6 +9,11 @@ from .project_proguard import ProjectProguard
 | 
				
			||||||
from .project_res_md5 import ProjectResMd5
 | 
					from .project_res_md5 import ProjectResMd5
 | 
				
			||||||
from .project_res_string import ProjectResString
 | 
					from .project_res_string import ProjectResString
 | 
				
			||||||
from .project_update import ProjectUpdate
 | 
					from .project_update import ProjectUpdate
 | 
				
			||||||
 | 
					from .project_update_config import ProjectUpdateConfig
 | 
				
			||||||
 | 
					from .project_update_game_res import ProjectUpdateGameRes
 | 
				
			||||||
 | 
					from .project_update_icon import ProjectUpdateIcon
 | 
				
			||||||
 | 
					from .project_update_image import ProjectUpdateImage
 | 
				
			||||||
 | 
					from .project_update_keystore import ProjectUpdateKeystore
 | 
				
			||||||
from .project_upload import ProjectUpload
 | 
					from .project_upload import ProjectUpload
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,6 +23,11 @@ def run(context: Context):
 | 
				
			||||||
        ProjectInit(context),
 | 
					        ProjectInit(context),
 | 
				
			||||||
        ProjectCopy(context),
 | 
					        ProjectCopy(context),
 | 
				
			||||||
        ProjectResMd5(context),
 | 
					        ProjectResMd5(context),
 | 
				
			||||||
 | 
					        ProjectUpdateKeystore(context),
 | 
				
			||||||
 | 
					        ProjectUpdateConfig(context),
 | 
				
			||||||
 | 
					        ProjectUpdateIcon(context),
 | 
				
			||||||
 | 
					        ProjectUpdateImage(context),
 | 
				
			||||||
 | 
					        ProjectUpdateGameRes(context),
 | 
				
			||||||
        ProjectUpdate(context),
 | 
					        ProjectUpdate(context),
 | 
				
			||||||
        ProjectResString(context),
 | 
					        ProjectResString(context),
 | 
				
			||||||
        ProjectInterface(context),
 | 
					        ProjectInterface(context),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,12 @@
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
from dataclasses import dataclass
 | 
					from dataclasses import dataclass
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@dataclass
 | 
					@dataclass
 | 
				
			||||||
class Context:
 | 
					class Context:
 | 
				
			||||||
 | 
					    project_original_path: str
 | 
				
			||||||
 | 
					    local_repo_commit: str
 | 
				
			||||||
    repo_url: str = ""
 | 
					    repo_url: str = ""
 | 
				
			||||||
    repo_branch: str = ""
 | 
					    repo_branch: str = ""
 | 
				
			||||||
    repo_commit: str = ""
 | 
					    repo_commit: str = ""
 | 
				
			||||||
| 
						 | 
					@ -18,6 +21,7 @@ class Context:
 | 
				
			||||||
    project_original_path: str = "project/original"
 | 
					    project_original_path: str = "project/original"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    temp_project_path: str = ""
 | 
					    temp_project_path: str = ""
 | 
				
			||||||
 | 
					    temp_project_config_path: str = ""
 | 
				
			||||||
    # 本地的版本号
 | 
					    # 本地的版本号
 | 
				
			||||||
    local_repo_branch: str = ""
 | 
					    local_repo_branch: str = ""
 | 
				
			||||||
    local_repo_commit: str = ""
 | 
					    local_repo_commit: str = ""
 | 
				
			||||||
| 
						 | 
					@ -44,6 +48,24 @@ class Context:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    string: dict = None
 | 
					    string: dict = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    update_code: bool = True
 | 
				
			||||||
 | 
					    update_config: bool = True
 | 
				
			||||||
 | 
					    update_keystore: bool = True
 | 
				
			||||||
 | 
					    update_res_img: bool = True
 | 
				
			||||||
 | 
					    update_res_icon: bool = True
 | 
				
			||||||
 | 
					    update_res_unity: bool = True
 | 
				
			||||||
 | 
					    config_path: str = ""
 | 
				
			||||||
 | 
					    keystore_path: str = ""
 | 
				
			||||||
 | 
					    res_img_path: str = ""
 | 
				
			||||||
 | 
					    res_icon_path: str = ""
 | 
				
			||||||
 | 
					    res_unity_path: str = ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    config_config_md5: str = ""
 | 
				
			||||||
 | 
					    config_keystore_md5: str = ""
 | 
				
			||||||
 | 
					    config_res_img_md5: str = ""
 | 
				
			||||||
 | 
					    config_res_icon_md5: str = ""
 | 
				
			||||||
 | 
					    config_res_unity_md5: str = ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def from_json(cls, json_str: str):
 | 
					    def from_json(cls, json_str: str):
 | 
				
			||||||
        data = json.loads(json_str)
 | 
					        data = json.loads(json_str)
 | 
				
			||||||
| 
						 | 
					@ -58,3 +80,37 @@ class Context:
 | 
				
			||||||
        if self.app_name:
 | 
					        if self.app_name:
 | 
				
			||||||
            return self.app_name
 | 
					            return self.app_name
 | 
				
			||||||
        return self.get_config("app_name")
 | 
					        return self.get_config("app_name")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_cache_config(self) -> dict[str, str]:
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            path = os.path.join(self.temp_project_config_path, "config.json")
 | 
				
			||||||
 | 
					            args = json.load(open(path, "r", encoding="utf-8"))
 | 
				
			||||||
 | 
					            return args
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            return {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_cache_config_from_key(self, key: str, default: str = "") -> str:
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            return self.get_cache_config().get(key, default)
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            return default
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def save_cache_config(self, key: str, value: str):
 | 
				
			||||||
 | 
					        path = os.path.join(self.temp_project_config_path, "config.json")
 | 
				
			||||||
 | 
					        config = self.get_cache_config()
 | 
				
			||||||
 | 
					        config[key] = value
 | 
				
			||||||
 | 
					        json.dump(config, open(path, "w", encoding="utf-8"), indent=4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_map(self) -> dict[str, str]:
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            path = os.path.join(self.temp_project_config_path, "map.json")
 | 
				
			||||||
 | 
					            return json.load(open(path, "r", encoding="utf-8"))
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            return {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def save_map(self, map: dict[str, str]):
 | 
				
			||||||
 | 
					        path = os.path.join(self.temp_project_config_path, "map.json")
 | 
				
			||||||
 | 
					        json.dump(map, open(path, "w", encoding="utf-8"), indent=4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_map_from_key(self, file_name) -> str:
 | 
				
			||||||
 | 
					        return self.get_map().get(file_name, file_name)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,7 +39,7 @@ class ProjectBuild(Task):
 | 
				
			||||||
    def execute(self):
 | 
					    def execute(self):
 | 
				
			||||||
        self.init()
 | 
					        self.init()
 | 
				
			||||||
        # self.save_project()
 | 
					        # self.save_project()
 | 
				
			||||||
        self.build_apk()
 | 
					        # self.build_apk()
 | 
				
			||||||
        self.build_aab()
 | 
					        self.build_aab()
 | 
				
			||||||
        self.copy_to_out()
 | 
					        self.copy_to_out()
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
| 
						 | 
					@ -54,12 +54,12 @@ class ProjectBuild(Task):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def copy_to_out(self):
 | 
					    def copy_to_out(self):
 | 
				
			||||||
        app_logger().debug(f"copy_to_out start.")
 | 
					        app_logger().debug(f"copy_to_out start.")
 | 
				
			||||||
        target = f"{self.context.temp_project_path}{os.sep}build{os.sep}outputs{os.sep}apk{os.sep}lawnWithQuickstepPlay{os.sep}debug"
 | 
					        # target = f"{self.context.temp_project_path}{os.sep}build{os.sep}outputs{os.sep}apk{os.sep}lawnWithQuickstepPlay{os.sep}debug"
 | 
				
			||||||
        FileUtils.copy(find_path(target, "apk"), self.context.out_debug_apk)
 | 
					        # FileUtils.copy(find_path(target, "apk"), self.context.out_debug_apk)
 | 
				
			||||||
        app_logger().debug(f"copy_to_out debug apk = {self.context.out_debug_apk}")
 | 
					        # app_logger().debug(f"copy_to_out debug apk = {self.context.out_debug_apk}")
 | 
				
			||||||
        target = f"{self.context.temp_project_path}{os.sep}build{os.sep}outputs{os.sep}apk{os.sep}lawnWithQuickstepPlay{os.sep}release"
 | 
					        # target = f"{self.context.temp_project_path}{os.sep}build{os.sep}outputs{os.sep}apk{os.sep}lawnWithQuickstepPlay{os.sep}release"
 | 
				
			||||||
        FileUtils.copy(find_path(target, "apk"), self.context.out_release_apk)
 | 
					        # FileUtils.copy(find_path(target, "apk"), self.context.out_release_apk)
 | 
				
			||||||
        app_logger().debug(f"copy_to_out release apk = {self.context.out_release_apk}")
 | 
					        # app_logger().debug(f"copy_to_out release apk = {self.context.out_release_apk}")
 | 
				
			||||||
        target = f"{self.context.temp_project_path}{os.sep}build{os.sep}outputs{os.sep}bundle{os.sep}lawnWithQuickstepPlayRelease"
 | 
					        target = f"{self.context.temp_project_path}{os.sep}build{os.sep}outputs{os.sep}bundle{os.sep}lawnWithQuickstepPlayRelease"
 | 
				
			||||||
        FileUtils.copy(find_path(target, "aab"), self.context.out_release_aab)
 | 
					        FileUtils.copy(find_path(target, "aab"), self.context.out_release_aab)
 | 
				
			||||||
        app_logger().debug(f"copy_to_out end.")
 | 
					        app_logger().debug(f"copy_to_out end.")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,21 +1,63 @@
 | 
				
			||||||
 | 
					import os.path
 | 
				
			||||||
 | 
					import shutil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from git import Repo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from scripts.task import Task
 | 
					from scripts.task import Task
 | 
				
			||||||
from utils import FileUtils
 | 
					from utils import FileUtils
 | 
				
			||||||
from utils import TimeUtils
 | 
					 | 
				
			||||||
from utils.logger_utils import app_logger
 | 
					from utils.logger_utils import app_logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def clean_workspace(repo):
 | 
				
			||||||
 | 
					    # 1. 放弃工作区所有已跟踪文件的修改(包括恢复被删除的已跟踪文件)
 | 
				
			||||||
 | 
					    #   - checkout 命令会将工作区文件重置为当前 HEAD 版本的状态
 | 
				
			||||||
 | 
					    repo.git.checkout('.')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # 2. 删除工作区所有未跟踪的文件和目录(包括空目录)
 | 
				
			||||||
 | 
					    #   - -f:强制删除(避免询问)
 | 
				
			||||||
 | 
					    #   - -d:同时删除未跟踪的目录
 | 
				
			||||||
 | 
					    repo.git.clean('-fd')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print("工作空间已清空,恢复到当前分支最新提交状态")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ProjectCopy(Task):
 | 
					class ProjectCopy(Task):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def execute(self):
 | 
					    def execute(self):
 | 
				
			||||||
        self.init()
 | 
					        if os.path.exists(self.context.temp_project_path):
 | 
				
			||||||
 | 
					            temp_path = os.path.join(self.context.temp_project_path, "build", "outputs")
 | 
				
			||||||
 | 
					            if os.path.exists(temp_path):
 | 
				
			||||||
 | 
					                shutil.rmtree(temp_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            temp_path = os.path.join(self.context.temp_project_path, "build", "generated")
 | 
				
			||||||
 | 
					            if os.path.exists(temp_path):
 | 
				
			||||||
 | 
					                shutil.rmtree(temp_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            app_logger().debug("project '{}' to '{}'".format(self.context.temp_project_path, "项目已经存在了"))
 | 
				
			||||||
 | 
					            repo = Repo(self.context.temp_project_path)
 | 
				
			||||||
 | 
					            temp_repo_commit = repo.head.commit.hexsha[:10]
 | 
				
			||||||
 | 
					            app_logger().debug(
 | 
				
			||||||
 | 
					                f"project '{self.context.temp_project_path}' , local '{temp_repo_commit}' remote '{self.context.local_repo_commit}")
 | 
				
			||||||
 | 
					            if temp_repo_commit != self.context.local_repo_commit:
 | 
				
			||||||
 | 
					                app_logger().debug("本地代码有变动,需要更新临时的目录")
 | 
				
			||||||
 | 
					                # 本地分支和远程的分支不一样
 | 
				
			||||||
 | 
					                clean_workspace(repo)
 | 
				
			||||||
 | 
					                origin = repo.remote("origin")
 | 
				
			||||||
 | 
					                origin.fetch()
 | 
				
			||||||
 | 
					                repo.git.checkout(self.context.local_repo_commit)
 | 
				
			||||||
 | 
					                self.context.update_code = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                self.context.update_config = True
 | 
				
			||||||
 | 
					                self.context.update_keystore = True
 | 
				
			||||||
 | 
					                self.context.update_res_img = True
 | 
				
			||||||
 | 
					                self.context.update_res_icon = True
 | 
				
			||||||
 | 
					                self.context.update_res_unity = True
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                self.context.update_code = False
 | 
				
			||||||
 | 
					                app_logger().debug("本地的代码没有变动,无需更新")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.context.update_code = True
 | 
				
			||||||
        result = FileUtils.copy(self.context.project_original_path, self.context.temp_project_path)
 | 
					        result = FileUtils.copy(self.context.project_original_path, self.context.temp_project_path)
 | 
				
			||||||
        app_logger().debug("Copied project '{}' to '{}'".format(self.context.project_original_path, result))
 | 
					        app_logger().debug("Copied project '{}' to '{}'".format(self.context.project_original_path, result))
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def init(self):
 | 
					 | 
				
			||||||
        self.context.temp_project_path = self.context.project_original_path.replace(
 | 
					 | 
				
			||||||
            "original", self.context.package_name.replace(".", "_") + TimeUtils.get_formatted_time(format_str="%H%M%S")
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        # self.context.temp_project_path = self.context.project_original_path
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        pass
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,5 +4,5 @@ from utils import FileUtils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ProjectEnd(Task):
 | 
					class ProjectEnd(Task):
 | 
				
			||||||
    def execute(self):
 | 
					    def execute(self):
 | 
				
			||||||
        FileUtils.delete(self.context.temp_project_path, True)
 | 
					        # FileUtils.delete(self.context.temp_project_path, True)
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,11 @@
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
import time
 | 
					import time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from git import Repo, RemoteProgress
 | 
					from git import Repo, RemoteProgress
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from utils import FileUtils
 | 
				
			||||||
 | 
					from utils.logger_utils import app_logger
 | 
				
			||||||
 | 
					from .context import Context
 | 
				
			||||||
from .task import Task
 | 
					from .task import Task
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +15,72 @@ def progress(op_code, cur_count, max_count=None, message=''):
 | 
				
			||||||
    print(f"操作: {op_code}, 进度: {cur_count}/{max_count}, 消息: {message}")
 | 
					    print(f"操作: {op_code}, 进度: {cur_count}/{max_count}, 消息: {message}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def check_config_exists(*file_paths):
 | 
				
			||||||
 | 
					    # game_config/com.diy.emoticon.free.zcaqf.game.launcher/com.diy.emoticon.free.zcaqf.game.launcher_android.zip
 | 
				
			||||||
 | 
					    # game_config/com.emoticon.diy.znfav.launcher.free/com.emoticon.diy.znfav.launcher.free_android.zip
 | 
				
			||||||
 | 
					    # 遍历检查每个文件
 | 
				
			||||||
 | 
					    if file_paths is None:
 | 
				
			||||||
 | 
					        file_paths = []
 | 
				
			||||||
 | 
					    for file_path in file_paths:
 | 
				
			||||||
 | 
					        if not os.path.exists(file_path):
 | 
				
			||||||
 | 
					            # 抛出异常并说明缺失的文件路径
 | 
				
			||||||
 | 
					            raise FileNotFoundError(f"配置文件不存在: {file_path}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ProjectInit(Task):
 | 
					class ProjectInit(Task):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, context: Context):
 | 
				
			||||||
 | 
					        super().__init__(context)
 | 
				
			||||||
 | 
					        self.context.temp_project_path = self.context.project_original_path.replace("original",
 | 
				
			||||||
 | 
					                                                                                    "V1_" + self.context.package_name.replace(
 | 
				
			||||||
 | 
					                                                                                        ".", "_"))
 | 
				
			||||||
 | 
					        self.context.temp_project_config_path = self.context.temp_project_path + "_config"
 | 
				
			||||||
 | 
					        if not os.path.exists(self.context.temp_project_config_path):
 | 
				
			||||||
 | 
					            os.makedirs(self.context.temp_project_config_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        config_md5 = context.get_cache_config_from_key("config", "")
 | 
				
			||||||
 | 
					        keystore_md5 = context.get_cache_config_from_key("keystore", "")
 | 
				
			||||||
 | 
					        res_img_md5 = context.get_cache_config_from_key("res_img", "")
 | 
				
			||||||
 | 
					        res_icon_md5 = context.get_cache_config_from_key("res_icon", "")
 | 
				
			||||||
 | 
					        res_unity_md5 = context.get_cache_config_from_key("res_unity", "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        app_logger().debug(f"temp project res md5 , "
 | 
				
			||||||
 | 
					                           f"config : {config_md5} , "
 | 
				
			||||||
 | 
					                           f"keystore : {keystore_md5} , "
 | 
				
			||||||
 | 
					                           f"res_img : {res_img_md5} , "
 | 
				
			||||||
 | 
					                           f"res_icon : {res_icon_md5} , "
 | 
				
			||||||
 | 
					                           f"res_unity : {res_unity_md5}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        config_root_path = os.path.join("game_config", self.context.package_name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.context.config_path = os.path.join(config_root_path, f"{self.context.package_name}_android.zip")
 | 
				
			||||||
 | 
					        self.context.keystore_path = ""
 | 
				
			||||||
 | 
					        for i in os.listdir(config_root_path):
 | 
				
			||||||
 | 
					            if i.endswith(".keystore"):
 | 
				
			||||||
 | 
					                self.context.keystore_path = os.path.join(config_root_path, i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.context.res_img_path = os.path.join(config_root_path, "drawable-xxhdpi.zip")
 | 
				
			||||||
 | 
					        self.context.res_icon_path = os.path.join(config_root_path, "icon.zip")
 | 
				
			||||||
 | 
					        self.context.res_unity_path = os.path.join(config_root_path, "unityLibrary.zip")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        check_config_exists(self.context.config_path,
 | 
				
			||||||
 | 
					                            self.context.keystore_path,
 | 
				
			||||||
 | 
					                            self.context.res_img_path,
 | 
				
			||||||
 | 
					                            self.context.res_icon_path,
 | 
				
			||||||
 | 
					                            self.context.res_unity_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.context.config_config_md5 = FileUtils.get_md5(self.context.config_path)
 | 
				
			||||||
 | 
					        self.context.config_keystore_md5 = FileUtils.get_md5(self.context.keystore_path)
 | 
				
			||||||
 | 
					        self.context.config_res_img_md5 = FileUtils.get_md5(self.context.res_img_path)
 | 
				
			||||||
 | 
					        self.context.config_res_icon_md5 = FileUtils.get_md5(self.context.res_icon_path)
 | 
				
			||||||
 | 
					        self.context.config_res_unity_md5 = FileUtils.get_md5(self.context.res_unity_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.context.update_config = config_md5 != self.context.config_config_md5
 | 
				
			||||||
 | 
					        self.context.update_keystore = keystore_md5 != self.context.config_keystore_md5
 | 
				
			||||||
 | 
					        self.context.update_res_img = res_img_md5 != self.context.config_res_img_md5
 | 
				
			||||||
 | 
					        self.context.update_res_icon = res_icon_md5 != self.context.config_res_icon_md5
 | 
				
			||||||
 | 
					        self.context.update_res_unity = res_unity_md5 != self.context.config_res_unity_md5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def execute(self):
 | 
					    def execute(self):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            repo = Repo(self.context.project_original_path)
 | 
					            repo = Repo(self.context.project_original_path)
 | 
				
			||||||
| 
						 | 
					@ -45,12 +115,13 @@ class ProjectInit(Task):
 | 
				
			||||||
                    local_branch.set_tracking_branch(repo.remotes[remote_name].refs[branch_name])  # 设置跟踪
 | 
					                    local_branch.set_tracking_branch(repo.remotes[remote_name].refs[branch_name])  # 设置跟踪
 | 
				
			||||||
                    local_branch.checkout()  # 切换到该分支
 | 
					                    local_branch.checkout()  # 切换到该分支
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # 拉取最新代码
 | 
				
			||||||
 | 
					            repo.remotes.origin.pull()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self.context.local_repo_branch = repo.active_branch.name
 | 
					            self.context.local_repo_branch = repo.active_branch.name
 | 
				
			||||||
            self.context.local_repo_commit = repo.head.commit.hexsha[:10]
 | 
					            self.context.local_repo_commit = repo.head.commit.hexsha[:10]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # 拉取最新代码
 | 
					            print("当前分支:" + repo.active_branch.name, self.context.local_repo_commit)
 | 
				
			||||||
            repo.remotes.origin.pull()
 | 
					 | 
				
			||||||
            print("当前分支:" + repo.active_branch.name)
 | 
					 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            raise Exception(f"No commit to {self.context.repo_commit}")
 | 
					            raise Exception(f"No commit to {self.context.repo_commit}")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,7 @@ import os
 | 
				
			||||||
import hashlib
 | 
					import hashlib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from utils import FileUtils
 | 
					from utils import FileUtils
 | 
				
			||||||
 | 
					from utils.logger_utils import app_logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def string_to_md5(text):
 | 
					def string_to_md5(text):
 | 
				
			||||||
| 
						 | 
					@ -65,6 +66,9 @@ class ProjectInterface(Task):
 | 
				
			||||||
                    f_out.write(line)
 | 
					                    f_out.write(line)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def execute(self):
 | 
					    def execute(self):
 | 
				
			||||||
 | 
					        if not self.context.update_code:
 | 
				
			||||||
 | 
					            app_logger().info("代码没有更新,不需要处理 unity 接口")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.unity_proxy_api_file = os.path.join(self.context.temp_project_path,
 | 
					        self.unity_proxy_api_file = os.path.join(self.context.temp_project_path,
 | 
				
			||||||
                                                 "launcher-game/src/com/game/hachisdk/unity/UnityProxyApi.java".replace(
 | 
					                                                 "launcher-game/src/com/game/hachisdk/unity/UnityProxyApi.java".replace(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -276,6 +276,10 @@ class ProjectProguard(Task):
 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def execute(self):
 | 
					    def execute(self):
 | 
				
			||||||
 | 
					        if not self.context.update_code:
 | 
				
			||||||
 | 
					            app_logger().info("No update project proguard found")
 | 
				
			||||||
 | 
					            self.context.proguard_dict = self.context.get_map()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
        self.root = self.context.temp_project_path
 | 
					        self.root = self.context.temp_project_path
 | 
				
			||||||
        self.module_path = os.path.join(self.root, "launcher-game")
 | 
					        self.module_path = os.path.join(self.root, "launcher-game")
 | 
				
			||||||
        self.code_path = os.path.join(self.module_path, "src")
 | 
					        self.code_path = os.path.join(self.module_path, "src")
 | 
				
			||||||
| 
						 | 
					@ -324,6 +328,7 @@ class ProjectProguard(Task):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        encrypt_xml_resources(self.string_path, False, string_to_md5(self.context.package_name).upper())
 | 
					        encrypt_xml_resources(self.string_path, False, string_to_md5(self.context.package_name).upper())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.context.save_map(self.context.proguard_dict)
 | 
				
			||||||
        app_logger().info(json.dumps(self.context.proguard_dict, indent=4))
 | 
					        app_logger().info(json.dumps(self.context.proguard_dict, indent=4))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# if __name__ == '__main__':
 | 
					# if __name__ == '__main__':
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,8 @@ import hashlib
 | 
				
			||||||
from PIL import Image
 | 
					from PIL import Image
 | 
				
			||||||
import random
 | 
					import random
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from utils.logger_utils import app_logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_md5(file_path):
 | 
					def get_md5(file_path):
 | 
				
			||||||
    """计算文件的MD5值"""
 | 
					    """计算文件的MD5值"""
 | 
				
			||||||
| 
						 | 
					@ -64,6 +66,9 @@ def modify_one_pixel(input_path, output_path):
 | 
				
			||||||
class ProjectResMd5(Task):
 | 
					class ProjectResMd5(Task):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def execute(self):
 | 
					    def execute(self):
 | 
				
			||||||
 | 
					        if not self.context.update_code:
 | 
				
			||||||
 | 
					            app_logger().info("不需要更新res md5")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
        path = f"launcher-game/res/"
 | 
					        path = f"launcher-game/res/"
 | 
				
			||||||
        root_path = os.path.join(self.context.temp_project_path, path)
 | 
					        root_path = os.path.join(self.context.temp_project_path, path)
 | 
				
			||||||
        for i in os.listdir(root_path):
 | 
					        for i in os.listdir(root_path):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,6 +37,9 @@ class ProjectResString(Task):
 | 
				
			||||||
        app_logger().debug("路径不存,不操作了,后续可以给他创建出来:" + string_path + "\t" + json.dumps(res, indent=4))
 | 
					        app_logger().debug("路径不存,不操作了,后续可以给他创建出来:" + string_path + "\t" + json.dumps(res, indent=4))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def execute(self):
 | 
					    def execute(self):
 | 
				
			||||||
 | 
					        if not self.context.update_code:
 | 
				
			||||||
 | 
					            app_logger().info("代码没有更新,不需要处理资源")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
        for key in self.context.string.keys():
 | 
					        for key in self.context.string.keys():
 | 
				
			||||||
            launcher = key.replace('base', '')
 | 
					            launcher = key.replace('base', '')
 | 
				
			||||||
            if launcher:
 | 
					            if launcher:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,86 +1,11 @@
 | 
				
			||||||
import os.path
 | 
					import os.path
 | 
				
			||||||
from pathlib import Path
 | 
					 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
from xml.dom import minidom
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import javaproperties
 | 
					 | 
				
			||||||
import requests
 | 
					 | 
				
			||||||
from lxml import etree
 | 
					 | 
				
			||||||
import xml.etree.ElementTree as ET
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from scripts.context import Context
 | 
					from scripts.context import Context
 | 
				
			||||||
from scripts.task import Task
 | 
					from scripts.task import Task
 | 
				
			||||||
from utils import FileUtils
 | 
					 | 
				
			||||||
from utils.logger_utils import app_logger
 | 
					from utils.logger_utils import app_logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def process_manifest(input_path, output_path):
 | 
					 | 
				
			||||||
    # 解析XML文件
 | 
					 | 
				
			||||||
    tree = ET.parse(input_path)
 | 
					 | 
				
			||||||
    root = tree.getroot()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # 定义命名空间映射
 | 
					 | 
				
			||||||
    android_namespace = 'http://schemas.android.com/apk/res/android'
 | 
					 | 
				
			||||||
    ET.register_namespace('android', android_namespace)
 | 
					 | 
				
			||||||
    namespaces = {'android': android_namespace}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # 处理application标签,移除所有属性
 | 
					 | 
				
			||||||
    application = root.find('application')
 | 
					 | 
				
			||||||
    if application is not None:
 | 
					 | 
				
			||||||
        # 保存所有子节点
 | 
					 | 
				
			||||||
        children = list(application)
 | 
					 | 
				
			||||||
        # 清除application标签
 | 
					 | 
				
			||||||
        root.remove(application)
 | 
					 | 
				
			||||||
        # 创建新的application标签(无属性)
 | 
					 | 
				
			||||||
        new_application = ET.Element('application')
 | 
					 | 
				
			||||||
        # 添加回所有子节点
 | 
					 | 
				
			||||||
        for child in children:
 | 
					 | 
				
			||||||
            new_application.append(child)
 | 
					 | 
				
			||||||
        # 将新的application标签添加回root
 | 
					 | 
				
			||||||
        root.append(new_application)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # 查找并删除指定的activity节点
 | 
					 | 
				
			||||||
        activity_to_remove = new_application.find(
 | 
					 | 
				
			||||||
            ".//activity[@android:name='com.unity3d.player.UnityPlayerActivity']",
 | 
					 | 
				
			||||||
            namespaces=namespaces
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        if activity_to_remove is not None:
 | 
					 | 
				
			||||||
            new_application.remove(activity_to_remove)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # 保存处理后的XML,保留android命名空间前缀
 | 
					 | 
				
			||||||
    rough_string = ET.tostring(root, 'utf-8')
 | 
					 | 
				
			||||||
    reparsed = minidom.parseString(rough_string)
 | 
					 | 
				
			||||||
    pretty_xml = reparsed.toprettyxml(indent="  ", encoding='utf-8')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # 去除空行
 | 
					 | 
				
			||||||
    lines = pretty_xml.decode('utf-8').split('\n')
 | 
					 | 
				
			||||||
    non_empty_lines = [line for line in lines if line.strip() != '']
 | 
					 | 
				
			||||||
    pretty_xml = '\n'.join(non_empty_lines).encode('utf-8')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    with open(output_path, 'wb') as f:
 | 
					 | 
				
			||||||
        f.write(pretty_xml)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    print(f"处理完成,结果已保存到 {output_path}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def uncomment_line(content, line_pattern):
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    取消指定行的注释
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    :param content: 文件内容
 | 
					 | 
				
			||||||
    :param line_pattern: 要取消注释的行内容(不含前导//和空格)
 | 
					 | 
				
			||||||
    :return: 更新后的内容
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    # 匹配以//开头,后跟任意空格,然后是目标行内容
 | 
					 | 
				
			||||||
    pattern = rf'^(\s*)//\s*({re.escape(line_pattern)}\s*)$'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # 替换为去注释版本(保留原有缩进)
 | 
					 | 
				
			||||||
    replacement = rf'\1\2'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    updated_content = re.sub(pattern, replacement, content, flags=re.MULTILINE)
 | 
					 | 
				
			||||||
    return updated_content
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def update_gradle_variable(content, variable_name, new_value):
 | 
					def update_gradle_variable(content, variable_name, new_value):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    更新 Gradle 文件中的 final def 变量值
 | 
					    更新 Gradle 文件中的 final def 变量值
 | 
				
			||||||
| 
						 | 
					@ -166,12 +91,8 @@ def update_gradle_property(content, key, new_value):
 | 
				
			||||||
    return updated_content
 | 
					    return updated_content
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LAUNCHER_CODE_PATH = f"LauncherCode/src/com/launchercode".replace("/", os.sep)
 | 
					 | 
				
			||||||
GAME_ACTIVITY_PATH = f"launcher-game/src/com/game/launcher/activity/GLGameActivity.kt".replace("/", os.sep)
 | 
					 | 
				
			||||||
GAME_ACTIVITY_PATH_2 = f"LauncherCode/src/com/launchercode/activity/GameActivity.kt".replace("/", os.sep)
 | 
					GAME_ACTIVITY_PATH_2 = f"LauncherCode/src/com/launchercode/activity/GameActivity.kt".replace("/", os.sep)
 | 
				
			||||||
ANDROID_MANIFEST_PATH = f"launcher-game/AndroidManifest.xml".replace("/", os.sep)
 | 
					 | 
				
			||||||
STRING_PATH = f"launcher-game/res/values/strings.xml".replace("/", os.sep)
 | 
					STRING_PATH = f"launcher-game/res/values/strings.xml".replace("/", os.sep)
 | 
				
			||||||
LAUNCER_STRING_PATH = f"LauncherCode/src/com/launchercode/LauncherStringsValue.kt".replace("/", os.sep)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ProjectUpdate(Task):
 | 
					class ProjectUpdate(Task):
 | 
				
			||||||
| 
						 | 
					@ -181,6 +102,9 @@ class ProjectUpdate(Task):
 | 
				
			||||||
        self.build_gradle_path = None
 | 
					        self.build_gradle_path = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def update_package_name(self):
 | 
					    def update_package_name(self):
 | 
				
			||||||
 | 
					        if not self.context.update_config:
 | 
				
			||||||
 | 
					            app_logger().info("配置文件没有变动,package不需要更新")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        更新包名
 | 
					        更新包名
 | 
				
			||||||
        :return:
 | 
					        :return:
 | 
				
			||||||
| 
						 | 
					@ -203,209 +127,6 @@ class ProjectUpdate(Task):
 | 
				
			||||||
                pass
 | 
					                pass
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def update_keystore(self):
 | 
					 | 
				
			||||||
        root_dir = os.path.join("game_config", self.context.package_name)
 | 
					 | 
				
			||||||
        for file in os.listdir(root_dir):
 | 
					 | 
				
			||||||
            if file.endswith(".keystore"):
 | 
					 | 
				
			||||||
                name = file.replace(".keystore", "")
 | 
					 | 
				
			||||||
                FileUtils.copy(os.path.join(root_dir, file), os.path.join(self.context.temp_project_path, file))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                open(os.path.join(self.context.temp_project_path, "keystore.properties"), "w", encoding="utf-8").write(
 | 
					 | 
				
			||||||
                    f"""
 | 
					 | 
				
			||||||
keyAlias={name}
 | 
					 | 
				
			||||||
keyPassword=123456
 | 
					 | 
				
			||||||
storeFile=./{name}.keystore
 | 
					 | 
				
			||||||
storePassword=123456
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
                return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        raise Exception("keystore not found")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def update_config(self):
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        更新配置文件
 | 
					 | 
				
			||||||
        :return:
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        root_dir = os.path.join("game_config", self.context.package_name)
 | 
					 | 
				
			||||||
        config_path = list(
 | 
					 | 
				
			||||||
            filter(lambda f: f.endswith(".zip") and f.startswith(self.context.package_name), os.listdir(root_dir)))
 | 
					 | 
				
			||||||
        if len(config_path) <= 0:
 | 
					 | 
				
			||||||
            raise Exception("config not found")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        target_path = os.path.join(root_dir, config_path[0])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        dst = os.path.join(self.context.temp_project_path, config_path[0].replace(".zip", ""))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        result = FileUtils.decompress(target_path, dst)
 | 
					 | 
				
			||||||
        app_logger().debug(f"{target_path} -> {dst} , 解压结果: {result}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        mainly_path = os.path.join(dst, "mainly")
 | 
					 | 
				
			||||||
        if not os.path.exists(mainly_path):
 | 
					 | 
				
			||||||
            mainly_path = os.path.join(dst, "appConfig")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        google_services_json_path = os.path.join(dst, "google-services.json")
 | 
					 | 
				
			||||||
        if not os.path.exists(google_services_json_path):
 | 
					 | 
				
			||||||
            google_services_json_path = os.path.join(dst, "appConfig", "google-services.json")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        FileUtils.copy(google_services_json_path,
 | 
					 | 
				
			||||||
                       os.path.join(self.context.temp_project_path, "google-services.json"),
 | 
					 | 
				
			||||||
                       True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        dst_path = os.path.join(self.context.temp_project_path, f"launcher-game{os.sep}assets")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for file in list(filter(lambda f: not (f == "google_fonts.json" or f == "pag_gl_slide.pag"),
 | 
					 | 
				
			||||||
                                os.listdir(dst_path))):
 | 
					 | 
				
			||||||
            FileUtils.delete(os.path.join(dst_path, file), True)
 | 
					 | 
				
			||||||
            pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for file in list(filter(lambda f: f.find(".") <= 0, os.listdir(mainly_path))):
 | 
					 | 
				
			||||||
            FileUtils.copy(os.path.join(mainly_path, file), os.path.join(dst_path, file))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        with open(os.path.join(dst, "tkg_config_mainly.properties"), 'rb') as f:
 | 
					 | 
				
			||||||
            self.context.config = javaproperties.load(f)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # 不打admob
 | 
					 | 
				
			||||||
        if self.context.admob_app_id is None or self.context.admob_app_id == "":
 | 
					 | 
				
			||||||
            self.context.admob_app_id = self.context.get_config("admob_id")
 | 
					 | 
				
			||||||
        pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def update_icon(self):
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        更新游戏Icon
 | 
					 | 
				
			||||||
        :return:
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        target_icon_path = os.path.join("game_config", self.context.package_name, "icon.zip")
 | 
					 | 
				
			||||||
        tag = "res_icon_resources"
 | 
					 | 
				
			||||||
        dst = os.path.join(self.context.temp_project_path, tag)
 | 
					 | 
				
			||||||
        FileUtils.decompress(target_icon_path, dst)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for root, dirs, files in os.walk(dst):
 | 
					 | 
				
			||||||
            for file in files:
 | 
					 | 
				
			||||||
                temp_tart_path = os.path.join(root, file)
 | 
					 | 
				
			||||||
                if temp_tart_path.find("__MACOSX") > 0:
 | 
					 | 
				
			||||||
                    continue
 | 
					 | 
				
			||||||
                temp_dst = temp_tart_path.replace(tag, "launcher-game" + os.sep + "res")
 | 
					 | 
				
			||||||
                app_logger().debug(f"copy icon = {temp_tart_path} -> {temp_dst}")
 | 
					 | 
				
			||||||
                FileUtils.copy(temp_tart_path, temp_dst, True)
 | 
					 | 
				
			||||||
        pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def update_game_result(self):
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        更新游戏资源
 | 
					 | 
				
			||||||
        :return:
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        root_dir = os.path.join("game_config", self.context.package_name)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if self.context.game_type == "unity_native":
 | 
					 | 
				
			||||||
            res_path = os.path.join(root_dir, "unityLibrary.zip")
 | 
					 | 
				
			||||||
            if not os.path.exists(res_path):
 | 
					 | 
				
			||||||
                raise Exception("unity library not found")
 | 
					 | 
				
			||||||
            dst = os.path.join(self.context.temp_project_path, "unityLibrary")
 | 
					 | 
				
			||||||
            temp_dst = dst + "_res"
 | 
					 | 
				
			||||||
            if os.path.exists(dst):
 | 
					 | 
				
			||||||
                FileUtils.delete(dst, True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if os.path.exists(temp_dst):
 | 
					 | 
				
			||||||
                FileUtils.delete(temp_dst, True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            FileUtils.decompress(res_path, temp_dst)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            build_path = os.path.join(temp_dst, "build")
 | 
					 | 
				
			||||||
            if os.path.exists(build_path):
 | 
					 | 
				
			||||||
                FileUtils.delete(build_path, True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if os.listdir(temp_dst).index("unityLibrary") >= 0:
 | 
					 | 
				
			||||||
                FileUtils.copy(os.path.join(temp_dst, "unityLibrary"), dst)
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                FileUtils.copy(temp_dst, dst)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            android_manifest_xml_path = os.path.join(dst, "src", "main", "AndroidManifest.xml")
 | 
					 | 
				
			||||||
            process_manifest(android_manifest_xml_path, android_manifest_xml_path)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            text = open(os.path.join(dst, "build.gradle"), "r", encoding="utf-8").read()
 | 
					 | 
				
			||||||
            text = text.replace("implementation", "api")
 | 
					 | 
				
			||||||
            if not 'namespace "com.unity3d.player"' in text:
 | 
					 | 
				
			||||||
                text = text.replace("compileSdkVersion", """
 | 
					 | 
				
			||||||
        namespace "com.unity3d.player"
 | 
					 | 
				
			||||||
        compileSdkVersion""")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            text = text.replace("unityStreamingAssets.tokenize(', ')",
 | 
					 | 
				
			||||||
                                '[".unity3d", ".bundle", ".version", ".bytes", ".hash"]')
 | 
					 | 
				
			||||||
            text = text.replace("apply plugin: 'com.android.library'", """
 | 
					 | 
				
			||||||
plugins {
 | 
					 | 
				
			||||||
    id 'com.android.library'
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
            """)
 | 
					 | 
				
			||||||
            open(os.path.join(dst, "build.gradle"), "w", encoding="utf-8").write(text)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            lines = open(os.path.join(dst, "build.gradle"), "r", encoding="utf-8").readlines()
 | 
					 | 
				
			||||||
            new_lines = []
 | 
					 | 
				
			||||||
            for line in lines:
 | 
					 | 
				
			||||||
                if line.find("com.game:hachisdk") > 0:
 | 
					 | 
				
			||||||
                    continue
 | 
					 | 
				
			||||||
                new_lines.append(line)
 | 
					 | 
				
			||||||
            open(os.path.join(dst, "build.gradle"), "w", encoding="utf-8").writelines(new_lines)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            # 引用Unity项目
 | 
					 | 
				
			||||||
            text = open(os.path.join(self.context.temp_project_path, "ad.gradle"), "r", encoding="utf-8").read()
 | 
					 | 
				
			||||||
            text = uncomment_line(text, "implementation projects.unityLibrary")
 | 
					 | 
				
			||||||
            open(os.path.join(self.context.temp_project_path, "ad.gradle"), "w", encoding="utf-8").write(text)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            text = open(os.path.join(self.context.temp_project_path, "settings.gradle"), "r", encoding="utf-8").read()
 | 
					 | 
				
			||||||
            text = uncomment_line(text, "include ':unityLibrary'")
 | 
					 | 
				
			||||||
            open(os.path.join(self.context.temp_project_path, "settings.gradle"), "w", encoding="utf-8").write(text)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            # launcher 引用 unityActivity
 | 
					 | 
				
			||||||
            text = open(os.path.join(self.context.temp_project_path, GAME_ACTIVITY_PATH), "r", encoding="utf-8").read()
 | 
					 | 
				
			||||||
            text = text.replace("GLGameWebActivity", "com.unity3d.player.UnityPlayerActivity")
 | 
					 | 
				
			||||||
            open(os.path.join(self.context.temp_project_path, GAME_ACTIVITY_PATH), "w", encoding="utf-8").write(text)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            text = open(os.path.join(self.context.temp_project_path, ANDROID_MANIFEST_PATH), "r",
 | 
					 | 
				
			||||||
                        encoding="utf-8").read()
 | 
					 | 
				
			||||||
            text = text.replace("@style/LauncherGameIntroTheme", "@style/UnityThemeSelector")
 | 
					 | 
				
			||||||
            open(os.path.join(self.context.temp_project_path, ANDROID_MANIFEST_PATH), "w", encoding="utf-8").write(text)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            raise Exception(f"不支持的游戏类型 : {self.context.game_type}")
 | 
					 | 
				
			||||||
        pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def update_image(self):
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        更新游戏的资源
 | 
					 | 
				
			||||||
        :return:
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        root_dir = os.path.join("game_config", self.context.package_name)
 | 
					 | 
				
			||||||
        drawable_path = os.path.join(root_dir, "drawable-xxhdpi.zip")
 | 
					 | 
				
			||||||
        if not os.path.exists(drawable_path):
 | 
					 | 
				
			||||||
            raise Exception("drawable not found")
 | 
					 | 
				
			||||||
        dst = os.path.join(self.context.temp_project_path, "drawable_res")
 | 
					 | 
				
			||||||
        FileUtils.decompress(drawable_path, dst)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if os.path.join(dst, "drawable-xxhdpi"):
 | 
					 | 
				
			||||||
            dst = os.path.join(dst, "drawable-xxhdpi")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        target_root_path = os.path.join(self.context.temp_project_path,
 | 
					 | 
				
			||||||
                                        f"launcher-game{os.sep}res{os.sep}drawable-xxhdpi")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        image_list = list(map(lambda f: Path(f).stem, os.listdir(target_root_path)))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for file in os.listdir(dst):
 | 
					 | 
				
			||||||
            if file == ".DS_Store":
 | 
					 | 
				
			||||||
                continue
 | 
					 | 
				
			||||||
            temp_tar = os.path.join(dst, file)
 | 
					 | 
				
			||||||
            temp_dst = os.path.join(target_root_path, file)
 | 
					 | 
				
			||||||
            file_name = Path(file).stem
 | 
					 | 
				
			||||||
            if file_name in image_list:
 | 
					 | 
				
			||||||
                FileUtils.delete(os.path.join(target_root_path, file_name + ".png"))
 | 
					 | 
				
			||||||
                FileUtils.delete(os.path.join(target_root_path, file_name + ".jpg"))
 | 
					 | 
				
			||||||
                pass
 | 
					 | 
				
			||||||
            FileUtils.copy(temp_tar, temp_dst, True)
 | 
					 | 
				
			||||||
            pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def update_gradle_config(self):
 | 
					    def update_gradle_config(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        更新gradle里面的版本号
 | 
					        更新gradle里面的版本号
 | 
				
			||||||
| 
						 | 
					@ -427,6 +148,9 @@ plugins {
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def update_string(self):
 | 
					    def update_string(self):
 | 
				
			||||||
 | 
					        if not self.context.update_config:
 | 
				
			||||||
 | 
					            app_logger().info("配置文件没有变动,string不需要更新")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
        privacy = self.context.get_config("TkA_Url_Privacy")
 | 
					        privacy = self.context.get_config("TkA_Url_Privacy")
 | 
				
			||||||
        if not privacy or privacy == "":
 | 
					        if not privacy or privacy == "":
 | 
				
			||||||
            raise Exception("配置文件中没有配置 TkA_Url_Privacy")
 | 
					            raise Exception("配置文件中没有配置 TkA_Url_Privacy")
 | 
				
			||||||
| 
						 | 
					@ -440,29 +164,11 @@ plugins {
 | 
				
			||||||
        text = text.replace("https://doanvanquy.com/TermsOfUse.html",
 | 
					        text = text.replace("https://doanvanquy.com/TermsOfUse.html",
 | 
				
			||||||
                            privacy.replace("privacy.html", "TermsOfUse.html"))
 | 
					                            privacy.replace("privacy.html", "TermsOfUse.html"))
 | 
				
			||||||
        open(os.path.join(self.context.temp_project_path, STRING_PATH), "w", encoding="utf-8").write(text)
 | 
					        open(os.path.join(self.context.temp_project_path, STRING_PATH), "w", encoding="utf-8").write(text)
 | 
				
			||||||
 | 
					 | 
				
			||||||
        # text = open(os.path.join(self.context.temp_project_path, LAUNCER_STRING_PATH), "r", encoding="utf-8").read()
 | 
					 | 
				
			||||||
        # text = text.replace("https://harmonitun.com/privacy.html", privacy)
 | 
					 | 
				
			||||||
        # text = text.replace("https://harmonitun.com/TermsOfUse.html",
 | 
					 | 
				
			||||||
        #                     privacy.replace("privacy.html", "TermsOfUse.html"))
 | 
					 | 
				
			||||||
        # text = text.replace("harmounitun@outlook.com", tkg_custom)
 | 
					 | 
				
			||||||
        # open(os.path.join(self.context.temp_project_path, LAUNCER_STRING_PATH), "w", encoding="utf-8").write(text)
 | 
					 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def execute(self):
 | 
					    def execute(self):
 | 
				
			||||||
        global GAME_ACTIVITY_PATH
 | 
					 | 
				
			||||||
        path = os.path.join(self.context.temp_project_path, GAME_ACTIVITY_PATH)
 | 
					 | 
				
			||||||
        if not os.path.exists(path):
 | 
					 | 
				
			||||||
            GAME_ACTIVITY_PATH = GAME_ACTIVITY_PATH_2
 | 
					 | 
				
			||||||
            # GAME_ACTIVITY_PATH = GAME_ACTIVITY_PATH_2
 | 
					 | 
				
			||||||
            pass
 | 
					 | 
				
			||||||
        self.build_gradle_path = os.path.join(self.context.temp_project_path, "build.gradle")
 | 
					        self.build_gradle_path = os.path.join(self.context.temp_project_path, "build.gradle")
 | 
				
			||||||
        self.update_package_name()
 | 
					        self.update_package_name()
 | 
				
			||||||
        self.update_keystore()
 | 
					 | 
				
			||||||
        self.update_config()
 | 
					 | 
				
			||||||
        self.update_icon()
 | 
					 | 
				
			||||||
        self.update_image()
 | 
					 | 
				
			||||||
        self.update_game_result()
 | 
					 | 
				
			||||||
        self.update_gradle_config()
 | 
					        self.update_gradle_config()
 | 
				
			||||||
        self.update_string()
 | 
					        self.update_string()
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,71 @@
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import shutil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javaproperties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from scripts.task import Task
 | 
				
			||||||
 | 
					from utils import FileUtils
 | 
				
			||||||
 | 
					from utils.logger_utils import app_logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ProjectUpdateConfig(Task):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_config(self):
 | 
				
			||||||
 | 
					        if not self.context.update_config:
 | 
				
			||||||
 | 
					            app_logger().info("配置文件没有更新")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        更新配置文件
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        target_path = self.context.config_path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dst = os.path.join(self.context.temp_project_path, os.path.basename(target_path).replace(".zip", ""))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not self.context.update_config:
 | 
				
			||||||
 | 
					            app_logger().info("No update config found")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            with open(os.path.join(dst, "tkg_config_mainly.properties"), 'rb') as f:
 | 
				
			||||||
 | 
					                self.context.config = javaproperties.load(f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # 不打admob
 | 
				
			||||||
 | 
					            if self.context.admob_app_id is None or self.context.admob_app_id == "":
 | 
				
			||||||
 | 
					                self.context.admob_app_id = self.context.get_config("admob_id")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if os.path.exists(dst):
 | 
				
			||||||
 | 
					            shutil.rmtree(dst)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = FileUtils.decompress(target_path, dst)
 | 
				
			||||||
 | 
					        app_logger().debug(f"{target_path} -> {dst} , 解压结果: {result}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mainly_path = os.path.join(dst, "mainly")
 | 
				
			||||||
 | 
					        if not os.path.exists(mainly_path):
 | 
				
			||||||
 | 
					            mainly_path = os.path.join(dst, "appConfig")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        google_services_json_path = os.path.join(dst, "google-services.json")
 | 
				
			||||||
 | 
					        if not os.path.exists(google_services_json_path):
 | 
				
			||||||
 | 
					            google_services_json_path = os.path.join(dst, "appConfig", "google-services.json")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        FileUtils.copy(google_services_json_path,
 | 
				
			||||||
 | 
					                       os.path.join(self.context.temp_project_path, "google-services.json"),
 | 
				
			||||||
 | 
					                       True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dst_path = os.path.join(self.context.temp_project_path, f"launcher-game{os.sep}assets")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for file in list(filter(lambda f: not (f == "google_fonts.json" or f == "pag_gl_slide.pag"),
 | 
				
			||||||
 | 
					                                os.listdir(dst_path))):
 | 
				
			||||||
 | 
					            FileUtils.delete(os.path.join(dst_path, file), True)
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for file in list(filter(lambda f: f.find(".") <= 0, os.listdir(mainly_path))):
 | 
				
			||||||
 | 
					            FileUtils.copy(os.path.join(mainly_path, file), os.path.join(dst_path, file), True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def execute(self):
 | 
				
			||||||
 | 
					        self.update_config()
 | 
				
			||||||
 | 
					        self.context.save_cache_config("config", self.context.config_config_md5)
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,170 @@
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					import xml.etree.ElementTree as ET
 | 
				
			||||||
 | 
					from xml.dom import minidom
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from scripts.task import Task
 | 
				
			||||||
 | 
					from utils import FileUtils
 | 
				
			||||||
 | 
					from utils.logger_utils import app_logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GAME_ACTIVITY_PATH = f"launcher-game/src/com/game/launcher/activity/GLGameActivity.kt".replace("/", os.sep)
 | 
				
			||||||
 | 
					ANDROID_MANIFEST_PATH = f"launcher-game/AndroidManifest.xml".replace("/", os.sep)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def process_manifest(input_path, output_path):
 | 
				
			||||||
 | 
					    # 解析XML文件
 | 
				
			||||||
 | 
					    tree = ET.parse(input_path)
 | 
				
			||||||
 | 
					    root = tree.getroot()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # 定义命名空间映射
 | 
				
			||||||
 | 
					    android_namespace = 'http://schemas.android.com/apk/res/android'
 | 
				
			||||||
 | 
					    ET.register_namespace('android', android_namespace)
 | 
				
			||||||
 | 
					    namespaces = {'android': android_namespace}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # 处理application标签,移除所有属性
 | 
				
			||||||
 | 
					    application = root.find('application')
 | 
				
			||||||
 | 
					    if application is not None:
 | 
				
			||||||
 | 
					        # 保存所有子节点
 | 
				
			||||||
 | 
					        children = list(application)
 | 
				
			||||||
 | 
					        # 清除application标签
 | 
				
			||||||
 | 
					        root.remove(application)
 | 
				
			||||||
 | 
					        # 创建新的application标签(无属性)
 | 
				
			||||||
 | 
					        new_application = ET.Element('application')
 | 
				
			||||||
 | 
					        # 添加回所有子节点
 | 
				
			||||||
 | 
					        for child in children:
 | 
				
			||||||
 | 
					            new_application.append(child)
 | 
				
			||||||
 | 
					        # 将新的application标签添加回root
 | 
				
			||||||
 | 
					        root.append(new_application)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # 查找并删除指定的activity节点
 | 
				
			||||||
 | 
					        activity_to_remove = new_application.find(
 | 
				
			||||||
 | 
					            ".//activity[@android:name='com.unity3d.player.UnityPlayerActivity']",
 | 
				
			||||||
 | 
					            namespaces=namespaces
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        if activity_to_remove is not None:
 | 
				
			||||||
 | 
					            new_application.remove(activity_to_remove)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # 保存处理后的XML,保留android命名空间前缀
 | 
				
			||||||
 | 
					    rough_string = ET.tostring(root, 'utf-8')
 | 
				
			||||||
 | 
					    reparsed = minidom.parseString(rough_string)
 | 
				
			||||||
 | 
					    pretty_xml = reparsed.toprettyxml(indent="  ", encoding='utf-8')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # 去除空行
 | 
				
			||||||
 | 
					    lines = pretty_xml.decode('utf-8').split('\n')
 | 
				
			||||||
 | 
					    non_empty_lines = [line for line in lines if line.strip() != '']
 | 
				
			||||||
 | 
					    pretty_xml = '\n'.join(non_empty_lines).encode('utf-8')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    with open(output_path, 'wb') as f:
 | 
				
			||||||
 | 
					        f.write(pretty_xml)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print(f"处理完成,结果已保存到 {output_path}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def uncomment_line(content, line_pattern):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    取消指定行的注释
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    :param content: 文件内容
 | 
				
			||||||
 | 
					    :param line_pattern: 要取消注释的行内容(不含前导//和空格)
 | 
				
			||||||
 | 
					    :return: 更新后的内容
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    # 匹配以//开头,后跟任意空格,然后是目标行内容
 | 
				
			||||||
 | 
					    pattern = rf'^(\s*)//\s*({re.escape(line_pattern)}\s*)$'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # 替换为去注释版本(保留原有缩进)
 | 
				
			||||||
 | 
					    replacement = rf'\1\2'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    updated_content = re.sub(pattern, replacement, content, flags=re.MULTILINE)
 | 
				
			||||||
 | 
					    return updated_content
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ProjectUpdateGameRes(Task):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_game_result(self):
 | 
				
			||||||
 | 
					        if not self.context.update_res_unity:
 | 
				
			||||||
 | 
					            app_logger().info("No update game res found")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        更新游戏资源
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if self.context.game_type == "unity_native":
 | 
				
			||||||
 | 
					            res_path = self.context.res_unity_path
 | 
				
			||||||
 | 
					            dst = os.path.join(self.context.temp_project_path, "unityLibrary")
 | 
				
			||||||
 | 
					            temp_dst = dst + "_res"
 | 
				
			||||||
 | 
					            if os.path.exists(dst):
 | 
				
			||||||
 | 
					                result = FileUtils.delete(dst, True)
 | 
				
			||||||
 | 
					                app_logger().info(f"删除unityLibrary结果 : {result}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if os.path.exists(temp_dst):
 | 
				
			||||||
 | 
					                result = FileUtils.delete(temp_dst, True)
 | 
				
			||||||
 | 
					                app_logger().info(f"删除temp unityLibrary结果 : {result}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            FileUtils.decompress(res_path, temp_dst)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            build_path = os.path.join(temp_dst, "build")
 | 
				
			||||||
 | 
					            if os.path.exists(build_path):
 | 
				
			||||||
 | 
					                FileUtils.delete(build_path, True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if os.listdir(temp_dst).index("unityLibrary") >= 0:
 | 
				
			||||||
 | 
					                FileUtils.copy(os.path.join(temp_dst, "unityLibrary"), dst)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                FileUtils.copy(temp_dst, dst)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            android_manifest_xml_path = os.path.join(dst, "src", "main", "AndroidManifest.xml")
 | 
				
			||||||
 | 
					            process_manifest(android_manifest_xml_path, android_manifest_xml_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            text = open(os.path.join(dst, "build.gradle"), "r", encoding="utf-8").read()
 | 
				
			||||||
 | 
					            text = text.replace("implementation", "api")
 | 
				
			||||||
 | 
					            if not 'namespace "com.unity3d.player"' in text:
 | 
				
			||||||
 | 
					                text = text.replace("compileSdkVersion", """
 | 
				
			||||||
 | 
					            namespace "com.unity3d.player"
 | 
				
			||||||
 | 
					            compileSdkVersion""")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            text = text.replace("unityStreamingAssets.tokenize(', ')",
 | 
				
			||||||
 | 
					                                '[".unity3d", ".bundle", ".version", ".bytes", ".hash"]')
 | 
				
			||||||
 | 
					            text = text.replace("apply plugin: 'com.android.library'", """
 | 
				
			||||||
 | 
					    plugins {
 | 
				
			||||||
 | 
					        id 'com.android.library'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					                """)
 | 
				
			||||||
 | 
					            open(os.path.join(dst, "build.gradle"), "w", encoding="utf-8").write(text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            lines = open(os.path.join(dst, "build.gradle"), "r", encoding="utf-8").readlines()
 | 
				
			||||||
 | 
					            new_lines = []
 | 
				
			||||||
 | 
					            for line in lines:
 | 
				
			||||||
 | 
					                if line.find("com.game:hachisdk") > 0:
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					                new_lines.append(line)
 | 
				
			||||||
 | 
					            open(os.path.join(dst, "build.gradle"), "w", encoding="utf-8").writelines(new_lines)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # 引用Unity项目
 | 
				
			||||||
 | 
					            text = open(os.path.join(self.context.temp_project_path, "ad.gradle"), "r", encoding="utf-8").read()
 | 
				
			||||||
 | 
					            text = uncomment_line(text, "implementation projects.unityLibrary")
 | 
				
			||||||
 | 
					            open(os.path.join(self.context.temp_project_path, "ad.gradle"), "w", encoding="utf-8").write(text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            text = open(os.path.join(self.context.temp_project_path, "settings.gradle"), "r", encoding="utf-8").read()
 | 
				
			||||||
 | 
					            text = uncomment_line(text, "include ':unityLibrary'")
 | 
				
			||||||
 | 
					            open(os.path.join(self.context.temp_project_path, "settings.gradle"), "w", encoding="utf-8").write(text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # launcher 引用 unityActivity
 | 
				
			||||||
 | 
					            text = open(os.path.join(self.context.temp_project_path, GAME_ACTIVITY_PATH), "r", encoding="utf-8").read()
 | 
				
			||||||
 | 
					            text = text.replace("GLGameWebActivity", "com.unity3d.player.UnityPlayerActivity")
 | 
				
			||||||
 | 
					            open(os.path.join(self.context.temp_project_path, GAME_ACTIVITY_PATH), "w", encoding="utf-8").write(text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            text = open(os.path.join(self.context.temp_project_path, ANDROID_MANIFEST_PATH), "r",
 | 
				
			||||||
 | 
					                        encoding="utf-8").read()
 | 
				
			||||||
 | 
					            text = text.replace("@style/LauncherGameIntroTheme", "@style/UnityThemeSelector")
 | 
				
			||||||
 | 
					            open(os.path.join(self.context.temp_project_path, ANDROID_MANIFEST_PATH), "w", encoding="utf-8").write(text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            raise Exception(f"不支持的游戏类型 : {self.context.game_type}")
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def execute(self):
 | 
				
			||||||
 | 
					        self.update_game_result()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.context.save_cache_config("res_unity", self.context.config_res_unity_md5)
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,39 @@
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import shutil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from scripts.task import Task
 | 
				
			||||||
 | 
					from utils import FileUtils
 | 
				
			||||||
 | 
					from utils.logger_utils import app_logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ProjectUpdateIcon(Task):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_icon(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        更新游戏Icon
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not self.context.update_res_icon:
 | 
				
			||||||
 | 
					            app_logger().info("No update res icon found")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        tag = "res_icon_resources"
 | 
				
			||||||
 | 
					        dst = os.path.join(self.context.temp_project_path, tag)
 | 
				
			||||||
 | 
					        if os.path.exists(dst):
 | 
				
			||||||
 | 
					            shutil.rmtree(dst)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        FileUtils.decompress(self.context.res_icon_path, dst)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for root, dirs, files in os.walk(dst):
 | 
				
			||||||
 | 
					            for file in files:
 | 
				
			||||||
 | 
					                temp_tart_path = os.path.join(root, file)
 | 
				
			||||||
 | 
					                if temp_tart_path.find("__MACOSX") > 0:
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					                temp_dst = temp_tart_path.replace(tag, "launcher-game" + os.sep + "res")
 | 
				
			||||||
 | 
					                app_logger().debug(f"copy icon = {temp_tart_path} -> {temp_dst}")
 | 
				
			||||||
 | 
					                FileUtils.copy(temp_tart_path, temp_dst, True)
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def execute(self):
 | 
				
			||||||
 | 
					        self.update_icon()
 | 
				
			||||||
 | 
					        self.context.save_cache_config("res_icon", self.context.config_res_icon_md5)
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,52 @@
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import shutil
 | 
				
			||||||
 | 
					from pathlib import Path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from scripts.task import Task
 | 
				
			||||||
 | 
					from utils import FileUtils
 | 
				
			||||||
 | 
					from utils.logger_utils import app_logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ProjectUpdateImage(Task):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_image(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        更新游戏的资源
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not self.context.update_res_img:
 | 
				
			||||||
 | 
					            app_logger().info("No update image found")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        dst = os.path.join(self.context.temp_project_path, "drawable_res")
 | 
				
			||||||
 | 
					        if os.path.exists(dst):
 | 
				
			||||||
 | 
					            shutil.rmtree(dst)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        FileUtils.decompress(self.context.res_img_path, dst)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if os.path.join(dst, "drawable-xxhdpi"):
 | 
				
			||||||
 | 
					            dst = os.path.join(dst, "drawable-xxhdpi")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        target_root_path = os.path.join(self.context.temp_project_path,
 | 
				
			||||||
 | 
					                                        f"launcher-game{os.sep}res{os.sep}drawable-xxhdpi")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        image_list = list(map(lambda f: Path(f).stem, os.listdir(target_root_path)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for file in os.listdir(dst):
 | 
				
			||||||
 | 
					            if file == ".DS_Store":
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            res_name = Path(file).stem
 | 
				
			||||||
 | 
					            file_name = self.context.get_map_from_key(res_name)
 | 
				
			||||||
 | 
					            temp_tar = os.path.join(dst, file)
 | 
				
			||||||
 | 
					            temp_dst = os.path.join(target_root_path, file).replace(file_name, self.context.get_map_from_key(res_name))
 | 
				
			||||||
 | 
					            if file_name in image_list:
 | 
				
			||||||
 | 
					                FileUtils.delete(os.path.join(target_root_path, file_name + ".png"))
 | 
				
			||||||
 | 
					                FileUtils.delete(os.path.join(target_root_path, file_name + ".jpg"))
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					            app_logger().info(f"copy {temp_tar} => {temp_dst}")
 | 
				
			||||||
 | 
					            FileUtils.copy(temp_tar, temp_dst, True)
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def execute(self):
 | 
				
			||||||
 | 
					        self.update_image()
 | 
				
			||||||
 | 
					        self.context.save_cache_config("res_img", self.context.config_res_img_md5)
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,41 @@
 | 
				
			||||||
 | 
					import os.path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from scripts.task import Task
 | 
				
			||||||
 | 
					from utils import FileUtils
 | 
				
			||||||
 | 
					from utils.logger_utils import app_logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ProjectUpdateKeystore(Task):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_keystore(self):
 | 
				
			||||||
 | 
					        if not self.context.update_keystore:
 | 
				
			||||||
 | 
					            app_logger().info("No update_keystore")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        name = os.path.basename(self.context.keystore_path).replace(".keystore", "")
 | 
				
			||||||
 | 
					        target_path = os.path.join(self.context.temp_project_path, name + ".keystore")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if os.path.exists(target_path):
 | 
				
			||||||
 | 
					            os.remove(target_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = FileUtils.copy(self.context.keystore_path, target_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        app_logger().debug(f"copy keystore result {result}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        target_path = os.path.join(self.context.temp_project_path, "keystore.properties")
 | 
				
			||||||
 | 
					        if os.path.exists(target_path):
 | 
				
			||||||
 | 
					            os.remove(target_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        open(target_path, "w", encoding="utf-8").write(
 | 
				
			||||||
 | 
					            f"""
 | 
				
			||||||
 | 
					keyAlias={name}
 | 
				
			||||||
 | 
					keyPassword=123456
 | 
				
			||||||
 | 
					storeFile=./{name}.keystore
 | 
				
			||||||
 | 
					storePassword=123456
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def execute(self):
 | 
				
			||||||
 | 
					        self.update_keystore()
 | 
				
			||||||
 | 
					        self.context.save_cache_config("keystore", self.context.config_keystore_md5)
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,6 @@ class Task:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, context: Context):
 | 
					    def __init__(self, context: Context):
 | 
				
			||||||
        self.context = context
 | 
					        self.context = context
 | 
				
			||||||
        pass
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def execute(self):
 | 
					    def execute(self):
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue