snapshot of https://github.com/tauri-apps/plugins-workspace.git (v2, 2026-09-23; blobs > 131072B omitted)
Some checks failed
integration tests / run-integration-tests (windows-latest) (push) Has been cancelled
Test Rust / test (push) Has been cancelled
test plugins e2e (mobile) / ios (push) Has been cancelled
test plugins e2e / test (map[name:Windows os:windows-latest]) (push) Has been cancelled
test plugins e2e / test (map[name:macOS os:macos-latest]) (push) Has been cancelled
integration tests / run-integration-tests (macos-latest) (push) Has been cancelled
version or publish / version-or-publish (push) Failing after 0s
integration tests / run-integration-tests (ubuntu-22.04) (push) Failing after 0s
Lint JavaScript / eslint (push) Failing after 0s
Sync / sync-to-mirrors (push) Failing after 0s
test plugins e2e (mobile) / android (push) Failing after 0s
test plugins e2e / test (map[name:Linux os:ubuntu-latest]) (push) Failing after 0s
Test Rust / changes (push) Failing after 0s
Lint Rust / changes (push) Failing after 0s
Lint Rust / clippy (push) Has been skipped
Audit Rust / audit-rust (push) Failing after 1s
Audit JavaScript / audit-js (push) Failing after 1s
Some checks failed
integration tests / run-integration-tests (windows-latest) (push) Has been cancelled
Test Rust / test (push) Has been cancelled
test plugins e2e (mobile) / ios (push) Has been cancelled
test plugins e2e / test (map[name:Windows os:windows-latest]) (push) Has been cancelled
test plugins e2e / test (map[name:macOS os:macos-latest]) (push) Has been cancelled
integration tests / run-integration-tests (macos-latest) (push) Has been cancelled
version or publish / version-or-publish (push) Failing after 0s
integration tests / run-integration-tests (ubuntu-22.04) (push) Failing after 0s
Lint JavaScript / eslint (push) Failing after 0s
Sync / sync-to-mirrors (push) Failing after 0s
test plugins e2e (mobile) / android (push) Failing after 0s
test plugins e2e / test (map[name:Linux os:ubuntu-latest]) (push) Failing after 0s
Test Rust / changes (push) Failing after 0s
Lint Rust / changes (push) Failing after 0s
Lint Rust / clippy (push) Has been skipped
Audit Rust / audit-rust (push) Failing after 1s
Audit JavaScript / audit-js (push) Failing after 1s
This commit is contained in:
290
plugins/notification/ios/Sources/NotificationPlugin.swift
Normal file
290
plugins/notification/ios/Sources/NotificationPlugin.swift
Normal file
@@ -0,0 +1,290 @@
|
||||
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import SwiftRs
|
||||
import Tauri
|
||||
import UIKit
|
||||
import UserNotifications
|
||||
import WebKit
|
||||
|
||||
enum ShowNotificationError: LocalizedError {
|
||||
case make(Error)
|
||||
case create(Error)
|
||||
|
||||
var errorDescription: String? {
|
||||
switch self {
|
||||
case .make(let error):
|
||||
return "Unable to make notification: \(error)"
|
||||
case .create(let error):
|
||||
return "Unable to create notification: \(error)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum ScheduleEveryKind: String, Decodable {
|
||||
case year
|
||||
case month
|
||||
case twoWeeks
|
||||
case week
|
||||
case day
|
||||
case hour
|
||||
case minute
|
||||
case second
|
||||
}
|
||||
|
||||
struct ScheduleInterval: Decodable {
|
||||
var year: Int?
|
||||
var month: Int?
|
||||
var day: Int?
|
||||
var weekday: Int?
|
||||
var hour: Int?
|
||||
var minute: Int?
|
||||
var second: Int?
|
||||
}
|
||||
|
||||
enum NotificationSchedule: Decodable {
|
||||
case at(date: String, repeating: Bool)
|
||||
case interval(interval: ScheduleInterval)
|
||||
case every(interval: ScheduleEveryKind, count: Int)
|
||||
}
|
||||
|
||||
struct NotificationAttachmentOptions: Codable {
|
||||
let iosUNNotificationAttachmentOptionsTypeHintKey: String?
|
||||
let iosUNNotificationAttachmentOptionsThumbnailHiddenKey: String?
|
||||
let iosUNNotificationAttachmentOptionsThumbnailClippingRectKey: String?
|
||||
let iosUNNotificationAttachmentOptionsThumbnailTimeKey: String?
|
||||
}
|
||||
|
||||
struct NotificationAttachment: Codable {
|
||||
let id: String
|
||||
let url: String
|
||||
let options: NotificationAttachmentOptions?
|
||||
}
|
||||
|
||||
struct Notification: Decodable {
|
||||
let id: Int
|
||||
var title: String
|
||||
var body: String?
|
||||
var extra: [String: String]?
|
||||
var schedule: NotificationSchedule?
|
||||
var attachments: [NotificationAttachment]?
|
||||
var sound: String?
|
||||
var group: String?
|
||||
var actionTypeId: String?
|
||||
var summary: String?
|
||||
var silent: Bool?
|
||||
}
|
||||
|
||||
struct RemoveActiveNotification: Decodable {
|
||||
let id: Int
|
||||
}
|
||||
|
||||
struct RemoveActiveArgs: Decodable {
|
||||
let notifications: [RemoveActiveNotification]
|
||||
}
|
||||
|
||||
func showNotification(invoke: Invoke, notification: Notification)
|
||||
throws -> UNNotificationRequest
|
||||
{
|
||||
var content: UNNotificationContent
|
||||
do {
|
||||
content = try makeNotificationContent(notification)
|
||||
} catch {
|
||||
throw ShowNotificationError.make(error)
|
||||
}
|
||||
|
||||
var trigger: UNNotificationTrigger?
|
||||
|
||||
do {
|
||||
if let schedule = notification.schedule {
|
||||
try trigger = handleScheduledNotification(schedule)
|
||||
}
|
||||
} catch {
|
||||
throw ShowNotificationError.create(error)
|
||||
}
|
||||
|
||||
// Schedule the request.
|
||||
let request = UNNotificationRequest(
|
||||
identifier: "\(notification.id)", content: content, trigger: trigger
|
||||
)
|
||||
|
||||
let center = UNUserNotificationCenter.current()
|
||||
center.add(request) { (error: Error?) in
|
||||
if let theError = error {
|
||||
invoke.reject(theError.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
return request
|
||||
}
|
||||
|
||||
struct CancelArgs: Decodable {
|
||||
// `cancelAll()` sends no list: cancel every pending notification
|
||||
let notifications: [Int]?
|
||||
}
|
||||
|
||||
struct Action: Decodable {
|
||||
let id: String
|
||||
let title: String
|
||||
var requiresAuthentication: Bool?
|
||||
var foreground: Bool?
|
||||
var destructive: Bool?
|
||||
var input: Bool?
|
||||
var inputButtonTitle: String?
|
||||
var inputPlaceholder: String?
|
||||
}
|
||||
|
||||
struct ActionType: Decodable {
|
||||
let id: String
|
||||
let actions: [Action]
|
||||
var hiddenPreviewsBodyPlaceholder: String?
|
||||
var customDismissAction: Bool?
|
||||
var allowInCarPlay: Bool?
|
||||
var hiddenPreviewsShowTitle: Bool?
|
||||
var hiddenPreviewsShowSubtitle: Bool?
|
||||
var hiddenBodyPlaceholder: String?
|
||||
}
|
||||
|
||||
struct RegisterActionTypesArgs: Decodable {
|
||||
let types: [ActionType]
|
||||
}
|
||||
|
||||
struct BatchArgs: Decodable {
|
||||
let notifications: [Notification]
|
||||
}
|
||||
|
||||
class NotificationPlugin: Plugin {
|
||||
let notificationHandler = NotificationHandler()
|
||||
let notificationManager = NotificationManager()
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
notificationManager.notificationHandler = notificationHandler
|
||||
notificationHandler.plugin = self
|
||||
}
|
||||
|
||||
@objc public func show(_ invoke: Invoke) throws {
|
||||
let notification = try invoke.parseArgs(Notification.self)
|
||||
|
||||
let request = try showNotification(invoke: invoke, notification: notification)
|
||||
notificationHandler.saveNotification(request.identifier, notification)
|
||||
invoke.resolve(Int(request.identifier) ?? -1)
|
||||
}
|
||||
|
||||
@objc public func batch(_ invoke: Invoke) throws {
|
||||
let args = try invoke.parseArgs(BatchArgs.self)
|
||||
var ids = [Int]()
|
||||
|
||||
for notification in args.notifications {
|
||||
let request = try showNotification(invoke: invoke, notification: notification)
|
||||
notificationHandler.saveNotification(request.identifier, notification)
|
||||
ids.append(Int(request.identifier) ?? -1)
|
||||
}
|
||||
|
||||
invoke.resolve(ids)
|
||||
}
|
||||
|
||||
@objc public override func requestPermissions(_ invoke: Invoke) {
|
||||
notificationHandler.requestPermissions { granted, error in
|
||||
guard error == nil else {
|
||||
invoke.reject(error!.localizedDescription)
|
||||
return
|
||||
}
|
||||
invoke.resolve(["permissionState": granted ? "granted" : "denied"])
|
||||
}
|
||||
}
|
||||
|
||||
@objc public override func checkPermissions(_ invoke: Invoke) {
|
||||
notificationHandler.checkPermissions { status in
|
||||
let permission: String
|
||||
|
||||
switch status {
|
||||
case .authorized, .ephemeral, .provisional:
|
||||
permission = "granted"
|
||||
case .denied:
|
||||
permission = "denied"
|
||||
case .notDetermined:
|
||||
permission = "prompt"
|
||||
@unknown default:
|
||||
permission = "prompt"
|
||||
}
|
||||
|
||||
invoke.resolve(["permissionState": permission])
|
||||
}
|
||||
}
|
||||
|
||||
@objc func cancel(_ invoke: Invoke) throws {
|
||||
let args = try invoke.parseArgs(CancelArgs.self)
|
||||
|
||||
if let notifications = args.notifications {
|
||||
UNUserNotificationCenter.current().removePendingNotificationRequests(
|
||||
withIdentifiers: notifications.map { String($0) }
|
||||
)
|
||||
} else {
|
||||
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
|
||||
}
|
||||
invoke.resolve()
|
||||
}
|
||||
|
||||
@objc func getPending(_ invoke: Invoke) {
|
||||
UNUserNotificationCenter.current().getPendingNotificationRequests(completionHandler: {
|
||||
(notifications) in
|
||||
let ret = notifications.compactMap({ [weak self] (notification) -> PendingNotification? in
|
||||
return self?.notificationHandler.toPendingNotification(notification)
|
||||
})
|
||||
|
||||
invoke.resolve(ret)
|
||||
})
|
||||
}
|
||||
|
||||
@objc func registerActionTypes(_ invoke: Invoke) throws {
|
||||
let args = try invoke.parseArgs(RegisterActionTypesArgs.self)
|
||||
makeCategories(args.types)
|
||||
invoke.resolve()
|
||||
}
|
||||
|
||||
@objc func removeActive(_ invoke: Invoke) {
|
||||
do {
|
||||
let args = try invoke.parseArgs(RemoveActiveArgs.self)
|
||||
UNUserNotificationCenter.current().removeDeliveredNotifications(
|
||||
withIdentifiers: args.notifications.map { String($0.id) })
|
||||
invoke.resolve()
|
||||
} catch {
|
||||
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
|
||||
DispatchQueue.main.async(execute: {
|
||||
UIApplication.shared.applicationIconBadgeNumber = 0
|
||||
})
|
||||
invoke.resolve()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func getActive(_ invoke: Invoke) {
|
||||
UNUserNotificationCenter.current().getDeliveredNotifications(completionHandler: {
|
||||
(notifications) in
|
||||
let ret = notifications.map({ (notification) -> ActiveNotification in
|
||||
return self.notificationHandler.toActiveNotification(
|
||||
notification.request)
|
||||
})
|
||||
invoke.resolve(ret)
|
||||
})
|
||||
}
|
||||
|
||||
@objc func createChannel(_ invoke: Invoke) {
|
||||
invoke.reject("not implemented")
|
||||
}
|
||||
|
||||
@objc func deleteChannel(_ invoke: Invoke) {
|
||||
invoke.reject("not implemented")
|
||||
}
|
||||
|
||||
@objc func listChannels(_ invoke: Invoke) {
|
||||
invoke.reject("not implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@_cdecl("init_plugin_notification")
|
||||
func initPlugin() -> Plugin {
|
||||
return NotificationPlugin()
|
||||
}
|
||||
Reference in New Issue
Block a user