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
42 changes: 31 additions & 11 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,39 @@
name: Build

on:
push:
branches:
- main
- development
on:
push:
branches:
- main
- development
pull_request:

jobs:
build:
name: Build
runs-on: macos-latest
name: Build (${{ matrix.platform }})
runs-on: macos-15
strategy:
fail-fast: false
matrix:
include:
- platform: macOS
destination: generic/platform=macOS
sdk: macosx
- platform: iOS
destination: generic/platform=iOS
sdk: iphoneos
steps:
- uses: actions/checkout@v4
- uses: swift-actions/setup-swift@v2
with:
swift-version: '5.9'
- name: Select Xcode
run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer
- name: Build
run: swift build
run: |
if ! xcrun --sdk '${{ matrix.sdk }}' --show-sdk-path >/dev/null 2>&1; then
echo "::notice::Skipping ${{ matrix.platform }} because its SDK is not installed on this runner."
exit 0
fi

xcodebuild \
-scheme NotificationManager \
-destination '${{ matrix.destination }}' \
CODE_SIGNING_ALLOWED=NO \
build
20 changes: 10 additions & 10 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
name: Test

on:
push:
branches:
- main
- development
on:
push:
branches:
- main
- development
pull_request:

jobs:
build:
test:
name: Test
runs-on: macos-latest
runs-on: macos-15
steps:
- uses: actions/checkout@v4
- uses: swift-actions/setup-swift@v2
with:
swift-version: '5.9'
- name: Select Xcode
run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer
- name: Run Tests
run: swift test -v
13 changes: 8 additions & 5 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,22 @@ let package = Package(
name: "NotificationManager",
platforms: [
.macOS(.v10_15),
.iOS(.v13),
.visionOS(.v1)
.iOS(.v13),
.visionOS(.v1)
],
products: [
.library(
name: "NotificationManager",
targets: ["NotificationManager"]),
targets: ["NotificationManager"]
),
],
targets: [
.target(
name: "NotificationManager"),
name: "NotificationManager"
),
.testTarget(
name: "NotificationManagerTests",
dependencies: ["NotificationManager"]),
dependencies: ["NotificationManager"]
),
]
)
249 changes: 170 additions & 79 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,120 +1,211 @@
# NotificationManager

