Add Firefox support and cross-browser compatibility layer
This update introduces full Firefox support using a new manifest-firefox.json (Manifest V2), adds a webext-compat.js compatibility layer for unified API usage, and refactors all extension scripts (background.js, content.js, popup.js) to use the new webext API. The build and development process is automated with new Python scripts (build.py, dev.py), and GitHub Actions workflows are updated to support multi-platform build, test, and release. Platform detection and capability abstraction are added, and all relevant files and manifests are updated for cross-browser compatibility.
This commit is contained in:
1 parent
ad5b3cae72
commit
130eec751f
12 files changed
+1347
-72
No files matched your search
@@ -0,0 +1,213 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
构建脚本,用于生成不同浏览器版本的扩展包
|
||||
支持 Chrome/Chromium(Manifest V3)和 Firefox(Manifest V2)
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def create_build_directory(platform, clean=True):
|
||||
"""创建构建目录"""
|
||||
build_dir = Path(f"build/{platform}")
|
||||
if clean and build_dir.exists():
|
||||
shutil.rmtree(build_dir)
|
||||
build_dir.mkdir(parents=True, exist_ok=True)
|
||||
return build_dir
|
||||
|
||||
|
||||
def copy_common_files(build_dir):
|
||||
"""复制通用文件"""
|
||||
common_files = [
|
||||
"webext-compat.js",
|
||||
"background.js",
|
||||
"content.js",
|
||||
"popup.js",
|
||||
"popup.html",
|
||||
"platforms.js",
|
||||
"LICENSE",
|
||||
"README.md",
|
||||
"PRIVACY_POLICY.md",
|
||||
"SECURITY.md",
|
||||
]
|
||||
|
||||
for file in common_files:
|
||||
if os.path.exists(file):
|
||||
shutil.copy2(file, build_dir)
|
||||
|
||||
# 复制 icons 目录
|
||||
if os.path.exists("icons"):
|
||||
shutil.copytree("icons", build_dir / "icons", dirs_exist_ok=True)
|
||||
|
||||
|
||||
def build_chrome():
|
||||
"""构建 Chrome 版本"""
|
||||
print("构建 Chrome 版本...")
|
||||
build_dir = create_build_directory("chrome")
|
||||
|
||||
# 复制通用文件
|
||||
copy_common_files(build_dir)
|
||||
|
||||
# 复制 Chrome manifest
|
||||
shutil.copy2("manifest.json", build_dir / "manifest.json")
|
||||
|
||||
# 修改 background.js 为 Chrome 优化
|
||||
optimize_for_chrome(build_dir)
|
||||
|
||||
print(f"Chrome 版本构建完成: {build_dir}")
|
||||
return build_dir
|
||||
|
||||
|
||||
def build_firefox():
|
||||
"""构建 Firefox 版本"""
|
||||
print("构建 Firefox 版本...")
|
||||
build_dir = create_build_directory("firefox")
|
||||
|
||||
# 复制通用文件
|
||||
copy_common_files(build_dir)
|
||||
|
||||
# 复制 Firefox manifest
|
||||
shutil.copy2("manifest-firefox.json", build_dir / "manifest.json")
|
||||
|
||||
# 修改文件为 Firefox 优化
|
||||
optimize_for_firefox(build_dir)
|
||||
|
||||
print(f"Firefox 版本构建完成: {build_dir}")
|
||||
return build_dir
|
||||
|
||||
|
||||
def optimize_for_chrome(build_dir):
|
||||
"""为 Chrome 优化文件"""
|
||||
# 移除 background.js 中的 importScripts 调用,因为在 Manifest V3 中不需要
|
||||
bg_file = build_dir / "background.js"
|
||||
if bg_file.exists():
|
||||
content = bg_file.read_text(encoding="utf-8")
|
||||
# 注释掉 importScripts 调用
|
||||
content = content.replace(
|
||||
"importScripts('webext-compat.js');",
|
||||
"// importScripts('webext-compat.js'); // Chrome 不需要显式导入",
|
||||
)
|
||||
bg_file.write_text(content, encoding="utf-8")
|
||||
|
||||
|
||||
def optimize_for_firefox(build_dir):
|
||||
"""为 Firefox 优化文件"""
|
||||
# Firefox 特有的优化可以在这里添加
|
||||
pass
|
||||
|
||||
|
||||
def create_package(build_dir, platform):
|
||||
"""创建扩展包"""
|
||||
package_dir = Path("packages")
|
||||
package_dir.mkdir(exist_ok=True)
|
||||
|
||||
# 读取版本信息
|
||||
manifest_file = build_dir / "manifest.json"
|
||||
with open(manifest_file, encoding="utf-8") as f:
|
||||
manifest = json.load(f)
|
||||
|
||||
version = manifest["version"]
|
||||
package_name = f"xget-now-{platform}-v{version}.zip"
|
||||
package_path = package_dir / package_name
|
||||
|
||||
# 创建 ZIP 包
|
||||
with zipfile.ZipFile(package_path, "w", zipfile.ZIP_DEFLATED) as zipf:
|
||||
for file_path in build_dir.rglob("*"):
|
||||
if file_path.is_file():
|
||||
arcname = file_path.relative_to(build_dir)
|
||||
zipf.write(file_path, arcname)
|
||||
|
||||
print(f"扩展包已创建: {package_path}")
|
||||
return package_path
|
||||
|
||||
|
||||
def validate_manifest(manifest_path, platform):
|
||||
"""验证 manifest 文件"""
|
||||
try:
|
||||
with open(manifest_path, encoding="utf-8") as f:
|
||||
manifest = json.load(f)
|
||||
|
||||
if platform == "chrome":
|
||||
# 验证 Manifest V3 要求
|
||||
assert manifest.get("manifest_version") == 3, "Chrome 需要 Manifest V3"
|
||||
assert "action" in manifest, "Chrome 需要 action 字段"
|
||||
assert "service_worker" in manifest.get("background", {}), (
|
||||
"Chrome 需要 service_worker"
|
||||
)
|
||||
|
||||
elif platform == "firefox":
|
||||
# 验证 Manifest V2 要求
|
||||
assert manifest.get("manifest_version") == 2, "Firefox 需要 Manifest V2"
|
||||
assert "browser_action" in manifest, "Firefox 需要 browser_action 字段"
|
||||
assert (
|
||||
"applications" in manifest or "browser_specific_settings" in manifest
|
||||
), "Firefox 需要应用ID"
|
||||
|
||||
print(f"✓ {platform} manifest 验证通过")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ {platform} manifest 验证失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="构建 Xget Now 扩展")
|
||||
parser.add_argument(
|
||||
"--platform",
|
||||
choices=["chrome", "firefox", "all"],
|
||||
default="all",
|
||||
help="要构建的平台",
|
||||
)
|
||||
parser.add_argument("--package", action="store_true", help="创建扩展包")
|
||||
parser.add_argument(
|
||||
"--clean", action="store_true", default=True, help="清理构建目录"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
platforms = []
|
||||
if args.platform == "all":
|
||||
platforms = ["chrome", "firefox"]
|
||||
else:
|
||||
platforms = [args.platform]
|
||||
|
||||
build_results = []
|
||||
|
||||
for platform in platforms:
|
||||
try:
|
||||
if platform == "chrome":
|
||||
build_dir = build_chrome()
|
||||
elif platform == "firefox":
|
||||
build_dir = build_firefox()
|
||||
|
||||
# 验证 manifest
|
||||
manifest_path = build_dir / "manifest.json"
|
||||
if not validate_manifest(manifest_path, platform):
|
||||
continue
|
||||
|
||||
build_results.append((platform, build_dir))
|
||||
|
||||
# 创建扩展包
|
||||
if args.package:
|
||||
create_package(build_dir, platform)
|
||||
|
||||
except Exception as e:
|
||||
print(f"构建 {platform} 时出错: {e}")
|
||||
|
||||
# 总结
|
||||
print("\n构建总结:")
|
||||
for platform, build_dir in build_results:
|
||||
print(f"✓ {platform}: {build_dir}")
|
||||
|
||||
if args.package:
|
||||
print("\n扩展包位于 packages/ 目录")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user