Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions packages/apple-targets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,11 @@ Ideally, this would be generated automatically based on a fully qualified Xcode
| classkit-context | ClassKit Context Provider Extension|
| unwanted-communication | Unwanted Communication Reporting |
| photo-editing | Photo Editing Extension |
| quicklook-preview | Quick Look Preview Extension |
| spotlight-delegate | CoreSpotlight Delegate Extension |
| virtual-conference | Virtual Conference Provider |
| shield-action | Shield Action Extension |
| shield-config | Shield Configuration Extension |


<!-- | imessage | iMessage Extension | -->
Expand All @@ -329,13 +334,8 @@ The following iOS extension types exist in Xcode but aren't supported yet. Contr
| Extension Point Identifier | Xcode Template Name |
| --- | --- |
| `com.apple.printing.discovery` | Print Service Extension |
| `com.apple.quicklook.preview` | Quick Look Preview Extension |
| `com.apple.spotlight.index` | CoreSpotlight Delegate Extension |
| `com.apple.ctk-tokens` | Smart Card / Persistent Token Extension |
| `com.apple.calendar.virtualconference` | Virtual Conference Provider Extension |
| `com.apple.AppSSO.idp-extension` | Authentication Services Extension |
| `com.apple.ManagedSettings.shield-action-service` | Shield Action Extension |
| `com.apple.ManagedSettingsUI.shield-configuration-service` | Shield Configuration Extension |
| `com.apple.tv-top-shelf` | TV Top Shelf Extension (tvOS) |
| `com.apple.FinderSync` | Finder Sync Extension (macOS) |
| `com.apple.email.extension` | Mail Extension (macOS) |
Expand Down
17 changes: 17 additions & 0 deletions packages/apple-targets/e2e/__tests__/build.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,23 @@ const TARGET_REGISTRY: TargetEntry[] = [
target: "unwantedcommunication",
},
{ type: "photo-editing", dir: "photo-editing", target: "photoediting" },
{
type: "quicklook-preview",
dir: "quicklook-preview",
target: "quicklookpreview",
},
{
type: "spotlight-delegate",
dir: "spotlight-delegate",
target: "spotlightdelegate",
},
{
type: "virtual-conference",
dir: "virtual-conference",
target: "virtualconference",
},
{ type: "shield-action", dir: "shield-action", target: "shieldaction" },
{ type: "shield-config", dir: "shield-config", target: "shieldconfig" },
];

// Derived from the central TARGET_REGISTRY — no need to maintain by hand.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "quicklook-preview" }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "shield-action" }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "shield-config" }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "spotlight-delegate" }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "virtual-conference" }
5 changes: 5 additions & 0 deletions packages/apple-targets/src/configuration-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,11 @@ function getConfigurationListBuildSettingsForType(
case "classkit-context":
case "unwanted-communication":
case "photo-editing":
case "quicklook-preview":
case "spotlight-delegate":
case "virtual-conference":
case "shield-action":
case "shield-config":
return createNotificationContentConfigurationList(props);
default:
const exhaustiveCheck: never = props.type;
Expand Down
69 changes: 69 additions & 0 deletions packages/apple-targets/src/target.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,32 @@ export const TARGET_REGISTRY = {
frameworks: ["Photos", "PhotosUI"],
displayName: "Photo Editing",
},
"quicklook-preview": {
extensionPointIdentifier: "com.apple.quicklook.preview",
needsEmbeddedSwift: true,
frameworks: ["QuickLook"],
displayName: "Quick Look Preview",
},
"spotlight-delegate": {
extensionPointIdentifier: "com.apple.spotlight.index",
frameworks: ["CoreSpotlight"],
displayName: "CoreSpotlight Delegate",
},
"virtual-conference": {
extensionPointIdentifier: "com.apple.calendar.virtualconference",
displayName: "Virtual Conference Provider",
},
"shield-action": {
extensionPointIdentifier: "com.apple.ManagedSettings.shield-action-service",
frameworks: ["ManagedSettings"],
displayName: "Shield Action",
},
"shield-config": {
extensionPointIdentifier:
"com.apple.ManagedSettingsUI.shield-configuration-service",
frameworks: ["ManagedSettings", "ManagedSettingsUI"],
displayName: "Shield Configuration",
},
} as const satisfies Record<string, TargetDefinition>;

