diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8667b55e82..3be66416ec 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,7 +10,7 @@
##### Bug Fixes
-- None.
+- Extension classes referenced in Info.plist as NSExtensionPrincipalClass are now retained.
## 2.2.1 (2020-11-22)
diff --git a/Sources/PeripheryKit/Indexer/InfoPlistParser.swift b/Sources/PeripheryKit/Indexer/InfoPlistParser.swift
index c9e83ec0f9..195ce5281e 100644
--- a/Sources/PeripheryKit/Indexer/InfoPlistParser.swift
+++ b/Sources/PeripheryKit/Indexer/InfoPlistParser.swift
@@ -8,7 +8,7 @@ struct InfoPlistReference {
}
final class InfoPlistParser {
- private static let elements = ["UISceneClassName", "UISceneDelegateClassName"]
+ private static let elements = ["UISceneClassName", "UISceneDelegateClassName", "NSExtensionPrincipalClass"]
private let path: Path
required init(path: Path) {
diff --git a/Tests/XcodeTests/iOSProject/NotificationServiceExtension/Info.plist b/Tests/XcodeTests/iOSProject/NotificationServiceExtension/Info.plist
new file mode 100644
index 0000000000..475b077a88
--- /dev/null
+++ b/Tests/XcodeTests/iOSProject/NotificationServiceExtension/Info.plist
@@ -0,0 +1,31 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ NotificationServiceExtension
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ $(PRODUCT_BUNDLE_PACKAGE_TYPE)
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ NSExtension
+
+ NSExtensionPointIdentifier
+ com.apple.usernotifications.service
+ NSExtensionPrincipalClass
+ $(PRODUCT_MODULE_NAME).NotificationService
+
+
+
diff --git a/Tests/XcodeTests/iOSProject/NotificationServiceExtension/NotificationService.swift b/Tests/XcodeTests/iOSProject/NotificationServiceExtension/NotificationService.swift
new file mode 100644
index 0000000000..6eb5976486
--- /dev/null
+++ b/Tests/XcodeTests/iOSProject/NotificationServiceExtension/NotificationService.swift
@@ -0,0 +1,26 @@
+import UserNotifications
+
+class NotificationService: UNNotificationServiceExtension {
+ var contentHandler: ((UNNotificationContent) -> Void)?
+ var bestAttemptContent: UNMutableNotificationContent?
+
+ override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
+ self.contentHandler = contentHandler
+ bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
+
+ if let bestAttemptContent = bestAttemptContent {
+ // Modify the notification content here...
+ bestAttemptContent.title = "\(bestAttemptContent.title) [modified]"
+
+ contentHandler(bestAttemptContent)
+ }
+ }
+
+ override func serviceExtensionTimeWillExpire() {
+ // Called just before the extension will be terminated by the system.
+ // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
+ if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
+ contentHandler(bestAttemptContent)
+ }
+ }
+}
diff --git a/Tests/XcodeTests/iOSProject/iOSProject.xcodeproj/project.pbxproj b/Tests/XcodeTests/iOSProject/iOSProject.xcodeproj/project.pbxproj
index a1701a1c9d..d557c40409 100644
--- a/Tests/XcodeTests/iOSProject/iOSProject.xcodeproj/project.pbxproj
+++ b/Tests/XcodeTests/iOSProject/iOSProject.xcodeproj/project.pbxproj
@@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
+ 3C1A70B4256BBAB300E07E4A /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C1A70B3256BBAB300E07E4A /* NotificationService.swift */; };
+ 3C1A70B8256BBAB300E07E4A /* NotificationServiceExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 3C1A70B1256BBAB300E07E4A /* NotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
3C1FECF72555DD1F0001BD58 /* PreviewProviderRetainedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C1FECF62555DD1F0001BD58 /* PreviewProviderRetainedView.swift */; };
3C1FED002556D5AB0001BD58 /* iOSProjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C1FECFF2556D5AB0001BD58 /* iOSProjectTests.swift */; };
3C1FED0D2556D7C60001BD58 /* FileInGroupWithoutFolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C1FED0C2556D7C60001BD58 /* FileInGroupWithoutFolder.swift */; };
@@ -29,6 +31,13 @@
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
+ 3C1A70B6256BBAB300E07E4A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 3C849652255405AD00900DA9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 3C1A70B0256BBAB300E07E4A;
+ remoteInfo = NotificationServiceExtension;
+ };
3C1FED022556D5AB0001BD58 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 3C849652255405AD00900DA9 /* Project object */;
@@ -46,6 +55,17 @@
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
+ 3C1A70B9256BBAB300E07E4A /* Embed App Extensions */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 13;
+ files = (
+ 3C1A70B8256BBAB300E07E4A /* NotificationServiceExtension.appex in Embed App Extensions */,
+ );
+ name = "Embed App Extensions";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
3C1FED232556D91D0001BD58 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
@@ -60,6 +80,9 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 3C1A70B1256BBAB300E07E4A /* NotificationServiceExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationServiceExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
+ 3C1A70B3256BBAB300E07E4A /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; };
+ 3C1A70B5256BBAB300E07E4A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
3C1FECF62555DD1F0001BD58 /* PreviewProviderRetainedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewProviderRetainedView.swift; sourceTree = ""; };
3C1FECFD2556D5AB0001BD58 /* iOSProjectTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = iOSProjectTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3C1FECFF2556D5AB0001BD58 /* iOSProjectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSProjectTests.swift; sourceTree = ""; };
@@ -86,6 +109,13 @@
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
+ 3C1A70AE256BBAB300E07E4A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
3C1FECFA2556D5AB0001BD58 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -111,6 +141,15 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
+ 3C1A70B2256BBAB300E07E4A /* NotificationServiceExtension */ = {
+ isa = PBXGroup;
+ children = (
+ 3C1A70B3256BBAB300E07E4A /* NotificationService.swift */,
+ 3C1A70B5256BBAB300E07E4A /* Info.plist */,
+ );
+ path = NotificationServiceExtension;
+ sourceTree = "";
+ };
3C1FECFE2556D5AB0001BD58 /* iOSProjectTests */ = {
isa = PBXGroup;
children = (
@@ -143,6 +182,7 @@
3C84965C255405AD00900DA9 /* iOSProject */,
3C1FECFE2556D5AB0001BD58 /* iOSProjectTests */,
3C1FED182556D91C0001BD58 /* Target With Spaces */,
+ 3C1A70B2256BBAB300E07E4A /* NotificationServiceExtension */,
3C84965B255405AD00900DA9 /* Products */,
);
sourceTree = "";
@@ -153,6 +193,7 @@
3C84965A255405AD00900DA9 /* iOSProject.app */,
3C1FECFD2556D5AB0001BD58 /* iOSProjectTests.xctest */,
3C1FED172556D91C0001BD58 /* Target_With_Spaces.framework */,
+ 3C1A70B1256BBAB300E07E4A /* NotificationServiceExtension.appex */,
);
name = Products;
sourceTree = "";
@@ -201,6 +242,23 @@
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
+ 3C1A70B0256BBAB300E07E4A /* NotificationServiceExtension */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 3C1A70BC256BBAB300E07E4A /* Build configuration list for PBXNativeTarget "NotificationServiceExtension" */;
+ buildPhases = (
+ 3C1A70AD256BBAB300E07E4A /* Sources */,
+ 3C1A70AE256BBAB300E07E4A /* Frameworks */,
+ 3C1A70AF256BBAB300E07E4A /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = NotificationServiceExtension;
+ productName = NotificationServiceExtension;
+ productReference = 3C1A70B1256BBAB300E07E4A /* NotificationServiceExtension.appex */;
+ productType = "com.apple.product-type.app-extension";
+ };
3C1FECFC2556D5AB0001BD58 /* iOSProjectTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 3C1FED062556D5AB0001BD58 /* Build configuration list for PBXNativeTarget "iOSProjectTests" */;
@@ -245,11 +303,13 @@
3C849657255405AD00900DA9 /* Frameworks */,
3C849658255405AD00900DA9 /* Resources */,
3C1FED232556D91D0001BD58 /* Embed Frameworks */,
+ 3C1A70B9256BBAB300E07E4A /* Embed App Extensions */,
);
buildRules = (
);
dependencies = (
3C1FED1D2556D91D0001BD58 /* PBXTargetDependency */,
+ 3C1A70B7256BBAB300E07E4A /* PBXTargetDependency */,
);
name = iOSProject;
productName = iOSProject;
@@ -265,6 +325,9 @@
LastSwiftUpdateCheck = 1220;
LastUpgradeCheck = 1220;
TargetAttributes = {
+ 3C1A70B0256BBAB300E07E4A = {
+ CreatedOnToolsVersion = 12.2;
+ };
3C1FECFC2556D5AB0001BD58 = {
CreatedOnToolsVersion = 12.2;
TestTargetID = 3C849659255405AD00900DA9;
@@ -294,11 +357,19 @@
3C849659255405AD00900DA9 /* iOSProject */,
3C1FECFC2556D5AB0001BD58 /* iOSProjectTests */,
3C1FED162556D91C0001BD58 /* Target With Spaces */,
+ 3C1A70B0256BBAB300E07E4A /* NotificationServiceExtension */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
+ 3C1A70AF256BBAB300E07E4A /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
3C1FECFB2556D5AB0001BD58 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -329,6 +400,14 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
+ 3C1A70AD256BBAB300E07E4A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 3C1A70B4256BBAB300E07E4A /* NotificationService.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
3C1FECF92556D5AB0001BD58 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -364,6 +443,11 @@
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
+ 3C1A70B7256BBAB300E07E4A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 3C1A70B0256BBAB300E07E4A /* NotificationServiceExtension */;
+ targetProxy = 3C1A70B6256BBAB300E07E4A /* PBXContainerItemProxy */;
+ };
3C1FED032556D5AB0001BD58 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 3C849659255405AD00900DA9 /* iOSProject */;
@@ -377,6 +461,48 @@
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
+ 3C1A70BA256BBAB300E07E4A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Manual;
+ DEVELOPMENT_TEAM = "";
+ INFOPLIST_FILE = NotificationServiceExtension/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 14.2;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.github.peripheryapp.iOSProject.NotificationServiceExtension;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SKIP_INSTALL = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 3C1A70BB256BBAB300E07E4A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Manual;
+ DEVELOPMENT_TEAM = "";
+ INFOPLIST_FILE = NotificationServiceExtension/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 14.2;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@executable_path/../../Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.github.peripheryapp.iOSProject.NotificationServiceExtension;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SKIP_INSTALL = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
3C1FED042556D5AB0001BD58 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -645,6 +771,15 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
+ 3C1A70BC256BBAB300E07E4A /* Build configuration list for PBXNativeTarget "NotificationServiceExtension" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 3C1A70BA256BBAB300E07E4A /* Debug */,
+ 3C1A70BB256BBAB300E07E4A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
3C1FED062556D5AB0001BD58 /* Build configuration list for PBXNativeTarget "iOSProjectTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
diff --git a/Tests/XcodeTests/iOSProjectTest.swift b/Tests/XcodeTests/iOSProjectTest.swift
index 810fa02c2a..a4cf108413 100644
--- a/Tests/XcodeTests/iOSProjectTest.swift
+++ b/Tests/XcodeTests/iOSProjectTest.swift
@@ -52,6 +52,10 @@ class iOSProjectTest: SourceGraphTestCase {
XCTAssertReferenced((.class, "SceneDelegate"))
}
+ func testRetainsExtensionPrincipalClassReferencedInInfoPlist() {
+ XCTAssertReferenced((.class, "NotificationService"))
+ }
+
func testRetainsXibReferencedClass() {
XCTAssertReferenced((.class, "XibViewController"))
XCTAssertReferenced((.varInstance, "button"), descendentOf: (.class, "XibViewController"))