Add iOS 27 remote media session and system player extension
This commit is contained in:
+40
-11
@@ -37,6 +37,13 @@ def source_group(folder):
|
||||
return add(folder, "PBXGroup", path=folder, sourceTree="<group>", children=refs), builds
|
||||
|
||||
app_group, app_sources = source_group("MusicBridge")
|
||||
remote_shared_group, remote_shared_sources = source_group("RemoteShared")
|
||||
remote_group, remote_sources = source_group("MusicBridgeRemote")
|
||||
remote_sources += [add("remote-shared/" + str(index), "PBXBuildFile", fileRef=objects[build]["fileRef"])
|
||||
for index, build in enumerate(remote_shared_sources)]
|
||||
for filename in ("Models.swift", "BridgeClient.swift"):
|
||||
remote_sources.append(add("remote-core/" + filename, "PBXBuildFile", fileRef=uid("MusicBridge/" + filename)))
|
||||
app_sources += remote_shared_sources
|
||||
shared_group, shared_sources = source_group("Shared")
|
||||
widget_group, widget_sources = source_group("MusicBridgeWidgets")
|
||||
app_sources += shared_sources
|
||||
@@ -54,16 +61,18 @@ objects[test_group]["children"].append(tls_fixture)
|
||||
tls_fixture_build = add("tls-fixture-build", "PBXBuildFile", fileRef=tls_fixture)
|
||||
products = []
|
||||
targets = []
|
||||
for name, sources, is_test in [("MusicBridge", app_sources, False), ("MusicBridgeTests", test_sources, True), ("MusicBridgeWidgets", widget_sources, False)]:
|
||||
for name, sources, is_test in [("MusicBridge", app_sources, False), ("MusicBridgeTests", test_sources, True), ("MusicBridgeWidgets", widget_sources, False), ("MusicBridgeRemote", remote_sources, False)]:
|
||||
is_widget = name == "MusicBridgeWidgets"
|
||||
product = add(name + "product", "PBXFileReference", explicitFileType="wrapper.app-extension" if is_widget else "wrapper.cfbundle" if is_test else "wrapper.application",
|
||||
includeInIndex=0, path=name + (".appex" if is_widget else ".xctest" if is_test else ".app"), sourceTree="BUILT_PRODUCTS_DIR")
|
||||
is_remote = name == "MusicBridgeRemote"
|
||||
is_extension = is_widget or is_remote
|
||||
product = add(name + "product", "PBXFileReference", explicitFileType="wrapper.extensionkit-extension" if is_remote else "wrapper.app-extension" if is_extension else "wrapper.cfbundle" if is_test else "wrapper.application",
|
||||
includeInIndex=0, path=name + (".appex" if is_extension else ".xctest" if is_test else ".app"), sourceTree="BUILT_PRODUCTS_DIR")
|
||||
products.append(product)
|
||||
phases = [add(name + "sources", "PBXSourcesBuildPhase", buildActionMask=2147483647, files=sources, runOnlyForDeploymentPostprocessing=0),
|
||||
add(name + "frameworks", "PBXFrameworksBuildPhase", buildActionMask=2147483647, files=[], runOnlyForDeploymentPostprocessing=0),
|
||||
add(name + "resources", "PBXResourcesBuildPhase", buildActionMask=2147483647, files=[] if is_widget else [fixture_build, tls_fixture_build] if is_test else [assets_build], runOnlyForDeploymentPostprocessing=0)]
|
||||
settings = dict(PRODUCT_NAME="$(TARGET_NAME)", PRODUCT_BUNDLE_IDENTIFIER="ru.yukinoki.musicbridge" + (".widgets" if is_widget else ".tests" if is_test else ""),
|
||||
SWIFT_VERSION="5.0", IPHONEOS_DEPLOYMENT_TARGET="17.0", SDKROOT="iphoneos",
|
||||
add(name + "resources", "PBXResourcesBuildPhase", buildActionMask=2147483647, files=[] if is_extension else [fixture_build, tls_fixture_build] if is_test else [assets_build], runOnlyForDeploymentPostprocessing=0)]
|
||||
settings = dict(PRODUCT_NAME="$(TARGET_NAME)", PRODUCT_BUNDLE_IDENTIFIER="ru.yukinoki.musicbridge" + (".remote" if is_remote else ".widgets" if is_widget else ".tests" if is_test else ""),
|
||||
SWIFT_VERSION="5.0", IPHONEOS_DEPLOYMENT_TARGET="27.0" if is_remote else "17.0", SDKROOT="iphoneos",
|
||||
SUPPORTED_PLATFORMS="iphoneos iphonesimulator", TARGETED_DEVICE_FAMILY="1", CODE_SIGN_STYLE="Automatic",
|
||||
GENERATE_INFOPLIST_FILE="YES" if is_test else "NO")
|
||||
deps = []
|
||||
@@ -71,24 +80,32 @@ for name, sources, is_test in [("MusicBridge", app_sources, False), ("MusicBridg
|
||||
settings.update(TEST_HOST="$(BUILT_PRODUCTS_DIR)/MusicBridge.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/MusicBridge", BUNDLE_LOADER="$(TEST_HOST)")
|
||||
proxy = add("test-proxy", "PBXContainerItemProxy", containerPortal=uid("project"), proxyType=1, remoteGlobalIDString=uid("MusicBridgetarget"), remoteInfo="MusicBridge")
|
||||
deps = [add("test-dependency", "PBXTargetDependency", target=uid("MusicBridgetarget"), targetProxy=proxy)]
|
||||
elif is_widget:
|
||||
settings.update(INFOPLIST_FILE="MusicBridgeWidgets/Info.plist", CURRENT_PROJECT_VERSION="7", MARKETING_VERSION="0.6.0",
|
||||
elif is_extension:
|
||||
settings.update(INFOPLIST_FILE=name + "/Info.plist", CURRENT_PROJECT_VERSION="8", MARKETING_VERSION="0.7.0",
|
||||
APPLICATION_EXTENSION_API_ONLY="YES", SKIP_INSTALL="YES",
|
||||
LD_RUNPATH_SEARCH_PATHS="$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks")
|
||||
if is_remote:
|
||||
settings.update(CODE_SIGN_ENTITLEMENTS="MusicBridgeRemote/Remote.entitlements")
|
||||
else:
|
||||
settings.update(INFOPLIST_FILE="MusicBridge/Info.plist", CURRENT_PROJECT_VERSION="7", MARKETING_VERSION="0.6.0", ASSETCATALOG_COMPILER_APPICON_NAME="AppIcon")
|
||||
settings.update(INFOPLIST_FILE="MusicBridge/Info.plist", CURRENT_PROJECT_VERSION="8", MARKETING_VERSION="0.7.0", ASSETCATALOG_COMPILER_APPICON_NAME="AppIcon", CODE_SIGN_ENTITLEMENTS="MusicBridge/App.entitlements")
|
||||
embed = add("embed-widget", "PBXBuildFile", fileRef=uid("MusicBridgeWidgetsproduct"), settings=dict(ATTRIBUTES=["RemoveHeadersOnCopy"]))
|
||||
embed_remote = add("embed-remote", "PBXBuildFile", fileRef=uid("MusicBridgeRemoteproduct"), settings=dict(ATTRIBUTES=["RemoveHeadersOnCopy"]))
|
||||
phases.append(add("embed-extensions", "PBXCopyFilesBuildPhase", buildActionMask=2147483647,
|
||||
dstPath="", dstSubfolderSpec=13, files=[embed], name="Embed App Extensions", runOnlyForDeploymentPostprocessing=0))
|
||||
phases.append(add("embed-remote-extensions", "PBXCopyFilesBuildPhase", buildActionMask=2147483647,
|
||||
dstPath="$(EXTENSIONS_FOLDER_PATH)", dstSubfolderSpec=16, files=[embed_remote], name="Embed ExtensionKit Extensions", runOnlyForDeploymentPostprocessing=0))
|
||||
proxy = add("widget-proxy", "PBXContainerItemProxy", containerPortal=uid("project"), proxyType=1,
|
||||
remoteGlobalIDString=uid("MusicBridgeWidgetstarget"), remoteInfo="MusicBridgeWidgets")
|
||||
deps = [add("widget-dependency", "PBXTargetDependency", target=uid("MusicBridgeWidgetstarget"), targetProxy=proxy)]
|
||||
remote_proxy = add("remote-proxy", "PBXContainerItemProxy", containerPortal=uid("project"), proxyType=1,
|
||||
remoteGlobalIDString=uid("MusicBridgeRemotetarget"), remoteInfo="MusicBridgeRemote")
|
||||
deps.append(add("remote-dependency", "PBXTargetDependency", target=uid("MusicBridgeRemotetarget"), targetProxy=remote_proxy))
|
||||
targets.append(add(name + "target", "PBXNativeTarget", name=name, productName=name, productReference=product,
|
||||
productType="com.apple.product-type.app-extension" if is_widget else "com.apple.product-type.bundle.unit-test" if is_test else "com.apple.product-type.application",
|
||||
productType="com.apple.product-type.extensionkit-extension" if is_remote else "com.apple.product-type.app-extension" if is_widget else "com.apple.product-type.bundle.unit-test" if is_test else "com.apple.product-type.application",
|
||||
buildConfigurationList=configurations(name, settings), buildPhases=phases, buildRules=[], dependencies=deps))
|
||||
|
||||
product_group = add("products", "PBXGroup", name="Products", sourceTree="<group>", children=products)
|
||||
main_group = add("main", "PBXGroup", sourceTree="<group>", children=[app_group, shared_group, widget_group, test_group, product_group])
|
||||
main_group = add("main", "PBXGroup", sourceTree="<group>", children=[app_group, shared_group, widget_group, remote_shared_group, remote_group, test_group, product_group])
|
||||
project = add("project", "PBXProject", attributes=dict(LastUpgradeCheck="1600", BuildIndependentTargetsInParallel="YES"),
|
||||
buildConfigurationList=configurations("project", dict(CLANG_ENABLE_MODULES="YES", CLANG_ENABLE_OBJC_ARC="YES")),
|
||||
compatibilityVersion="Xcode 14.0", developmentRegion="ru", knownRegions=["ru", "en", "Base"],
|
||||
@@ -144,4 +161,16 @@ widget_info = dict(CFBundleDevelopmentRegion="ru", CFBundleDisplayName="MusicBri
|
||||
CFBundleShortVersionString="$(MARKETING_VERSION)", CFBundleVersion="$(CURRENT_PROJECT_VERSION)",
|
||||
NSExtension=dict(NSExtensionPointIdentifier="com.apple.widgetkit-extension"))
|
||||
(ROOT / "MusicBridgeWidgets" / "Info.plist").write_bytes(plistlib.dumps(widget_info, sort_keys=False))
|
||||
shared_group_name = "$(AppIdentifierPrefix)ru.yukinoki.musicbridge.remote-control"
|
||||
info["MusicBridgeSharedKeychainGroup"] = shared_group_name
|
||||
(ROOT / "MusicBridge" / "Info.plist").write_bytes(plistlib.dumps(info, sort_keys=False))
|
||||
remote_info = {k: v for k, v in widget_info.items() if k != "NSExtension"}
|
||||
remote_info.update(EXAppExtensionAttributes=dict(EXExtensionPointIdentifier="com.apple.nowplaying.remote-media"),
|
||||
MusicBridgeSharedKeychainGroup=shared_group_name,
|
||||
NSLocalNetworkUsageDescription=info["NSLocalNetworkUsageDescription"],
|
||||
NSAppTransportSecurity=info["NSAppTransportSecurity"])
|
||||
(ROOT / "MusicBridgeRemote" / "Info.plist").write_bytes(plistlib.dumps(remote_info, sort_keys=False))
|
||||
for folder, filename in (("MusicBridge", "App.entitlements"), ("MusicBridgeRemote", "Remote.entitlements")):
|
||||
groups = ["$(AppIdentifierPrefix)$(PRODUCT_BUNDLE_IDENTIFIER)", shared_group_name]
|
||||
(ROOT / folder / filename).write_bytes(plistlib.dumps({"keychain-access-groups": groups}))
|
||||
print("Generated Xcode project, shared scheme and Info.plist.")
|
||||
|
||||
@@ -11,12 +11,13 @@ import xml.etree.ElementTree as ET
|
||||
root = pathlib.Path(__file__).resolve().parents[1]
|
||||
generated = [root / "MusicBridge.xcodeproj/project.pbxproj",
|
||||
root / "MusicBridge.xcodeproj/xcshareddata/xcschemes/MusicBridge.xcscheme",
|
||||
root / "MusicBridge/Info.plist", root / "MusicBridgeWidgets/Info.plist"]
|
||||
root / "MusicBridge/Info.plist", root / "MusicBridgeWidgets/Info.plist",
|
||||
root / "MusicBridgeRemote/Info.plist", root / "MusicBridge/App.entitlements", root / "MusicBridgeRemote/Remote.entitlements"]
|
||||
before = [p.read_bytes() for p in generated]
|
||||
subprocess.run([sys.executable, str(root / "tools/generate_project.py")], check=True)
|
||||
assert before == [p.read_bytes() for p in generated], "Generated project is stale; review and commit regeneration."
|
||||
project = generated[0].read_text(encoding="utf-8")
|
||||
for folder in ("MusicBridge", "MusicBridgeTests", "Shared", "MusicBridgeWidgets"):
|
||||
for folder in ("MusicBridge", "MusicBridgeTests", "Shared", "MusicBridgeWidgets", "RemoteShared", "MusicBridgeRemote"):
|
||||
for source in (root / folder).glob("*.swift"):
|
||||
key = hashlib.sha256(source.relative_to(root).as_posix().encode()).hexdigest()[:24].upper()
|
||||
assert key in project, f"Missing source: {source.name}"
|
||||
|
||||
Reference in New Issue
Block a user