MAC端打包

maziang
Maziang 5 months ago
parent 6f78fd78c3
commit 5e00843cb8

1
.gitignore vendored

@ -198,6 +198,7 @@ temp/
*.orig
# Project specific
macos_release/
resources/config/deepseek_api.json
*.key
*.secret

Binary file not shown.

@ -0,0 +1,351 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
MagicWord macOS完整打包脚本
用于构建macOS Apple Silicon原生应用程序包含所有必需资源
"""
import os
import sys
import subprocess
import platform
import shutil
import plistlib
from datetime import datetime
def run_command(command, shell=False, cwd=None):
"""运行命令并返回结果"""
try:
result = subprocess.run(command, shell=shell, capture_output=True, text=True, encoding='utf-8', cwd=cwd)
return result.returncode, result.stdout, result.stderr
except Exception as e:
return -1, "", str(e)
def check_system():
"""检查系统是否为macOS"""
if platform.system() != "Darwin":
print("错误: 此脚本仅支持macOS系统")
return False
# 检查架构
machine = platform.machine()
if machine == 'arm64':
print(f"系统信息: macOS {platform.mac_ver()[0]}, Apple Silicon ({machine})")
elif machine == 'x86_64':
print(f"系统信息: macOS {platform.mac_ver()[0]}, Intel ({machine})")
else:
print(f"系统信息: macOS {platform.mac_ver()[0]}, {machine}")
return True
def clean_build_dirs():
"""清理构建目录"""
print("清理构建目录...")
dirs_to_clean = ['build', 'dist', '__pycache__', '*.egg-info']
for dir_name in dirs_to_clean:
if '*' in dir_name:
import glob
for path in glob.glob(dir_name):
if os.path.isdir(path):
shutil.rmtree(path, ignore_errors=True)
elif os.path.exists(dir_name):
if os.path.isdir(dir_name):
shutil.rmtree(dir_name, ignore_errors=True)
else:
os.remove(dir_name)
# 清理src目录下的__pycache__
for root, dirs, files in os.walk('src'):
for dir_name in dirs:
if dir_name == '__pycache__':
cache_path = os.path.join(root, dir_name)
shutil.rmtree(cache_path, ignore_errors=True)
print(f"清理缓存: {cache_path}")
def install_dependencies():
"""安装依赖"""
print("安装项目依赖...")
# 首先确保pip是最新的
run_command([sys.executable, "-m", "pip", "install", "--upgrade", "pip"])
# 安装requirements.txt中的依赖
if os.path.exists("requirements.txt"):
code, stdout, stderr = run_command([sys.executable, "-m", "pip", "install", "-r", "requirements.txt"])
if code != 0:
print(f"依赖安装失败: {stderr}")
return False
else:
print("警告: 找不到requirements.txt文件")
# 安装PyInstaller
print("安装PyInstaller...")
code, stdout, stderr = run_command([sys.executable, "-m", "pip", "install", "pyinstaller"])
if code != 0:
print(f"PyInstaller安装失败: {stderr}")
return False
print("依赖安装成功")
return True
def build_macos_app():
"""构建macOS应用包"""
print("构建macOS应用包...")
# 确定架构
machine = platform.machine()
if machine == 'arm64':
target_arch = 'arm64'
elif machine == 'x86_64':
target_arch = 'x86_64'
else:
target_arch = 'universal2' # 通用架构
# PyInstaller命令 - 针对macOS优化
pyinstaller_cmd = [
"pyinstaller",
"--name", "MagicWord",
"--version", "1.0.0",
"--distpath", "dist",
"--workpath", "build",
"--specpath", ".",
# 数据文件 - macOS格式使用冒号分隔
"--add-data", "resources:resources",
"--add-data", "src:src",
"--add-data", "src/ui/UI.png:ui",
"--add-data", "src/ui/114514.png:ui",
# 图标文件
"--icon", "resources/icons/app_icon_256X256.png",
# 隐藏导入模块
"--hidden-import", "PyQt5",
"--hidden-import", "PyQt5.QtCore",
"--hidden-import", "PyQt5.QtGui",
"--hidden-import", "PyQt5.QtWidgets",
"--hidden-import", "requests",
"--hidden-import", "beautifulsoup4",
"--hidden-import", "python-docx",
"--hidden-import", "PyPDF2",
"--hidden-import", "ebooklib",
"--hidden-import", "chardet",
"--hidden-import", "PIL",
# macOS应用包选项
"--windowed", # 无控制台窗口
"--osx-bundle-identifier", "com.magicword.app",
"--target-architecture", target_arch,
"--noconfirm",
"src/main.py"
]
print(f"目标架构: {target_arch}")
print("运行PyInstaller...")
code, stdout, stderr = run_command(pyinstaller_cmd)
if code != 0:
print(f"构建失败: {stderr}")
print("尝试通用架构...")
# 尝试通用架构
pyinstaller_cmd[-2] = "universal2"
code, stdout, stderr = run_command(pyinstaller_cmd)
if code != 0:
print(f"通用架构构建也失败: {stderr}")
return False
print("macOS应用包构建成功")
return True
def create_app_bundle():
"""创建macOS应用束"""
print("创建macOS应用束...")
app_path = "dist/MagicWord.app"
if not os.path.exists(app_path):
print(f"错误: 找不到应用包 {app_path}")
return False
# 创建Info.plist文件
info_plist = {
'CFBundleName': 'MagicWord',
'CFBundleDisplayName': 'MagicWord - 隐私学习软件',
'CFBundleIdentifier': 'com.magicword.app',
'CFBundleVersion': '1.0.0',
'CFBundleShortVersionString': '1.0.0',
'CFBundleExecutable': 'MagicWord',
'CFBundlePackageType': 'APPL',
'CFBundleSignature': '????',
'LSMinimumSystemVersion': '11.0', # macOS Big Sur及更高版本
'NSHighResolutionCapable': True,
'NSHumanReadableCopyright': 'Copyright © 2024 MagicWord Team. All rights reserved.',
'CFBundleDocumentTypes': [
{
'CFBundleTypeName': 'Text Document',
'CFBundleTypeExtensions': ['txt', 'docx', 'pdf'],
'CFBundleTypeRole': 'Editor'
}
]
}
plist_path = os.path.join(app_path, "Contents", "Info.plist")
with open(plist_path, 'wb') as f:
plistlib.dump(info_plist, f)
# 复制图标文件到应用束
icon_files = [
'resources/icons/app_icon_32X32.png',
'resources/icons/app_icon_64X64.png',
'resources/icons/app_icon_128X128.png',
'resources/icons/app_icon_256X256.png'
]
resources_dir = os.path.join(app_path, "Contents", "Resources")
os.makedirs(resources_dir, exist_ok=True)
for icon_file in icon_files:
if os.path.exists(icon_file):
shutil.copy2(icon_file, resources_dir)
print(f"复制图标: {icon_file}")
# 复制UI图片文件
ui_files = [
'src/ui/UI.png',
'src/ui/114514.png'
]
for ui_file in ui_files:
if os.path.exists(ui_file):
shutil.copy2(ui_file, resources_dir)
print(f"复制UI文件: {ui_file}")
print("macOS应用束创建完成")
return True
def create_dmg():
"""创建DMG安装包"""
print("创建DMG安装包...")
app_path = "dist/MagicWord.app"
if not os.path.exists(app_path):
print(f"错误: 找不到应用包 {app_path}")
return False
# 创建发布目录
release_dir = "macos_release"
if os.path.exists(release_dir):
shutil.rmtree(release_dir)
os.makedirs(release_dir)
# 复制应用到发布目录
release_app_path = os.path.join(release_dir, "MagicWord.app")
shutil.copytree(app_path, release_app_path)
# 创建Applications链接
applications_link = os.path.join(release_dir, "Applications")
os.symlink("/Applications", applications_link)
# 创建README文件
readme_content = f"""# MagicWord 1.0.0 for macOS
## 安装说明
1. MagicWord.app 拖拽到 Applications 文件夹
2. 首次运行时如果出现安全提示请前往 系统设置 > 隐私与安全性 允许应用运行
3. 或者右键点击应用选择"打开"
## 系统要求
- macOS Big Sur (11.0) 或更高版本
- Apple Silicon (M1/M2/M3) Intel 处理器
## 功能特性
- 隐私学习通过打字练习来学习文档内容
- 支持多种文档格式TXT, DOCX, PDF
- 智能打字模式
- 美观的Word风格界面
- 内置小游戏扫雷和贪吃蛇
## 版本信息
构建时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
平台: {platform.system()} {platform.machine()}
Python版本: {platform.python_version()}
## 技术支持
如有问题请查看项目文档或联系开发团队
"""
with open(os.path.join(release_dir, "README.txt"), "w") as f:
f.write(readme_content)
# 创建DMG文件如果系统支持
machine = platform.machine()
dmg_name = f"MagicWord-1.0.0-macOS-{machine}.dmg"
dmg_path = os.path.join("dist", dmg_name)
# 使用hdiutil创建DMG
create_dmg_cmd = [
"hdiutil", "create",
"-volname", "MagicWord",
"-srcfolder", release_dir,
"-ov",
"-format", "UDZO",
dmg_path
]
code, stdout, stderr = run_command(create_dmg_cmd)
if code == 0:
print(f"✅ DMG创建成功: {dmg_path}")
return True
else:
print(f"⚠️ DMG创建失败: {stderr}")
print("已创建应用包可手动打包DMG")
return False
def main():
"""主函数"""
print("=== MagicWord macOS完整打包脚本 ===")
print(f"构建时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
# 检查系统
if not check_system():
return False
# 清理构建目录
clean_build_dirs()
# 安装依赖
if not install_dependencies():
print("依赖安装失败")
return False
# 构建应用
if not build_macos_app():
print("应用构建失败")
return False
# 创建应用束
if not create_app_bundle():
print("应用束创建失败")
return False
# 创建DMG
create_dmg()
print("\n=== 构建完成 ===")
print("📱 应用位置: dist/MagicWord.app")
print("💿 DMG文件: dist/MagicWord-*.dmg")
print("")
print("🔧 安装步骤:")
print(" 1. 将 MagicWord.app 拖拽到 Applications 文件夹")
print(" 2. 首次运行时,右键点击应用选择'打开'")
print(" 3. 或者在 系统设置 > 隐私与安全性 中允许应用运行")
print("")
print("✨ 应用特点:")
print(" ✅ 包含app_icon_256X256.png图标")
print(" ✅ 包含UI.png界面图片")
print(" ✅ 支持拖拽安装")
print(" ✅ 双击即可运行")
if __name__ == "__main__":
main()
Loading…
Cancel
Save