Composable User Notifications is library that bridges the Composable Architecture and User Notifications.
This library is modelling it's dependency using swift concurrency since version 0.3.0.
Check out the Example demo to see how ComposableUserNotifications can be used.
To handle incoming user notification you can observe the UNUserNotificationCenterDelegate
actions through UserNotificationClient.DelegateAction
of the UserNotificationClient.delegate
.
import ComposableUserNotifications
struct App: ReducerProtocol {
enum Action {
case userNotification(UserNotificationClient.DelegateAction)
// Your domain's other actions:
...
The UserNotificationClient.DelegateAction
holds the actions
willPresentNotification(_:completion)
didReceiveResponse(_:completionHandler:)
openSettingsForNotification(_:)
The wrapper around apple's UNUserNotificationCenter
UserNotificationClient
, is available on the DependencyValues
and can be retrieved on using @Dependency(\.userNotifications)
.
At some point you need to subscribe to UserNotificationClient.DelegateAction
in order not to miss any UNUserNotificationCenterDelegate
related actions. This can be done early after starting the application.
func reduce(into state: inout State, action: Action) -> EffectTask<Action> {
switch action {
case let .didFinishLaunching(notification):
...
return .run { send in
for await event in self.userNotifications.delegate() {
await send(.userNotifications(event))
}
}
}
}
}
When subscribing to these actions we can handle them as follows.
...
case let .userNotification(.willPresentNotification(notification, completion)):
return .fireAndForget {
completion([.list, .banner, .sound])
}
case let .userNotification(.didReceiveResponse(response, completion)):
return .fireAndForget {
completion()
}
case .userNotification(.openSettingsForNotification):
return .none
...
To request authorization from the user you can use requestAuthorization
and handle the users choice as a new action.
func reduce(into state: inout State, action: Action) -> EffectTask<Action> {
switch action {
case .didFinishLaunching:
return .task {
.requestAuthorizationResponse(
TaskResult {
try await self.userNotifications.requestAuthorization([.alert, .badge, .sound])
}
)
}
}
...
}
Adding notification requests is also straight forward. It can be done using UNNotificationRequest
in conjunction with UserNotificationClient.add(_:)
.
case .tappedScheduleButton:
let content = UNMutableNotificationContent()
content.title = "Example title"
content.body = "Example body"
let request = UNNotificationRequest(
identifier: "example_notification",
content: content,
trigger: UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
)
return .task {
await self.userNotifications
.removePendingNotificationRequestsWithIdentifiers(["example_notification"])
return await .addNotificationResponse(
TaskResult {
Unit(try await self.userNotifications.add(request))
}
)
}
...
All API calls to UNUserNotificationCenter
are available through UserNotificationClient
.
The true power of this approach lies in the testability of your notification logic.
For more info around testability have a look at ExampleTests.swift.
You can add ComposableUserNotifications to an Xcode project by adding it as a package dependency.
This library is released under the MIT license. See LICENSE for details.
link |
Stars: 16 |
Last commit: 12 weeks ago |
Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics