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
connectionOptionsparameter 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
Start the conversation