feat(tvos): add top shelf support
This commit is contained in:
@@ -8,6 +8,8 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
055E465F9095D0B6E9B91D46 /* PathProviderPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41AA251EF365516E2AC5287 /* PathProviderPlugin.swift */; };
|
||||
1C6B234E223CDFFE5BF3FC0B /* TVServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25B7925EFD8A2C1C7EB667D5 /* TVServices.framework */; };
|
||||
28DB4404B17342F46BC2B0A1 /* TopShelfProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2F829B3F190657106F66379 /* TopShelfProvider.swift */; };
|
||||
35DB0C8FEF635A3BCA0B722A /* PackageInfoPlusPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9426EFA282CDA8E0E98EEE9 /* PackageInfoPlusPlugin.swift */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
5C71F5F7B33075F2B007825B /* MpvPlayerPluginShared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73645904F226A24585A092CE /* MpvPlayerPluginShared.swift */; };
|
||||
@@ -22,12 +24,24 @@
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
A7596F780E93AF0BE3838A26 /* ConnectivityProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CCA7E80F3A99D8759F2E59F /* ConnectivityProvider.swift */; };
|
||||
AA34E3E5872B3792D6959EAA /* MpvPipController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2635E12EB9322B151EE5127 /* MpvPipController.swift */; };
|
||||
BDD87DA7F5C435F9DBB8F9BE /* TopShelfExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 035F0D5A5E54BE7AD9AFA23C /* TopShelfExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
C6A15611158B29B0FF43A960 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 824D2C68D1F1206932E118C2 /* Pods_Runner.framework */; };
|
||||
CD1C0534948840272E58248E /* PathMonitorConnectivityProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AEF79DFBD1D80F00AB39CDA /* PathMonitorConnectivityProvider.swift */; };
|
||||
D2A548D9DE1A0F319B30B74C /* SystemShelfPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0760C00EDC55A4D718BCB406 /* SystemShelfPlugin.swift */; };
|
||||
E3DEAD2AAFC347A2E55AC0F7 /* SharedPreferencesPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0455EBA0EF4A61D3B71D2D7 /* SharedPreferencesPlugin.swift */; };
|
||||
E79A4474D308631AFA59CAE7 /* DeviceInfoPlusPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E1F41676FEF1AB57076F8B9 /* DeviceInfoPlusPlugin.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
3E4E59C5E29F44BA64BEB559 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 63C63C245D7F38BFF091CEC3;
|
||||
remoteInfo = TopShelfExtension;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
@@ -39,11 +53,25 @@
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
AE0235548DB8213618795857 /* Embed App Extensions */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 13;
|
||||
files = (
|
||||
BDD87DA7F5C435F9DBB8F9BE /* TopShelfExtension.appex in Embed App Extensions */,
|
||||
);
|
||||
name = "Embed App Extensions";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
035F0D5A5E54BE7AD9AFA23C /* TopShelfExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; name = TopShelfExtension.appex; path = TopShelfExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
04DD35536DEE7C27FFA53862 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
0760C00EDC55A4D718BCB406 /* SystemShelfPlugin.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SystemShelfPlugin.swift; sourceTree = "<group>"; };
|
||||
0C25F4F2367A30B47E945AD6 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
25B7925EFD8A2C1C7EB667D5 /* TVServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TVServices.framework; path = System/Library/Frameworks/TVServices.framework; sourceTree = SDKROOT; };
|
||||
34CD411CCD84E381C4BF4C1B /* messages.g.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = messages.g.swift; sourceTree = "<group>"; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
3CCA7E80F3A99D8759F2E59F /* ConnectivityProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConnectivityProvider.swift; sourceTree = "<group>"; };
|
||||
@@ -56,6 +84,8 @@
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
824D2C68D1F1206932E118C2 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
9165AF55B967D8845D042FE7 /* TopShelfExtension.entitlements */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.entitlements; path = TopShelfExtension.entitlements; sourceTree = "<group>"; };
|
||||
937C0D45D6114EF1E957F5F6 /* Runner.entitlements */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -66,13 +96,23 @@
|
||||
9D7A998830EDC8F77BF521D1 /* MpvPlayerPlugin.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MpvPlayerPlugin.swift; path = ../ios/Runner/MpvPlayer/MpvPlayerPlugin.swift; sourceTree = "<source_root>"; };
|
||||
A12B8610AE5D580077264851 /* MpvPlayerCore.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MpvPlayerCore.swift; path = ../ios/Runner/MpvPlayer/MpvPlayerCore.swift; sourceTree = "<source_root>"; };
|
||||
A2635E12EB9322B151EE5127 /* MpvPipController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MpvPipController.swift; path = ../ios/Runner/MpvPlayer/MpvPipController.swift; sourceTree = "<source_root>"; };
|
||||
BBCB49C8AE9E90DEF97A87CA /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
C0455EBA0EF4A61D3B71D2D7 /* SharedPreferencesPlugin.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SharedPreferencesPlugin.swift; sourceTree = "<group>"; };
|
||||
D41AA251EF365516E2AC5287 /* PathProviderPlugin.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PathProviderPlugin.swift; sourceTree = "<group>"; };
|
||||
D52A3BDA46E79969EA1DF3AC /* MpvPlayerCoreBase.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MpvPlayerCoreBase.swift; path = ../shared/apple/MpvPlayer/MpvPlayerCoreBase.swift; sourceTree = "<source_root>"; };
|
||||
F2F829B3F190657106F66379 /* TopShelfProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TopShelfProvider.swift; sourceTree = "<group>"; };
|
||||
F9426EFA282CDA8E0E98EEE9 /* PackageInfoPlusPlugin.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PackageInfoPlusPlugin.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
43E2EE359822E384AD7E8A2E /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
1C6B234E223CDFFE5BF3FC0B /* TVServices.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -114,6 +154,17 @@
|
||||
path = connectivity_plus;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
47C2D3F50A23DE33DE92F592 /* TopShelfExtension */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F2F829B3F190657106F66379 /* TopShelfProvider.swift */,
|
||||
BBCB49C8AE9E90DEF97A87CA /* Info.plist */,
|
||||
9165AF55B967D8845D042FE7 /* TopShelfExtension.entitlements */,
|
||||
);
|
||||
name = TopShelfExtension;
|
||||
path = TopShelfExtension;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
53CDD29681161166962B9FA5 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -128,6 +179,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
824D2C68D1F1206932E118C2 /* Pods_Runner.framework */,
|
||||
25B7925EFD8A2C1C7EB667D5 /* TVServices.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
@@ -160,6 +212,7 @@
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
53CDD29681161166962B9FA5 /* Pods */,
|
||||
5833EC5B503BBB4E370BA1B7 /* Frameworks */,
|
||||
47C2D3F50A23DE33DE92F592 /* TopShelfExtension */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -167,6 +220,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||
035F0D5A5E54BE7AD9AFA23C /* TopShelfExtension.appex */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -182,6 +236,8 @@
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
||||
BF0B7DFE378943E9D7865D18 /* MpvPlayer */,
|
||||
D58B788B11920D95BC7D750C /* Plugins */,
|
||||
0760C00EDC55A4D718BCB406 /* SystemShelfPlugin.swift */,
|
||||
937C0D45D6114EF1E957F5F6 /* Runner.entitlements */,
|
||||
);
|
||||
path = Runner;
|
||||
sourceTree = "<group>";
|
||||
@@ -224,6 +280,23 @@
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
63C63C245D7F38BFF091CEC3 /* TopShelfExtension */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = C995F7A5B711B6DB7E97B000 /* Build configuration list for PBXNativeTarget "TopShelfExtension" */;
|
||||
buildPhases = (
|
||||
B1C48839AB6C24EF099DDFA3 /* Sources */,
|
||||
43E2EE359822E384AD7E8A2E /* Frameworks */,
|
||||
64CEA7DE6B9394CE88783302 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = TopShelfExtension;
|
||||
productName = TopShelfExtension;
|
||||
productReference = 035F0D5A5E54BE7AD9AFA23C /* TopShelfExtension.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
97C146ED1CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
@@ -234,12 +307,14 @@
|
||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
AE0235548DB8213618795857 /* Embed App Extensions */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
7C33FC680D67B3859BF9AE6C /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
F0399FC35D3A6ED67E74810D /* PBXTargetDependency */,
|
||||
);
|
||||
name = Runner;
|
||||
packageProductDependencies = (
|
||||
@@ -281,11 +356,19 @@
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
97C146ED1CF9000F007C117D /* Runner */,
|
||||
63C63C245D7F38BFF091CEC3 /* TopShelfExtension */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
64CEA7DE6B9394CE88783302 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EC1CF9000F007C117D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -388,11 +471,29 @@
|
||||
81F08E404EBEB19B00FF148D /* ConnectivityPlusPlugin.swift in Sources */,
|
||||
A7596F780E93AF0BE3838A26 /* ConnectivityProvider.swift in Sources */,
|
||||
CD1C0534948840272E58248E /* PathMonitorConnectivityProvider.swift in Sources */,
|
||||
D2A548D9DE1A0F319B30B74C /* SystemShelfPlugin.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
B1C48839AB6C24EF099DDFA3 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
28DB4404B17342F46BC2B0A1 /* TopShelfProvider.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
F0399FC35D3A6ED67E74810D /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = TopShelfExtension;
|
||||
target = 63C63C245D7F38BFF091CEC3 /* TopShelfExtension */;
|
||||
targetProxy = 3E4E59C5E29F44BA64BEB559 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
@@ -470,6 +571,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
@@ -500,6 +602,98 @@
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
37D721B4A1E3E0EDC16D1456 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 9740EEB31CF90195004384FC /* Generated.xcconfig */;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = TopShelfExtension/TopShelfExtension.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = G88U5B5783;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = TopShelfExtension/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = "$(FLUTTER_BUILD_NAME)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.edde746.plezy.TopShelfExtension;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = appletvos;
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTED_PLATFORMS = "appletvos appletvsimulator";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 3;
|
||||
TVOS_DEPLOYMENT_TARGET = 14.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
4A02CC70113C79647D6EEB12 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 9740EEB31CF90195004384FC /* Generated.xcconfig */;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = TopShelfExtension/TopShelfExtension.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = G88U5B5783;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = TopShelfExtension/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = "$(FLUTTER_BUILD_NAME)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.edde746.plezy.TopShelfExtension;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = appletvos;
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTED_PLATFORMS = "appletvos appletvsimulator";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 3;
|
||||
TVOS_DEPLOYMENT_TARGET = 14.0;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
65F6020FE0DF48006BADE49C /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 9740EEB31CF90195004384FC /* Generated.xcconfig */;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = TopShelfExtension/TopShelfExtension.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = G88U5B5783;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = TopShelfExtension/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = "$(FLUTTER_BUILD_NAME)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.edde746.plezy.TopShelfExtension;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = appletvos;
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTED_PLATFORMS = "appletvos appletvsimulator";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 3;
|
||||
TVOS_DEPLOYMENT_TARGET = 14.0;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
97C147031CF9000F007C117D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@@ -614,6 +808,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
@@ -651,6 +846,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
@@ -704,6 +900,16 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
C995F7A5B711B6DB7E97B000 /* Build configuration list for PBXNativeTarget "TopShelfExtension" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
65F6020FE0DF48006BADE49C /* Release */,
|
||||
37D721B4A1E3E0EDC16D1456 /* Debug */,
|
||||
4A02CC70113C79647D6EEB12 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
|
||||
@@ -128,6 +128,10 @@ import wakelock_plus
|
||||
|
||||
application.beginReceivingRemoteControlEvents()
|
||||
|
||||
if let url = launchOptions?[UIApplication.LaunchOptionsKey.url] as? URL {
|
||||
_ = SystemShelfPlugin.handleOpenURL(url)
|
||||
}
|
||||
|
||||
if let r = self.registrar(forPlugin: "SharedPreferencesPlugin") {
|
||||
SharedPreferencesPlugin.register(with: r)
|
||||
}
|
||||
@@ -155,7 +159,21 @@ import wakelock_plus
|
||||
if let r = self.registrar(forPlugin: "WakelockPlusPlugin") {
|
||||
WakelockPlusPlugin.register(with: r)
|
||||
}
|
||||
if let r = self.registrar(forPlugin: "SystemShelfPlugin") {
|
||||
SystemShelfPlugin.register(with: r)
|
||||
}
|
||||
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
open url: URL,
|
||||
options: [UIApplication.OpenURLOptionsKey: Any] = [:]
|
||||
) -> Bool {
|
||||
if SystemShelfPlugin.handleOpenURL(url) {
|
||||
return true
|
||||
}
|
||||
return super.application(application, open: url, options: options)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,17 @@
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>com.edde746.plezy.play</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>plezy</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>GCSupportedGameControllers</key>
|
||||
<array>
|
||||
<dict>
|
||||
@@ -39,6 +50,11 @@
|
||||
<true/>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.com.edde746.plezy</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,177 @@
|
||||
import Foundation
|
||||
import TVServices
|
||||
|
||||
#if os(tvOS)
|
||||
import Flutter
|
||||
|
||||
final class SystemShelfPlugin: NSObject, FlutterPlugin {
|
||||
private static let channelName = "com.plezy/system_shelf"
|
||||
private static let appGroupIdentifier = "group.com.edde746.plezy"
|
||||
private static let cacheFileName = "PlezySystemShelfCache.json"
|
||||
private static var pendingDeepLink: String?
|
||||
private static var methodChannel: FlutterMethodChannel?
|
||||
|
||||
static func register(with registrar: FlutterPluginRegistrar) {
|
||||
let channel = FlutterMethodChannel(
|
||||
name: channelName,
|
||||
binaryMessenger: registrar.messenger()
|
||||
)
|
||||
methodChannel = channel
|
||||
registrar.addMethodCallDelegate(SystemShelfPlugin(), channel: channel)
|
||||
}
|
||||
|
||||
static func handleOpenURL(_ url: URL) -> Bool {
|
||||
guard let contentId = contentId(from: url) else { return false }
|
||||
pendingDeepLink = contentId
|
||||
methodChannel?.invokeMethod("onShelfItemTap", arguments: ["contentId": contentId])
|
||||
return true
|
||||
}
|
||||
|
||||
private static func contentId(from url: URL) -> String? {
|
||||
guard url.scheme == "plezy", url.host == "play" else { return nil }
|
||||
let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
|
||||
return components?.queryItems?.first { $0.name == "content_id" }?.value
|
||||
}
|
||||
|
||||
func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||
switch call.method {
|
||||
case "isSupported":
|
||||
let supported = Self.cacheURL != nil
|
||||
if !supported {
|
||||
Self.log("App Group container unavailable")
|
||||
}
|
||||
result(supported)
|
||||
case "sync":
|
||||
guard let args = call.arguments as? [String: Any], let rawItems = args["items"] as? [[String: Any]] else {
|
||||
result(FlutterError(code: "INVALID_ARGS", message: "Missing items", details: nil))
|
||||
return
|
||||
}
|
||||
result(Self.writeItems(rawItems.map(Self.normalizedItem)))
|
||||
case "clear":
|
||||
result(Self.clearCache())
|
||||
case "remove":
|
||||
guard let args = call.arguments as? [String: Any], let contentId = args["contentId"] as? String else {
|
||||
result(FlutterError(code: "INVALID_ARGS", message: "Missing contentId", details: nil))
|
||||
return
|
||||
}
|
||||
result(Self.removeItem(contentId: contentId))
|
||||
case "getInitialDeepLink":
|
||||
let contentId = Self.pendingDeepLink
|
||||
Self.pendingDeepLink = nil
|
||||
result(contentId)
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
private static var appGroupContainerURL: URL? {
|
||||
FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier)
|
||||
}
|
||||
|
||||
private static var cacheURL: URL? {
|
||||
appGroupContainerURL?.appendingPathComponent(cacheFileName, isDirectory: false)
|
||||
}
|
||||
|
||||
private static func log(_ message: String) {
|
||||
NSLog("PlezySystemShelf: %@", message)
|
||||
}
|
||||
|
||||
private static func normalizedItem(_ item: [String: Any]) -> [String: Any] {
|
||||
item.reduce(into: [String: Any]()) { result, entry in
|
||||
if entry.value is NSNull { return }
|
||||
result[entry.key] = entry.value
|
||||
}
|
||||
}
|
||||
|
||||
private static func writeItems(_ items: [[String: Any]]) -> Bool {
|
||||
let payload: [String: Any] = [
|
||||
"updatedAt": Date().timeIntervalSince1970,
|
||||
"sections": [
|
||||
[
|
||||
"id": "continue_watching",
|
||||
"title": "Continue Watching",
|
||||
"items": items,
|
||||
]
|
||||
],
|
||||
]
|
||||
|
||||
return writePayload(payload)
|
||||
}
|
||||
|
||||
private static func writePayload(_ payload: [String: Any]) -> Bool {
|
||||
guard let url = cacheURL else {
|
||||
log("Cannot write cache because App Group container is unavailable")
|
||||
return false
|
||||
}
|
||||
|
||||
guard JSONSerialization.isValidJSONObject(payload),
|
||||
let data = try? JSONSerialization.data(withJSONObject: payload)
|
||||
else {
|
||||
log("Cannot write cache because payload is not valid JSON")
|
||||
return false
|
||||
}
|
||||
|
||||
do {
|
||||
try data.write(to: url, options: [.atomic])
|
||||
} catch {
|
||||
log("Failed to write cache: \(error)")
|
||||
return false
|
||||
}
|
||||
|
||||
let itemCount =
|
||||
(payload["sections"] as? [[String: Any]])?.reduce(0) { count, section in
|
||||
count + ((section["items"] as? [[String: Any]])?.count ?? 0)
|
||||
} ?? 0
|
||||
log("Wrote cache with \(itemCount) items")
|
||||
TVTopShelfContentProvider.topShelfContentDidChange()
|
||||
return true
|
||||
}
|
||||
|
||||
private static func clearCache() -> Bool {
|
||||
guard let url = cacheURL else {
|
||||
log("Cannot clear cache because App Group container is unavailable")
|
||||
return false
|
||||
}
|
||||
|
||||
do {
|
||||
if FileManager.default.fileExists(atPath: url.path) {
|
||||
try FileManager.default.removeItem(at: url)
|
||||
}
|
||||
} catch {
|
||||
log("Failed to clear cache: \(error)")
|
||||
return false
|
||||
}
|
||||
|
||||
log("Cleared cache")
|
||||
TVTopShelfContentProvider.topShelfContentDidChange()
|
||||
return true
|
||||
}
|
||||
|
||||
private static func removeItem(contentId: String) -> Bool {
|
||||
guard let url = cacheURL,
|
||||
let data = try? Data(contentsOf: url),
|
||||
var payload = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
|
||||
let sections = payload["sections"] as? [[String: Any]]
|
||||
else {
|
||||
log("Cannot remove cache item because cache is unavailable or invalid")
|
||||
return false
|
||||
}
|
||||
|
||||
var removed = false
|
||||
let filteredSections = sections.map { section -> [String: Any] in
|
||||
var nextSection = section
|
||||
if let items = section["items"] as? [[String: Any]] {
|
||||
let filteredItems = items.filter { $0["contentId"] as? String != contentId }
|
||||
removed = removed || filteredItems.count != items.count
|
||||
nextSection["items"] = filteredItems
|
||||
}
|
||||
return nextSection
|
||||
}
|
||||
|
||||
if !removed { return false }
|
||||
payload["updatedAt"] = Date().timeIntervalSince1970
|
||||
payload["sections"] = filteredSections
|
||||
return writePayload(payload)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Plezy Top Shelf</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.tv-top-shelf</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).TopShelfProvider</string>
|
||||
</dict>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>arm64</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.com.edde746.plezy</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,141 @@
|
||||
import Foundation
|
||||
import TVServices
|
||||
|
||||
private enum TopShelfShared {
|
||||
static let appGroupIdentifier = "group.com.edde746.plezy"
|
||||
static let cacheFileName = "PlezySystemShelfCache.json"
|
||||
|
||||
static var cacheURL: URL? {
|
||||
FileManager.default
|
||||
.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier)?
|
||||
.appendingPathComponent(cacheFileName, isDirectory: false)
|
||||
}
|
||||
|
||||
static func log(_ message: String) {
|
||||
NSLog("PlezyTopShelf: %@", message)
|
||||
}
|
||||
}
|
||||
|
||||
private struct TopShelfCachePayload: Decodable {
|
||||
struct Section: Decodable {
|
||||
let id: String
|
||||
let title: String
|
||||
let items: [Item]
|
||||
}
|
||||
|
||||
struct Item: Decodable {
|
||||
let contentId: String
|
||||
let title: String
|
||||
let episodeTitle: String?
|
||||
let description: String?
|
||||
let posterUri: String?
|
||||
let type: String?
|
||||
let duration: Double?
|
||||
let lastPlaybackPosition: Double?
|
||||
let seasonNumber: Int?
|
||||
let episodeNumber: Int?
|
||||
}
|
||||
|
||||
let sections: [Section]
|
||||
}
|
||||
|
||||
final class TopShelfProvider: TVTopShelfContentProvider {
|
||||
override func loadTopShelfContent() async -> (any TVTopShelfContent)? {
|
||||
buildContent()
|
||||
}
|
||||
|
||||
private func buildContent() -> TVTopShelfContent? {
|
||||
guard let url = TopShelfShared.cacheURL else {
|
||||
TopShelfShared.log("App Group container unavailable")
|
||||
return nil
|
||||
}
|
||||
|
||||
guard FileManager.default.fileExists(atPath: url.path) else {
|
||||
TopShelfShared.log("Cache file missing")
|
||||
return nil
|
||||
}
|
||||
|
||||
let payload: TopShelfCachePayload
|
||||
do {
|
||||
let data = try Data(contentsOf: url)
|
||||
payload = try JSONDecoder().decode(TopShelfCachePayload.self, from: data)
|
||||
} catch {
|
||||
TopShelfShared.log("Failed to read cache: \(error)")
|
||||
return nil
|
||||
}
|
||||
|
||||
let sections = payload.sections.compactMap { section -> TVTopShelfItemCollection<TVTopShelfSectionedItem>? in
|
||||
let items = section.items.compactMap(makeTopShelfItem)
|
||||
guard !items.isEmpty else { return nil }
|
||||
|
||||
let collection = TVTopShelfItemCollection(items: items)
|
||||
collection.title = section.title
|
||||
return collection
|
||||
}
|
||||
|
||||
guard !sections.isEmpty else {
|
||||
TopShelfShared.log("Cache has no displayable items")
|
||||
return nil
|
||||
}
|
||||
|
||||
let itemCount = sections.reduce(0) { $0 + $1.items.count }
|
||||
TopShelfShared.log("Loaded \(itemCount) items")
|
||||
return TVTopShelfSectionedContent(sections: sections)
|
||||
}
|
||||
|
||||
private func makeTopShelfItem(_ cacheItem: TopShelfCachePayload.Item) -> TVTopShelfSectionedItem? {
|
||||
guard !cacheItem.contentId.isEmpty else { return nil }
|
||||
|
||||
let item = TVTopShelfSectionedItem(identifier: cacheItem.contentId)
|
||||
item.title = displayTitle(for: cacheItem)
|
||||
item.imageShape = .hdtv
|
||||
|
||||
if let duration = cacheItem.duration, duration > 0,
|
||||
let position = cacheItem.lastPlaybackPosition, position > 0
|
||||
{
|
||||
item.playbackProgress = min(max(position / duration, 0), 1)
|
||||
}
|
||||
|
||||
if let url = deepLinkURL(contentId: cacheItem.contentId) {
|
||||
let action = TVTopShelfAction(url: url)
|
||||
item.displayAction = action
|
||||
item.playAction = action
|
||||
}
|
||||
|
||||
if let posterUri = cacheItem.posterUri, let imageURL = URL(string: posterUri) {
|
||||
item.setImageURL(imageURL, for: .screenScale1x)
|
||||
item.setImageURL(imageURL, for: .screenScale2x)
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
private func displayTitle(for item: TopShelfCachePayload.Item) -> String {
|
||||
guard let episodeTitle = item.episodeTitle, !episodeTitle.isEmpty else {
|
||||
return item.title
|
||||
}
|
||||
|
||||
let episodePrefix: String? = {
|
||||
if let seasonNumber = item.seasonNumber, let episodeNumber = item.episodeNumber {
|
||||
return "S\(seasonNumber) E\(episodeNumber)"
|
||||
}
|
||||
if let episodeNumber = item.episodeNumber {
|
||||
return "E\(episodeNumber)"
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
|
||||
if let episodePrefix {
|
||||
return "\(item.title) - \(episodePrefix) - \(episodeTitle)"
|
||||
}
|
||||
return "\(item.title) - \(episodeTitle)"
|
||||
}
|
||||
|
||||
private func deepLinkURL(contentId: String) -> URL? {
|
||||
var components = URLComponents()
|
||||
components.scheme = "plezy"
|
||||
components.host = "play"
|
||||
components.queryItems = [URLQueryItem(name: "content_id", value: contentId)]
|
||||
return components.url
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
#!/usr/bin/env ruby
|
||||
# Adds Plezy's tvOS Top Shelf extension target and Runner-side bridge source.
|
||||
|
||||
require 'xcodeproj'
|
||||
|
||||
PROJECT_PATH = File.expand_path('../Runner.xcodeproj', __dir__)
|
||||
project = Xcodeproj::Project.open(PROJECT_PATH)
|
||||
runner = project.targets.find { |t| t.name == 'Runner' }
|
||||
raise 'Runner target not found' unless runner
|
||||
|
||||
main_group = project.main_group
|
||||
runner_group = main_group['Runner']
|
||||
raise 'Runner group not found' unless runner_group
|
||||
products_group = main_group['Products'] || main_group.new_group('Products')
|
||||
frameworks_group = main_group['Frameworks'] || main_group.new_group('Frameworks')
|
||||
generated_config_ref = project.files.find { |file| file.path == 'Flutter/Generated.xcconfig' }
|
||||
raise 'Generated.xcconfig not found' unless generated_config_ref
|
||||
|
||||
def ensure_file(group, path, name: nil, source_tree: '<group>')
|
||||
existing = group.files.find { |f| f.path == path || f.display_name == (name || File.basename(path)) }
|
||||
return existing if existing
|
||||
|
||||
ref = group.new_file(path)
|
||||
ref.name = name if name
|
||||
ref.source_tree = source_tree
|
||||
ref
|
||||
end
|
||||
|
||||
def ensure_source(target, file_ref)
|
||||
phase = target.source_build_phase
|
||||
return if phase.files_references.include?(file_ref)
|
||||
|
||||
phase.add_file_reference(file_ref, true)
|
||||
end
|
||||
|
||||
def ensure_copy_file(project, phase, file_ref)
|
||||
existing = phase.files.find { |build_file| build_file.file_ref == file_ref }
|
||||
return existing if existing
|
||||
|
||||
build_file = project.new(Xcodeproj::Project::Object::PBXBuildFile)
|
||||
build_file.file_ref = file_ref
|
||||
build_file.settings = { 'ATTRIBUTES' => ['RemoveHeadersOnCopy'] }
|
||||
phase.files << build_file
|
||||
build_file
|
||||
end
|
||||
|
||||
def ensure_framework(target, file_ref)
|
||||
phase = target.frameworks_build_phase
|
||||
return if phase.files_references.include?(file_ref)
|
||||
|
||||
phase.add_file_reference(file_ref, true)
|
||||
end
|
||||
|
||||
system_shelf_ref = ensure_file(runner_group, 'SystemShelfPlugin.swift')
|
||||
ensure_source(runner, system_shelf_ref)
|
||||
ensure_file(runner_group, 'Runner.entitlements')
|
||||
|
||||
extension_group = main_group['TopShelfExtension'] || main_group.new_group('TopShelfExtension', 'TopShelfExtension')
|
||||
top_shelf_ref = ensure_file(extension_group, 'TopShelfProvider.swift')
|
||||
ensure_file(extension_group, 'Info.plist')
|
||||
ensure_file(extension_group, 'TopShelfExtension.entitlements')
|
||||
|
||||
extension_target = project.targets.find { |t| t.name == 'TopShelfExtension' }
|
||||
unless extension_target
|
||||
extension_target = project.new_target(:app_extension, 'TopShelfExtension', :tvos, '14.0')
|
||||
end
|
||||
extension_target.product_type = 'com.apple.product-type.app-extension'
|
||||
|
||||
ensure_source(extension_target, top_shelf_ref)
|
||||
|
||||
removed_framework_refs = []
|
||||
extension_target.frameworks_build_phase.files.delete_if do |build_file|
|
||||
next false unless build_file.file_ref&.display_name == 'Foundation.framework'
|
||||
|
||||
removed_framework_refs << build_file.file_ref
|
||||
true
|
||||
end
|
||||
removed_framework_refs.compact.uniq.each do |file_ref|
|
||||
still_used = project.targets.any? do |target|
|
||||
target.frameworks_build_phase.files_references.include?(file_ref)
|
||||
end
|
||||
file_ref.remove_from_project unless still_used
|
||||
end
|
||||
|
||||
tv_services_ref = ensure_file(
|
||||
frameworks_group,
|
||||
'System/Library/Frameworks/TVServices.framework',
|
||||
name: 'TVServices.framework',
|
||||
source_tree: 'SDKROOT'
|
||||
)
|
||||
ensure_framework(extension_target, tv_services_ref)
|
||||
|
||||
extension_product = extension_target.product_reference
|
||||
extension_product.name = 'TopShelfExtension.appex'
|
||||
extension_product.path = 'TopShelfExtension.appex'
|
||||
extension_product.explicit_file_type = 'wrapper.app-extension'
|
||||
products_group.children << extension_product unless products_group.children.include?(extension_product)
|
||||
|
||||
runner.add_dependency(extension_target) unless runner.dependencies.any? { |d| d.target == extension_target }
|
||||
|
||||
embed_phase = runner.copy_files_build_phases.find { |phase| phase.name == 'Embed App Extensions' }
|
||||
unless embed_phase
|
||||
embed_phase = project.new(Xcodeproj::Project::Object::PBXCopyFilesBuildPhase)
|
||||
embed_phase.name = 'Embed App Extensions'
|
||||
embed_phase.dst_subfolder_spec = '13'
|
||||
embed_phase.dst_path = ''
|
||||
runner.build_phases.insert(-3, embed_phase)
|
||||
end
|
||||
ensure_copy_file(project, embed_phase, extension_product)
|
||||
|
||||
runner.build_configurations.each do |config|
|
||||
config.build_settings['CODE_SIGN_ENTITLEMENTS'] = 'Runner/Runner.entitlements'
|
||||
end
|
||||
|
||||
extension_target.build_configurations.each do |config|
|
||||
config.base_configuration_reference = generated_config_ref
|
||||
|
||||
settings = config.build_settings
|
||||
settings['APPLICATION_EXTENSION_API_ONLY'] = 'YES'
|
||||
settings['CLANG_ENABLE_MODULES'] = 'YES'
|
||||
settings['CODE_SIGN_ENTITLEMENTS'] = 'TopShelfExtension/TopShelfExtension.entitlements'
|
||||
settings['CODE_SIGN_IDENTITY'] = 'Apple Development'
|
||||
settings['CODE_SIGN_STYLE'] = 'Automatic'
|
||||
settings['CURRENT_PROJECT_VERSION'] = '$(FLUTTER_BUILD_NUMBER)'
|
||||
settings['DEVELOPMENT_TEAM'] = 'G88U5B5783'
|
||||
settings['ENABLE_BITCODE'] = 'NO'
|
||||
settings['INFOPLIST_FILE'] = 'TopShelfExtension/Info.plist'
|
||||
settings['LD_RUNPATH_SEARCH_PATHS'] = [
|
||||
'$(inherited)',
|
||||
'@executable_path/Frameworks',
|
||||
'@executable_path/../../Frameworks',
|
||||
]
|
||||
settings['MARKETING_VERSION'] = '$(FLUTTER_BUILD_NAME)'
|
||||
settings['PRODUCT_BUNDLE_IDENTIFIER'] = 'com.edde746.plezy.TopShelfExtension'
|
||||
settings['PRODUCT_NAME'] = '$(TARGET_NAME)'
|
||||
settings['SDKROOT'] = 'appletvos'
|
||||
settings['SKIP_INSTALL'] = 'YES'
|
||||
settings['SUPPORTED_PLATFORMS'] = 'appletvos appletvsimulator'
|
||||
settings['SWIFT_VERSION'] = '5.0'
|
||||
settings['TARGETED_DEVICE_FAMILY'] = '3'
|
||||
settings['TVOS_DEPLOYMENT_TARGET'] = '14.0'
|
||||
end
|
||||
|
||||
project.save
|
||||
puts 'Saved Top Shelf wiring'
|
||||
@@ -21,6 +21,12 @@ else
|
||||
fi
|
||||
|
||||
ReadPubspecVersion() {
|
||||
if [[ -n "${FLUTTER_BUILD_NAME:-}" && -n "${FLUTTER_BUILD_NUMBER:-}" ]]; then
|
||||
export FLUTTER_BUILD_NAME
|
||||
export FLUTTER_BUILD_NUMBER
|
||||
return 0
|
||||
fi
|
||||
|
||||
local app_path="${FLUTTER_APPLICATION_PATH:-}"
|
||||
if [[ -z "$app_path" ]]; then
|
||||
if [[ -n "${PROJECT_DIR:-}" ]]; then
|
||||
@@ -98,6 +104,13 @@ SyncRunnerVersion() {
|
||||
echo " └─Syncing Runner version $FLUTTER_BUILD_NAME ($FLUTTER_BUILD_NUMBER)"
|
||||
SetPlistString "$plist" CFBundleShortVersionString "$FLUTTER_BUILD_NAME"
|
||||
SetPlistString "$plist" CFBundleVersion "$FLUTTER_BUILD_NUMBER"
|
||||
|
||||
local top_shelf_plist="$TARGET_BUILD_DIR/$WRAPPER_NAME/PlugIns/TopShelfExtension.appex/Info.plist"
|
||||
if [[ -f "$top_shelf_plist" ]]; then
|
||||
echo " └─Syncing TopShelfExtension version $FLUTTER_BUILD_NAME ($FLUTTER_BUILD_NUMBER)"
|
||||
SetPlistString "$top_shelf_plist" CFBundleShortVersionString "$FLUTTER_BUILD_NAME"
|
||||
SetPlistString "$top_shelf_plist" CFBundleVersion "$FLUTTER_BUILD_NUMBER"
|
||||
fi
|
||||
}
|
||||
|
||||
EngineOutputExists() {
|
||||
|
||||
Reference in New Issue
Block a user