更新工程的代码

This commit is contained in:
luojian 2025-09-07 22:43:06 +08:00
parent fc46fb68d6
commit 804a89c170
1 changed files with 147 additions and 100 deletions

View File

@ -1,10 +1,12 @@
import os.path import os.path
from pathlib import Path from pathlib import Path
import re import re
from xml.dom import minidom
import javaproperties import javaproperties
import requests import requests
from lxml import etree 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
@ -12,33 +14,53 @@ from utils import FileUtils
from utils.logger_utils import app_logger from utils.logger_utils import app_logger
def update_dependency_version(content, dependency_name, new_version): def process_manifest(input_path, output_path):
""" # 解析XML文件
更新 Gradle 依赖的版本号 tree = ET.parse(input_path)
root = tree.getroot()
:param content: Gradle 文件内容 # 定义命名空间映射
:param dependency_name: 依赖名称可以是完整字符串或部分匹配 android_namespace = 'http://schemas.android.com/apk/res/android'
:param new_version: 新版本号 ET.register_namespace('android', android_namespace)
:return: 更新后的内容 namespaces = {'android': android_namespace}
"""
# 匹配 implementation 声明,捕获组用于保留前缀和后缀
pattern = rf"(implementation\s*\(\s*['\"]{re.escape(dependency_name)}:)([^'\"]+)(['\"]\s*\))"
# 替换版本号部分 # 处理application标签移除所有属性
updated_content = re.sub(pattern, rf"\g<1>{new_version}\g<3>", content) 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)
return updated_content # 查找并删除指定的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')
def get_latest_version(url): # 去除空行
try: lines = pretty_xml.decode('utf-8').split('\n')
response = requests.get(url) non_empty_lines = [line for line in lines if line.strip() != '']
root = etree.fromstring(response.content) pretty_xml = '\n'.join(non_empty_lines).encode('utf-8')
latest = root.xpath("//latest/text()") or root.xpath("//version[last()]/text()")
return latest[0] if latest else None with open(output_path, 'wb') as f:
except Exception as e: f.write(pretty_xml)
app_logger().error(f"Error: {e}")
return None print(f"处理完成,结果已保存到 {output_path}")
def uncomment_line(content, line_pattern): def uncomment_line(content, line_pattern):
@ -82,6 +104,56 @@ def update_gradle_variable(content, variable_name, new_value):
return updated_content return updated_content
def modify_text_with_regex(original_text, key, new_value):
"""
使用正则表达式修改文本中指定key的值支持带引号和数字类型
参数:
original_text -- 原始文本内容
key -- 要修改的键名
new_value -- 新的值
返回:
修改后的文本内容
"""
# 改进的正则模式:更精确地匹配带引号的值和数字值
# 匹配带引号的值(单引号或双引号)或数字值
pattern = re.compile(
r'(final def ' + re.escape(key) + r' = )' # 前缀部分
r'(?:' # 非捕获组,用于分组不同情况
r'([\'"])(.*?)\2' # 带引号的值(单引号或双引号)
r'|' # 或者
r'(\d+)' # 数字值(整数)
r')'
)
# 查找匹配
match = pattern.search(original_text)
if not match:
print(f"未找到键: {key}")
return original_text
# 检查是带引号的情况还是数字情况
quote_type = match.group(2) # 引号类型(单引号或双引号)
is_number = match.group(4) is not None # 是否是数字类型
# 构造替换字符串
if quote_type:
# 有引号的情况,保持原有引号类型
replacement = f'\g<1>{quote_type}{new_value}{quote_type}'
elif is_number:
# 数字类型,直接替换数字
replacement = f'\g<1>{new_value}'
else:
# 其他情况,保持原样替换
replacement = f'\g<1>{new_value}'
# 执行替换,只替换第一个匹配项
modified_text = pattern.sub(replacement, original_text, count=1)
return modified_text
def update_gradle_property(content, key, new_value): def update_gradle_property(content, key, new_value):
# 匹配两种格式: # 匹配两种格式:
# 1. resValue "string", "key", "value" # 1. resValue "string", "key", "value"
@ -95,10 +167,10 @@ def update_gradle_property(content, key, new_value):
LAUNCHER_CODE_PATH = f"LauncherCode/src/com/launchercode".replace("/", os.sep) LAUNCHER_CODE_PATH = f"LauncherCode/src/com/launchercode".replace("/", os.sep)
GAME_ACTIVITY_PATH = f"LauncherCode/src/com/launchercode/GameActivity.kt".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"lawnchair/AndroidManifest.xml".replace("/", os.sep) ANDROID_MANIFEST_PATH = f"launcher-game/AndroidManifest.xml".replace("/", os.sep)
STRING_PATH = f"LauncherCode/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) LAUNCER_STRING_PATH = f"LauncherCode/src/com/launchercode/LauncherStringsValue.kt".replace("/", os.sep)
@ -114,21 +186,19 @@ class ProjectUpdate(Task):
:return: :return:
""" """
build_gradle_path = os.path.join(self.context.temp_project_path, "build.gradle") build_gradle_path = os.path.join(self.context.temp_project_path, "ad.gradle")
text = open(build_gradle_path, "r", encoding="utf-8").read() text = open(build_gradle_path, "r", encoding="utf-8").read()
text = text.replace("com.fingerheart.launcher.game.free.sdjws", self.context.package_name) text = text.replace(self.context.original_package, self.context.package_name)
open(build_gradle_path, "w", encoding="utf-8").write(text) open(build_gradle_path, "w", encoding="utf-8").write(text)
xml_path = os.path.join(self.context.temp_project_path, "lawnchair/res/xml") xml_path = os.path.join(self.context.temp_project_path, "lawnchair/res/xml")
# com.launchercode.SplashActivity
# TODO 这里还需要改启动项
for root, dirs, files in os.walk(xml_path): for root, dirs, files in os.walk(xml_path):
for file in files: for file in files:
temp_xml_path = os.path.join(root, file) temp_xml_path = os.path.join(root, file)
text = open(temp_xml_path, "r", encoding="utf-8").read() text = open(temp_xml_path, "r", encoding="utf-8").read()
text = text.replace("com.fingerheart.launcher.game.free.sdjws", self.context.package_name) text = text.replace(self.context.original_package, self.context.package_name)
open(temp_xml_path, "w", encoding="utf-8").write(text) open(temp_xml_path, "w", encoding="utf-8").write(text)
pass pass
pass pass
@ -178,9 +248,9 @@ storePassword=123456
os.path.join(self.context.temp_project_path, "google-services.json"), os.path.join(self.context.temp_project_path, "google-services.json"),
True) True)
dst_path = os.path.join(self.context.temp_project_path, f"lawnchair{os.sep}assets") 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_wallpaper_slide.pag"), for file in list(filter(lambda f: not (f == "google_fonts.json" or f == "pag_gl_slide.pag"),
os.listdir(dst_path))): os.listdir(dst_path))):
FileUtils.delete(os.path.join(dst_path, file), True) FileUtils.delete(os.path.join(dst_path, file), True)
pass pass
@ -212,7 +282,7 @@ storePassword=123456
temp_tart_path = os.path.join(root, file) temp_tart_path = os.path.join(root, file)
if temp_tart_path.find("__MACOSX") > 0: if temp_tart_path.find("__MACOSX") > 0:
continue continue
temp_dst = temp_tart_path.replace(tag, "res") temp_dst = temp_tart_path.replace(tag, "launcher-game" + os.sep + "res")
app_logger().debug(f"copy icon = {temp_tart_path} -> {temp_dst}") app_logger().debug(f"copy icon = {temp_tart_path} -> {temp_dst}")
FileUtils.copy(temp_tart_path, temp_dst, True) FileUtils.copy(temp_tart_path, temp_dst, True)
pass pass
@ -232,6 +302,10 @@ storePassword=123456
temp_dst = dst + "_res" temp_dst = dst + "_res"
if os.path.exists(dst): if os.path.exists(dst):
FileUtils.delete(dst, True) FileUtils.delete(dst, True)
if os.path.exists(temp_dst):
FileUtils.delete(temp_dst, True)
FileUtils.decompress(res_path, temp_dst) FileUtils.decompress(res_path, temp_dst)
build_path = os.path.join(temp_dst, "build") build_path = os.path.join(temp_dst, "build")
@ -243,11 +317,16 @@ storePassword=123456
else: else:
FileUtils.copy(temp_dst, dst) 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 = open(os.path.join(dst, "build.gradle"), "r", encoding="utf-8").read()
text = text.replace("implementation", "api") text = text.replace("implementation", "api")
if not 'namespace "com.unity3d.player"' in text:
text = text.replace("compileSdkVersion", """ text = text.replace("compileSdkVersion", """
namespace "com.unity3d.player" namespace "com.unity3d.player"
compileSdkVersion""") compileSdkVersion""")
text = text.replace("unityStreamingAssets.tokenize(', ')", text = text.replace("unityStreamingAssets.tokenize(', ')",
'[".unity3d", ".bundle", ".version", ".bytes", ".hash"]') '[".unity3d", ".bundle", ".version", ".bytes", ".hash"]')
text = text.replace("apply plugin: 'com.android.library'", """ text = text.replace("apply plugin: 'com.android.library'", """
@ -257,15 +336,26 @@ plugins {
""") """)
open(os.path.join(dst, "build.gradle"), "w", encoding="utf-8").write(text) 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项目 # 引用Unity项目
text = open(self.build_gradle_path, "r", encoding="utf-8").read() text = open(os.path.join(self.context.temp_project_path, "ad.gradle"), "r", encoding="utf-8").read()
text = uncomment_line(text, "implementation projects.unityLibrary") text = uncomment_line(text, "implementation projects.unityLibrary")
open(self.build_gradle_path, "w", encoding="utf-8").write(text) 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 # launcher 引用 unityActivity
text = open(os.path.join(self.context.temp_project_path, GAME_ACTIVITY_PATH), "r", encoding="utf-8").read() text = open(os.path.join(self.context.temp_project_path, GAME_ACTIVITY_PATH), "r", encoding="utf-8").read()
text = text.replace("WebActivity", "com.unity3d.player.UnityPlayerActivity") 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) 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", text = open(os.path.join(self.context.temp_project_path, ANDROID_MANIFEST_PATH), "r",
@ -295,7 +385,7 @@ plugins {
dst = os.path.join(dst, "drawable-xxhdpi") dst = os.path.join(dst, "drawable-xxhdpi")
target_root_path = os.path.join(self.context.temp_project_path, target_root_path = os.path.join(self.context.temp_project_path,
f"LauncherCode{os.sep}res{os.sep}drawable-xxhdpi") f"launcher-game{os.sep}res{os.sep}drawable-xxhdpi")
image_list = list(map(lambda f: Path(f).stem, os.listdir(target_root_path))) image_list = list(map(lambda f: Path(f).stem, os.listdir(target_root_path)))
@ -318,21 +408,17 @@ plugins {
:return: :return:
""" """
build_gradle_path = os.path.join(self.context.temp_project_path, "build.gradle") build_gradle_path = os.path.join(self.context.temp_project_path, "ad.gradle")
text = open(build_gradle_path, "r", encoding="UTF-8").read() text = open(build_gradle_path, "r", encoding="UTF-8").read()
text = update_gradle_property(text, "admob_app_id", self.context.admob_app_id) text = modify_text_with_regex(text, "admob_app_id", self.context.admob_app_id)
text = update_gradle_property(text, "game_services_project_id", self.context.game_services_project_id) text = modify_text_with_regex(text, "game_services_project_id", self.context.game_services_project_id)
text = update_gradle_property(text, "facebook_app_id", self.context.facebook_app_id) text = modify_text_with_regex(text, "facebook_app_id", self.context.facebook_app_id)
text = update_gradle_property(text, "facebook_client_token", self.context.facebook_client_token) text = modify_text_with_regex(text, "facebook_client_token", self.context.facebook_client_token)
text = update_gradle_property(text, "derived_app_name", self.context.get_app_name()) text = modify_text_with_regex(text, "appName", self.context.get_app_name())
text = update_gradle_variable(text, "versionDisplayName", self.context.version_display_name) text = modify_text_with_regex(text, "appVersionName", self.context.version_display_name)
text = update_gradle_variable(text, "version_code", self.context.version_code) text = modify_text_with_regex(text, "appVersionCode", self.context.version_code)
text = update_dependency_version(text, f"straw:hachisdk_unity_{self.context.package_name}",
self.context.sdk_prolink_version)
text = update_dependency_version(text, f"com.game:hachisdk_unity_{self.context.package_name}",
self.context.sdk_version)
open(build_gradle_path, "w", encoding="UTF-8").write(text) open(build_gradle_path, "w", encoding="UTF-8").write(text)
pass pass
@ -346,28 +432,20 @@ plugins {
raise Exception("配置文件中没有配置 tkg_custom") raise Exception("配置文件中没有配置 tkg_custom")
text = open(os.path.join(self.context.temp_project_path, STRING_PATH), "r", encoding="utf-8").read() text = open(os.path.join(self.context.temp_project_path, STRING_PATH), "r", encoding="utf-8").read()
text = text.replace("https://harmonitun.com/privacy.html", privacy) text = text.replace("https://doanvanquy.com/privacy.html", privacy)
text = text.replace("https://harmonitun.com/TermsOfUse.html", text = text.replace("https://doanvanquy.com/TermsOfUse.html",
privacy.replace("privacy.html", "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, 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 = 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/privacy.html", privacy)
text = text.replace("https://harmonitun.com/TermsOfUse.html", # text = text.replace("https://harmonitun.com/TermsOfUse.html",
privacy.replace("privacy.html", "TermsOfUse.html")) # privacy.replace("privacy.html", "TermsOfUse.html"))
text = text.replace("harmounitun@outlook.com", tkg_custom) # 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) # open(os.path.join(self.context.temp_project_path, LAUNCER_STRING_PATH), "w", encoding="utf-8").write(text)
pass
def update_code_dir(self):
# code_path = os.path.join(self.context.temp_project_path, GAME_ACTIVITY_PATH)
# for i in os.listdir(code_path):
# os
pass pass
def execute(self): def execute(self):
self.update_code_dir()
global GAME_ACTIVITY_PATH global GAME_ACTIVITY_PATH
path = os.path.join(self.context.temp_project_path, GAME_ACTIVITY_PATH) path = os.path.join(self.context.temp_project_path, GAME_ACTIVITY_PATH)
if not os.path.exists(path): if not os.path.exists(path):
@ -375,7 +453,6 @@ plugins {
# GAME_ACTIVITY_PATH = GAME_ACTIVITY_PATH_2 # GAME_ACTIVITY_PATH = GAME_ACTIVITY_PATH_2
pass 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.init_sdk_version()
self.update_package_name() self.update_package_name()
self.update_keystore() self.update_keystore()
self.update_config() self.update_config()
@ -385,33 +462,3 @@ plugins {
self.update_gradle_config() self.update_gradle_config()
self.update_string() self.update_string()
pass pass
def get_sdk_version(self) -> str:
for i in range(3):
try:
url = f"https://repo.dgtverse.cn/repository/tk_my/com/game/hachisdk_unity_{self.context.package_name}/maven-metadata.xml"
version = get_latest_version(url)
if version:
return version
pass
except Exception as e:
pass
raise Exception("sdk error.")
def get_prolink_version(self) -> str:
for i in range(3):
try:
url = f"https://repo.dgtverse.cn/repository/tk_my/straw/hachisdk_unity_{self.context.package_name}/maven-metadata.xml"
print(url)
version = get_latest_version(url)
if version:
return version
except Exception as e:
print(e)
pass
raise Exception("sdk prolink error.")
def init_sdk_version(self):
self.context.sdk_version = self.get_sdk_version()
self.context.sdk_prolink_version = self.get_prolink_version()
pass