Issue #774
Start by defining your quick actions. You can use UIApplicationShortcutIcon(type:)
for predefined icons, or use UIApplicationShortcutIcon(systemImageName:)
for SFSymbol
enum QuickAction: String {
case readPasteboard
case clear
var shortcutItem: UIApplicationShortcutItem {
switch self {
case .readPasteboard:
return UIApplicationShortcutItem(
type: rawValue,
localizedTitle: "Read Pasteboard",
localizedSubtitle: "",
icon: UIApplicationShortcutIcon(type: .add),
userInfo: nil
)
case .clear:
return UIApplicationShortcutItem(
type: rawValue,
localizedTitle: "Clear Pasteboard",
localizedSubtitle: "",
icon: UIApplicationShortcutIcon(systemImageName: SFSymbol.wind.rawValue),
userInfo: nil
)
}
}
}
Add a service to store selected quick action. I usually make this conform to ObservableObject
to be able to bind to SwiftUI views later
final class QuickActionService: ObservableObject {
var shortcutItem: UIApplicationShortcutItem?
Expose AppDelegate and SceneDelegate to your SwiftUI App
. Listen to scenePhase
to add dynamic items
From Define Dynamic Quick Actions
Set dynamic screen quick actions at any point, but the sample sets them in the sceneWillResignActive(_:) function of the scene delegate. During the transition to a background state is a good time to update any dynamic quick actions, because the system executes this code before the user returns to the Home Screen.
@main
struct PastePaliOSApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self)
var appDelegate
@Environment(\.scenePhase)
var scenePhase
var body: some Scene {
WindowGroup {
main
}
.onChange(of: scenePhase) { scenePhase in
switch scenePhase {
case .background:
addDynamicQuickActions()
case .active:
QuickActionService.shared.perform()
default:
break
}
}
}
private func addDynamicQuickActions() {
UIApplication.shared.shortcutItems = [
QuickAction.readPasteboard.shortcutItem,
QuickAction.clear.shortcutItem
]
}
}
Quick actions are notified in 2 cases
- If the app isn’t already loaded, it’s launched and passes details of the shortcut item in through the
connectionOptions
parameter of thescene(_:willConnectTo:options:)
function in AppDelegate - If your app is already loaded, the system calls the
windowScene(_:performActionFor:completionHandler:)
function of your SceneDelegate
Therefore we need to handle both cases.
final class AppDelegate: NSObject, UIApplicationDelegate {
func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
if let shortcutItem = options.shortcutItem {
QuickActionService.shared.shortcutItem = shortcutItem
}
let sceneConfiguration = UISceneConfiguration(
name: "Default",
sessionRole: connectingSceneSession.role
)
sceneConfiguration.delegateClass = SceneDelegate.self
return sceneConfiguration
}
}
private final class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func windowScene(
_ windowScene: UIWindowScene,
performActionFor shortcutItem: UIApplicationShortcutItem,
completionHandler: @escaping (Bool) -> Void
) {
QuickActionService.shared.shortcutItem = shortcutItem
completionHandler(true)
}
Read more
For more please consult official Apple docs and design