[![License: MIT](https://img.shields.io/badge/license-MIT-blue)](https://opensource.org/license/mit)
[![Build](https://github.com/timokoethe/NotificationManager/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/timokoethe/NotificationManager/actions/workflows/build.yml)
[![Test](https://github.com/timokoethe/NotificationManager/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/timokoethe/NotificationManager/actions/workflows/test.yml)
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Ftimokoethe%2FNotificationManager%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/timokoethe/NotificationManager)
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Ftimokoethe%2FNotificationManager%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/timokoethe/NotificationManager)
[![Swift versions](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Ftimokoethe%2FNotificationManager%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/timokoethe/NotificationManager)
[![Platforms](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Ftimokoethe%2FNotificationManager%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/timokoethe/NotificationManager)

NotificationManager is a Swift Package to make your code easier for managing local notifications.
This package is supposed to make it possible to manage notifications in a highly intuitive way.
It shall also appear as minimalistic as possible.
NotificationManager is a lightweight Swift package for requesting notification authorization and managing local notifications.

## Requirements
- Xcode 15.0+

- Swift 5.9+
- macOS 10.15+
- Xcode 15.0+
- iOS 13.0+
- macOS 10.15+
- visionOS 1.0+

## Installation
1. Copy the resource url:
```

Add the package in Xcode using **File > Add Package Dependencies** and enter:

```text
https://github.com/timokoethe/NotificationManager.git
```
2. Open your Xcode project.
3. Navigate to _File_ / _Add Package Dependency_.
4. Paste the resource url at the top right corner in _Search or Enter Package URL_.
5. Choose the right target under _Add to project_.
6. To complete hit _Add Package_.

## Setup
1. Importing the Framework <br>
In any Swift file where you want to use NotificationManager, add the following import statement:
```import NotificationManager```
Add `NotificationManager` to your target and import it:

2. Request notification authorization <br>
Before your app can send notifications, you need to request permission from the user. This is typically done when the app first launches. Add the following code to your App struct or the place wherever you want to ask the user to permit:
```
import SwiftUI
import UserNotifications
```swift
import NotificationManager
```

@main
struct YourApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.onAppear {
requestNotificationAuthorization()
}
}
## Authorization

Request the standard alert, sound, and badge permissions at a point where the user understands why notifications are needed:

```swift
do {
let granted = try await NotificationManager.requestAuthorizationThrowing()

if granted {
// Notifications are authorized.
}
} catch {
// Handle the authorization error.
}
```

## Usage
- Scheduling a Notification <br>
Once you have authorization, you can schedule notifications. Here's an example of how to schedule a notification that should arrive after 10 seconds using NotificationManager by pushing a button:
To request custom options:

```swift
import UserNotifications

let granted = try await NotificationManager.requestAuthorization(
for: [.alert, .sound, .badge, .provisional]
)
```
import SwiftUI
import NotificationManager

struct ContentView: View {
var body: some View {
VStack {
Button("Schedule") {
NotificationManager.scheduleNotification(id: UUID().uuidString, title: "Title", body: "Body", triggerDate: Date()+10)
}
}
}
}
Read the current authorization status:

```swift
let status = await NotificationManager.getAuthorizationStatus()
```

- Getting pending notifications <br>
Once you have scheduled one or more notifications you can get all pending:
## Scheduling

The asynchronous APIs validate their input and propagate errors from `UNUserNotificationCenter`.

Schedule a notification after a time interval:

```swift
try await NotificationManager.scheduleNotification(
id: UUID().uuidString,
title: "Reminder",
body: "Your task is due.",
timeInterval: 10
)
```
import SwiftUI
import NotificationManager

struct ContentView: View {
@State private var notifications = [UNNotificationRequest]()
var body: some View {
VStack {
Button("Get") {
Task {
notifications = await NotificationManager.getPendingNotificationRequests()
}
}
}
}
}
Schedule a notification for a date:

```swift
let deliveryDate = Date().addingTimeInterval(60)

try await NotificationManager.scheduleNotification(
id: "task-reminder",
title: "Reminder",
body: "Your task is due.",
triggerDate: deliveryDate
)
```

- Removing all pending notifications <br>
After scheduling several notifications you can remove them easily:
Schedule a repeating notification:

```swift
try await NotificationManager.scheduleRepeatNotification(
id: "hourly-reminder",
title: "Reminder",
body: "Take a short break.",
timeInterval: 3_600
)
```
import SwiftUI
import NotificationManager

struct ContentView: View {
var body: some View {
VStack {
Button("Remove") {
NotificationManager.removeAllPendingNotificationRequests()
}
}
}
Repeating notifications require an interval of at least 60 seconds.

For compatibility, synchronous fire-and-forget overloads are also available. They print scheduling errors instead of returning them:

```swift
NotificationManager.scheduleNotification(
id: "task-reminder",
title: "Reminder",
body: "Your task is due.",
timeInterval: 10
)
```

## Error Handling

Input validation uses `NotificationManagerError`:

```swift
do {
try await NotificationManager.scheduleRepeatNotification(
id: "reminder",
title: "Reminder",
body: "This interval is too short.",
timeInterval: 30
)
} catch NotificationManagerError.repeatingTimeIntervalTooShort {
// Repeating intervals must be at least 60 seconds.
} catch {
// Handle errors from the notification center.
}
```

Available validation errors:

- `invalidTimeInterval`
- `repeatingTimeIntervalTooShort`
- `triggerDateMustBeInFuture`

## Pending Notifications

Fetch all pending requests:

```swift
import UserNotifications

let requests: [UNNotificationRequest] =
await NotificationManager.getPendingNotificationRequests()
```

Fetch only their identifiers:

```swift
let identifiers = await NotificationManager.getPendingNotificationRequestIDs()
```

Fetch delivered notifications and their identifiers:

```swift
let deliveredNotifications = await NotificationManager.getDeliveredNotifications()
let deliveredIDs = await NotificationManager.getDeliveredNotificationIDs()
```

## Replacing Notifications

Replace a pending notification while keeping its identifier:

```swift
try await NotificationManager.replaceNotificationRequestFromId(
id: "task-reminder",
newTitle: "Updated reminder",
newBody: "The task deadline has changed.",
newDate: Date().addingTimeInterval(300)
)
```

If no pending request has the supplied identifier, the method returns without making changes.

## Removing Notifications

```swift
NotificationManager.removePendingNotificationRequests(
ids: ["task-reminder", "hourly-reminder"]
)

NotificationManager.removeDeliveredNotifications(
ids: ["task-reminder"]
)

NotificationManager.removeAllPendingNotificationRequests()
NotificationManager.removeAllDeliveredNotificationRequests()
```

## Badge Count

Badge updates are available on iOS 16+, macOS 13+, and visionOS 1+:

```swift
try await NotificationManager.setBadge(badge: 3)
try await NotificationManager.resetBadge()
```

## Contributing
We welcome contributions from the community to help improve NotificationManager. If you encounter any bugs, have feature requests, or would like to contribute code, please feel free to open an issue or submit a pull request on our GitHub repository.

## Support
If you have any questions, feedback, or need assistance with NotificationManager, please don't hesitate to contact us. We're here to help!
Bug reports, feature requests, and pull requests are welcome through the GitHub repository.

## License
NotificationManager is released under the [MIT License](https://opensource.org/license/mit).

Feel free to adjust and expand upon this template to better suit your project's needs!
NotificationManager is available under the [MIT License](LICENSE).
Loading
Loading