From 8cf180a80c3a39830a53fddebe13852ee89485db Mon Sep 17 00:00:00 2001 From: zhushuanguquan Date: Mon, 19 Jun 2023 20:32:23 +0800 Subject: [PATCH] feat: Send Push Notifications using CloudKit in SwiftUI --- .../project.pbxproj | 4 + .../CloudKitPushNotificationBootcamp.swift | 89 +++++++++++++++++++ .../SwiftfulThinkingAdvancedLearningApp.swift | 3 +- 3 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 StudyNotes/Swift Collection/Swiftful Thinking/[Advanced Level] SwiftUI Advanced Learning/SwiftfulThinkingAdvancedLearning/CloudKitBootcamps/CloudKitPushNotificationBootcamp.swift diff --git a/StudyNotes/Swift Collection/Swiftful Thinking/[Advanced Level] SwiftUI Advanced Learning/SwiftfulThinkingAdvancedLearning.xcodeproj/project.pbxproj b/StudyNotes/Swift Collection/Swiftful Thinking/[Advanced Level] SwiftUI Advanced Learning/SwiftfulThinkingAdvancedLearning.xcodeproj/project.pbxproj index d29975ec1..51f32d5aa 100644 --- a/StudyNotes/Swift Collection/Swiftful Thinking/[Advanced Level] SwiftUI Advanced Learning/SwiftfulThinkingAdvancedLearning.xcodeproj/project.pbxproj +++ b/StudyNotes/Swift Collection/Swiftful Thinking/[Advanced Level] SwiftUI Advanced Learning/SwiftfulThinkingAdvancedLearning.xcodeproj/project.pbxproj @@ -31,6 +31,7 @@ 9D67DF382A1752C2004F08EB /* CustomNavView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D67DF372A1752C2004F08EB /* CustomNavView.swift */; }; 9D67DF3A2A178537004F08EB /* CustomNavLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D67DF392A178537004F08EB /* CustomNavLink.swift */; }; 9D67DF3C2A178A74004F08EB /* CustomNavBarPreferenceKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D67DF3B2A178A74004F08EB /* CustomNavBarPreferenceKeys.swift */; }; + 9D78804B2A30D6EC00ACD639 /* CloudKitPushNotificationBootcamp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D78804A2A30D6EC00ACD639 /* CloudKitPushNotificationBootcamp.swift */; }; 9D83B0E72A20F98D00E650F1 /* AdvancedCombineBootcamp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D83B0E62A20F98D00E650F1 /* AdvancedCombineBootcamp.swift */; }; 9D83B0E92A21A0DE00E650F1 /* FuturesBootcamp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D83B0E82A21A0DE00E650F1 /* FuturesBootcamp.swift */; }; 9D83B0F02A22FB2F00E650F1 /* CloudKitUserBootcamp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D83B0EF2A22FB2F00E650F1 /* CloudKitUserBootcamp.swift */; }; @@ -97,6 +98,7 @@ 9D67DF372A1752C2004F08EB /* CustomNavView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomNavView.swift; sourceTree = ""; }; 9D67DF392A178537004F08EB /* CustomNavLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomNavLink.swift; sourceTree = ""; }; 9D67DF3B2A178A74004F08EB /* CustomNavBarPreferenceKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomNavBarPreferenceKeys.swift; sourceTree = ""; }; + 9D78804A2A30D6EC00ACD639 /* CloudKitPushNotificationBootcamp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudKitPushNotificationBootcamp.swift; sourceTree = ""; }; 9D83B0E62A20F98D00E650F1 /* AdvancedCombineBootcamp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedCombineBootcamp.swift; sourceTree = ""; }; 9D83B0E82A21A0DE00E650F1 /* FuturesBootcamp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FuturesBootcamp.swift; sourceTree = ""; }; 9D83B0EF2A22FB2F00E650F1 /* CloudKitUserBootcamp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudKitUserBootcamp.swift; sourceTree = ""; }; @@ -246,6 +248,7 @@ children = ( 9D83B0EF2A22FB2F00E650F1 /* CloudKitUserBootcamp.swift */, 9D1FAF9E2A2634AA000DE9DC /* CloudKitCrudBootcamp.swift */, + 9D78804A2A30D6EC00ACD639 /* CloudKitPushNotificationBootcamp.swift */, ); path = CloudKitBootcamps; sourceTree = ""; @@ -438,6 +441,7 @@ 9DEAC40C2A1324890079DE4B /* MatchedGeometryEffectBootcamp.swift in Sources */, 9D67DF2F2A1716F6004F08EB /* TabBarItem.swift in Sources */, 9DEAC40E2A1345C40079DE4B /* CustomShapesBootcamp.swift in Sources */, + 9D78804B2A30D6EC00ACD639 /* CloudKitPushNotificationBootcamp.swift in Sources */, 9D4C70512A1D004800F23557 /* DependencyInjectionBootcamp.swift in Sources */, 9DEAC4182A1469D50079DE4B /* PreferenceKeyBootcamp.swift in Sources */, 9D83B0F02A22FB2F00E650F1 /* CloudKitUserBootcamp.swift in Sources */, diff --git a/StudyNotes/Swift Collection/Swiftful Thinking/[Advanced Level] SwiftUI Advanced Learning/SwiftfulThinkingAdvancedLearning/CloudKitBootcamps/CloudKitPushNotificationBootcamp.swift b/StudyNotes/Swift Collection/Swiftful Thinking/[Advanced Level] SwiftUI Advanced Learning/SwiftfulThinkingAdvancedLearning/CloudKitBootcamps/CloudKitPushNotificationBootcamp.swift new file mode 100644 index 000000000..3102f48a4 --- /dev/null +++ b/StudyNotes/Swift Collection/Swiftful Thinking/[Advanced Level] SwiftUI Advanced Learning/SwiftfulThinkingAdvancedLearning/CloudKitBootcamps/CloudKitPushNotificationBootcamp.swift @@ -0,0 +1,89 @@ +// +// CloudKitPushNotificationBootcamp.swift +// SwiftfulThinkingAdvancedLearning +// +// Created by 朱双泉 on 2023/6/7. +// + +import SwiftUI +import CloudKit + +class CloudKitPushNotificationBootcampViewModel: ObservableObject { + + func requestNotificationPermissions() { + let options: UNAuthorizationOptions = [.alert, .sound, .badge] + UNUserNotificationCenter.current().requestAuthorization(options: options) { success, error in + if let error = error { + print(error) + } else if success { + print("Notification permissions success!") + + DispatchQueue.main.async { + UIApplication.shared.registerForRemoteNotifications() + } + } else { + print("Notification permissions failure.") + } + } + } + + func subscribeToNotification() { + let predicate = NSPredicate(value: true) + + let subscription = CKQuerySubscription(recordType: "Fruits", predicate: predicate, subscriptionID: "fruit_added_to_database", options: .firesOnRecordCreation) + + let notification = CKSubscription.NotificationInfo() + notification.title = "There's a new fruit!" + notification.alertBody = "Open the app to check your fruits." + notification.soundName = "default" + + subscription.notificationInfo = notification + + CKContainer.default().publicCloudDatabase.save(subscription) { returnedSubscrition, returnedError in + if let error = returnedError { + print(error) + } else { + print("Successfully subscribed to notifications!") + } + } + } + + func unsubscribeToNotifications() { +// CKContainer.default().publicCloudDatabase.fetchAllSubscriptions + CKContainer.default().publicCloudDatabase.delete(withSubscriptionID: "fruits_added_to_databases") { returnedID, returnError in + if let error = returnError { + print(error) + } else { + print("Successfully unsubscribed!") + } + } + } +} + +struct CloudKitPushNotificationBootcamp: View { + + @StateObject private var vm = CloudKitPushNotificationBootcampViewModel() + + var body: some View { + VStack(spacing: 40) { + + Button("Request notification permissions") { + vm.requestNotificationPermissions() + } + + Button("Subscribe to notifications") { + vm.subscribeToNotification() + } + + Button("Unsubscribe to notifications") { + vm.unsubscribeToNotifications() + } + } + } +} + +struct CloudKitPushNotificationBootcamp_Previews: PreviewProvider { + static var previews: some View { + CloudKitPushNotificationBootcamp() + } +} diff --git a/StudyNotes/Swift Collection/Swiftful Thinking/[Advanced Level] SwiftUI Advanced Learning/SwiftfulThinkingAdvancedLearning/SwiftfulThinkingAdvancedLearningApp.swift b/StudyNotes/Swift Collection/Swiftful Thinking/[Advanced Level] SwiftUI Advanced Learning/SwiftfulThinkingAdvancedLearning/SwiftfulThinkingAdvancedLearningApp.swift index da75b3ae9..4f4f179b8 100644 --- a/StudyNotes/Swift Collection/Swiftful Thinking/[Advanced Level] SwiftUI Advanced Learning/SwiftfulThinkingAdvancedLearning/SwiftfulThinkingAdvancedLearningApp.swift +++ b/StudyNotes/Swift Collection/Swiftful Thinking/[Advanced Level] SwiftUI Advanced Learning/SwiftfulThinkingAdvancedLearning/SwiftfulThinkingAdvancedLearningApp.swift @@ -22,7 +22,8 @@ struct SwiftfulThinkingAdvancedLearningApp: App { var body: some Scene { WindowGroup { - CloudKitCrudBootcamp() +// CloudKitPushNotificationBootcamp() + CloudKitCrudBootcamp() // CloudKitUserBootcamp() // UITestingBootcampView(currentUserIsSignedIn: currentUserIsSignedIn ) }