export type ExtensionType = keyof typeof TARGET_REGISTRY;
Expand Down Expand Up @@ -596,6 +622,49 @@ export function getTargetInfoPlistForType(type: ExtensionType) {
},
},
};
case "quicklook-preview":
return {
NSExtension: {
NSExtensionAttributes: {
QLSupportedContentTypes: [],
},
NSExtensionPrincipalClass:
"$(PRODUCT_MODULE_NAME).PreviewViewController",
NSExtensionPointIdentifier,
},
};
case "spotlight-delegate":
return {
NSExtension: {
NSExtensionPointIdentifier,
NSExtensionPrincipalClass:
"$(PRODUCT_MODULE_NAME).IndexRequestHandler",
},
};
case "virtual-conference":
return {
NSExtension: {
NSExtensionPointIdentifier,
NSExtensionPrincipalClass:
"$(PRODUCT_MODULE_NAME).VirtualConferenceProvider",
},
};
case "shield-action":
return {
NSExtension: {
NSExtensionPointIdentifier,
NSExtensionPrincipalClass:
"$(PRODUCT_MODULE_NAME).ShieldActionExtension",
},
};
case "shield-config":
return {
NSExtension: {
NSExtensionPointIdentifier,
NSExtensionPrincipalClass:
"$(PRODUCT_MODULE_NAME).ShieldConfigurationExtension",
},
};
default:
// Default: used for widget and bg-download
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,14 @@ module.exports = config => ({
});"
`;

exports[`getTemplateConfig should return a valid template for quicklook-preview 1`] = `
"/** @type {import('@bacons/apple-targets/app.plugin').ConfigFunction} */
module.exports = config => ({
type: \\"quicklook-preview\\",
entitlements: { /* Add entitlements */ },
});"
`;

exports[`getTemplateConfig should return a valid template for quicklook-thumbnail 1`] = `
"/** @type {import('@bacons/apple-targets/app.plugin').ConfigFunction} */
module.exports = config => ({
Expand Down Expand Up @@ -190,6 +198,22 @@ module.exports = config => ({
});"
`;

exports[`getTemplateConfig should return a valid template for shield-action 1`] = `
"/** @type {import('@bacons/apple-targets/app.plugin').ConfigFunction} */
module.exports = config => ({
type: \\"shield-action\\",
entitlements: {\\"com.apple.developer.family-controls\\":true},
});"
`;

exports[`getTemplateConfig should return a valid template for shield-config 1`] = `
"/** @type {import('@bacons/apple-targets/app.plugin').ConfigFunction} */
module.exports = config => ({
type: \\"shield-config\\",
entitlements: {\\"com.apple.developer.family-controls\\":true},
});"
`;

exports[`getTemplateConfig should return a valid template for spotlight 1`] = `
"/** @type {import('@bacons/apple-targets/app.plugin').ConfigFunction} */
module.exports = config => ({
Expand All @@ -198,6 +222,14 @@ module.exports = config => ({
});"
`;

exports[`getTemplateConfig should return a valid template for spotlight-delegate 1`] = `
"/** @type {import('@bacons/apple-targets/app.plugin').ConfigFunction} */
module.exports = config => ({
type: \\"spotlight-delegate\\",
entitlements: { /* Add entitlements */ },
});"
`;

exports[`getTemplateConfig should return a valid template for unwanted-communication 1`] = `
"/** @type {import('@bacons/apple-targets/app.plugin').ConfigFunction} */
module.exports = config => ({
Expand All @@ -206,6 +238,14 @@ module.exports = config => ({
});"
`;

exports[`getTemplateConfig should return a valid template for virtual-conference 1`] = `
"/** @type {import('@bacons/apple-targets/app.plugin').ConfigFunction} */
module.exports = config => ({
type: \\"virtual-conference\\",
entitlements: { /* Add entitlements */ },
});"
`;

exports[`getTemplateConfig should return a valid template for watch 1`] = `
"/** @type {import('@bacons/apple-targets/app.plugin').ConfigFunction} */
module.exports = config => ({
Expand Down
5 changes: 5 additions & 0 deletions packages/create-target/src/__tests__/createAsync.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ const ALL_TARGET_TYPES = [
"classkit-context",
"unwanted-communication",
"photo-editing",
"quicklook-preview",
"spotlight-delegate",
"virtual-conference",
"shield-action",
"shield-config",
];

describe(getTemplateConfig, () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import UIKit
import QuickLook

class PreviewViewController: UIViewController, QLPreviewingController {

override func viewDidLoad() {
super.viewDidLoad()
}

func preparePreviewOfFile(at url: URL, completionHandler handler: @escaping (Error?) -> Void) {
// Add the supported content types to the QLSupportedContentTypes array in the Info.plist.
handler(nil)
}

func preparePreviewOfSearchableItem(identifier: String, queryString: String?, completionHandler handler: @escaping (Error?) -> Void) {
// Perform any setup necessary in order to prepare the view.
handler(nil)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import ManagedSettings

class ShieldActionExtension: ShieldActionDelegate {

override func handle(action: ShieldAction, for application: ApplicationToken, completionHandler: @escaping (ShieldActionResponse) -> Void) {
switch action {
case .primaryButtonPressed:
completionHandler(.close)
case .secondaryButtonPressed:
completionHandler(.defer)
@unknown default:
fatalError()
}
}

override func handle(action: ShieldAction, for webDomain: WebDomainToken, completionHandler: @escaping (ShieldActionResponse) -> Void) {
switch action {
case .primaryButtonPressed:
completionHandler(.close)
case .secondaryButtonPressed:
completionHandler(.defer)
@unknown default:
fatalError()
}
}

override func handle(action: ShieldAction, for category: ActivityCategoryToken, completionHandler: @escaping (ShieldActionResponse) -> Void) {
switch action {
case .primaryButtonPressed:
completionHandler(.close)
case .secondaryButtonPressed:
completionHandler(.defer)
@unknown default:
fatalError()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import ManagedSettings
import ManagedSettingsUI
import UIKit

class ShieldConfigurationExtension: ShieldConfigurationDataSource {

override func configuration(shielding application: Application) -> ShieldConfiguration {
return ShieldConfiguration()
}

override func configuration(shielding application: Application, in category: ActivityCategory) -> ShieldConfiguration {
return ShieldConfiguration()
}

override func configuration(shielding webDomain: WebDomain) -> ShieldConfiguration {
return ShieldConfiguration()
}

override func configuration(shielding webDomain: WebDomain, in category: ActivityCategory) -> ShieldConfiguration {
return ShieldConfiguration()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import CoreSpotlight

class IndexRequestHandler: CSIndexExtensionRequestHandler {

override func searchableIndex(_ searchableIndex: CSSearchableIndex, reindexAllSearchableItemsWithAcknowledgementHandler acknowledgementHandler: @escaping () -> Void) {
// Reindex all data with the provided index
acknowledgementHandler()
}

override func searchableIndex(_ searchableIndex: CSSearchableIndex, reindexSearchableItemsWithIdentifiers identifiers: [String], acknowledgementHandler: @escaping () -> Void) {
// Reindex any items with the given identifiers and the provided index
acknowledgementHandler()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import EventKit

class VirtualConferenceProvider: EKVirtualConferenceProvider {

override func fetchVirtualConference(identifier: String, completionHandler: @escaping (EKVirtualConferenceDescriptor?, Error?) -> Void) {
// Create and return a virtual conference descriptor
let urlDescriptor = EKVirtualConferenceURLDescriptor(
title: "Join Meeting",
url: URL(string: "https://example.com/meeting")!
)
let descriptor = EKVirtualConferenceDescriptor(
title: "Example Meeting",
urlDescriptors: [urlDescriptor],
conferenceDetails: nil
)
completionHandler(descriptor, nil)
}
}