diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9bea433 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +.DS_Store diff --git a/FlurSchnaps.xcodeproj/project.pbxproj b/FlurSchnaps.xcodeproj/project.pbxproj index faadb44..69498bc 100644 --- a/FlurSchnaps.xcodeproj/project.pbxproj +++ b/FlurSchnaps.xcodeproj/project.pbxproj @@ -8,11 +8,11 @@ /* Begin PBXBuildFile section */ 881E0B26284B74E200435EC2 /* Data+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 881E0B25284B74E200435EC2 /* Data+Extensions.swift */; }; - 88DBE72A284B989C00D1573B /* DeviceList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88DBE729284B989C00D1573B /* DeviceList.swift */; }; + 88F92BA928C67EEB0078BEC4 /* TokenUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88F92BA828C67EEB0078BEC4 /* TokenUpload.swift */; }; + 88F92BAC28C67F8B0078BEC4 /* BinaryCodable in Frameworks */ = {isa = PBXBuildFile; productRef = 88F92BAB28C67F8B0078BEC4 /* BinaryCodable */; }; E234995C284E1D02002B55F8 /* SFSafeSymbols in Frameworks */ = {isa = PBXBuildFile; productRef = E234995B284E1D02002B55F8 /* SFSafeSymbols */; }; E234995F284E372B002B55F8 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E2349961284E372B002B55F8 /* Localizable.strings */; }; E2349964284F3133002B55F8 /* TextEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2349963284F3133002B55F8 /* TextEntryField.swift */; }; - E2349968284F78E3002B55F8 /* Push in Frameworks */ = {isa = PBXBuildFile; productRef = E2349967284F78E3002B55F8 /* Push */; }; E29A7E47284B6143000B908A /* FlurSchnapsApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = E29A7E46284B6143000B908A /* FlurSchnapsApp.swift */; }; E29A7E49284B6143000B908A /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E29A7E48284B6143000B908A /* ContentView.swift */; }; E29A7E4B284B6144000B908A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E29A7E4A284B6144000B908A /* Assets.xcassets */; }; @@ -23,7 +23,7 @@ 881E0B25284B74E200435EC2 /* Data+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Extensions.swift"; sourceTree = ""; }; 88DBE727284B7EB200D1573B /* FlurSchnaps.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = FlurSchnaps.entitlements; sourceTree = ""; }; 88DBE728284B813500D1573B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; - 88DBE729284B989C00D1573B /* DeviceList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceList.swift; sourceTree = ""; }; + 88F92BA828C67EEB0078BEC4 /* TokenUpload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenUpload.swift; sourceTree = ""; }; E2349960284E372B002B55F8 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; E2349962284E3733002B55F8 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; E2349963284F3133002B55F8 /* TextEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = ""; }; @@ -39,7 +39,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - E2349968284F78E3002B55F8 /* Push in Frameworks */, + 88F92BAC28C67F8B0078BEC4 /* BinaryCodable in Frameworks */, E234995C284E1D02002B55F8 /* SFSafeSymbols in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -72,10 +72,10 @@ E29A7E46284B6143000B908A /* FlurSchnapsApp.swift */, E29A7E48284B6143000B908A /* ContentView.swift */, E2349963284F3133002B55F8 /* TextEntryField.swift */, - 88DBE729284B989C00D1573B /* DeviceList.swift */, 881E0B25284B74E200435EC2 /* Data+Extensions.swift */, E29A7E4A284B6144000B908A /* Assets.xcassets */, E29A7E4C284B6144000B908A /* Preview Content */, + 88F92BA828C67EEB0078BEC4 /* TokenUpload.swift */, ); path = FlurSchnaps; sourceTree = ""; @@ -106,7 +106,7 @@ name = FlurSchnaps; packageProductDependencies = ( E234995B284E1D02002B55F8 /* SFSafeSymbols */, - E2349967284F78E3002B55F8 /* Push */, + 88F92BAB28C67F8B0078BEC4 /* BinaryCodable */, ); productName = FlurSchnaps; productReference = E29A7E43284B6143000B908A /* FlurSchnaps.app */; @@ -139,7 +139,7 @@ mainGroup = E29A7E3A284B6143000B908A; packageReferences = ( E234995A284E1D02002B55F8 /* XCRemoteSwiftPackageReference "SFSafeSymbols" */, - E2349966284F78E3002B55F8 /* XCRemoteSwiftPackageReference "Push-iOS" */, + 88F92BAA28C67F8B0078BEC4 /* XCRemoteSwiftPackageReference "BinaryCodable" */, ); productRefGroup = E29A7E44284B6143000B908A /* Products */; projectDirPath = ""; @@ -171,8 +171,8 @@ E2349964284F3133002B55F8 /* TextEntryField.swift in Sources */, E29A7E49284B6143000B908A /* ContentView.swift in Sources */, 881E0B26284B74E200435EC2 /* Data+Extensions.swift in Sources */, - 88DBE72A284B989C00D1573B /* DeviceList.swift in Sources */, E29A7E47284B6143000B908A /* FlurSchnapsApp.swift in Sources */, + 88F92BA928C67EEB0078BEC4 /* TokenUpload.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -395,6 +395,14 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ + 88F92BAA28C67F8B0078BEC4 /* XCRemoteSwiftPackageReference "BinaryCodable" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/christophhagen/BinaryCodable"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; E234995A284E1D02002B55F8 /* XCRemoteSwiftPackageReference "SFSafeSymbols" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/SFSafeSymbols/SFSafeSymbols"; @@ -403,27 +411,19 @@ minimumVersion = 3.0.0; }; }; - E2349966284F78E3002B55F8 /* XCRemoteSwiftPackageReference "Push-iOS" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://christophhagen.de/git/ch/Push-iOS"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 0.2.0; - }; - }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 88F92BAB28C67F8B0078BEC4 /* BinaryCodable */ = { + isa = XCSwiftPackageProductDependency; + package = 88F92BAA28C67F8B0078BEC4 /* XCRemoteSwiftPackageReference "BinaryCodable" */; + productName = BinaryCodable; + }; E234995B284E1D02002B55F8 /* SFSafeSymbols */ = { isa = XCSwiftPackageProductDependency; package = E234995A284E1D02002B55F8 /* XCRemoteSwiftPackageReference "SFSafeSymbols" */; productName = SFSafeSymbols; }; - E2349967284F78E3002B55F8 /* Push */ = { - isa = XCSwiftPackageProductDependency; - package = E2349966284F78E3002B55F8 /* XCRemoteSwiftPackageReference "Push-iOS" */; - productName = Push; - }; /* End XCSwiftPackageProductDependency section */ }; rootObject = E29A7E3B284B6143000B908A /* Project object */; diff --git a/FlurSchnaps.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/FlurSchnaps.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 4ef0330..2d85b9f 100644 --- a/FlurSchnaps.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/FlurSchnaps.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,39 +1,12 @@ { "pins" : [ { - "identity" : "apnswift", + "identity" : "binarycodable", "kind" : "remoteSourceControl", - "location" : "https://github.com/swift-server-community/APNSwift.git", + "location" : "https://github.com/christophhagen/BinaryCodable", "state" : { - "revision" : "99a3c7bb5fd211009438fb386d18c94bb2f63b17", - "version" : "4.0.0" - } - }, - { - "identity" : "jwt-kit", - "kind" : "remoteSourceControl", - "location" : "https://github.com/vapor/jwt-kit.git", - "state" : { - "revision" : "3537dd319dfbcc403a5165d8c19c4834e8e64730", - "version" : "4.5.0" - } - }, - { - "identity" : "push-definitions", - "kind" : "remoteSourceControl", - "location" : "https://christophhagen.de/git/ch/Push-Definitions.git", - "state" : { - "revision" : "3a4e93889b0cb5f500eeccd7ba2a099d0f3862f0", - "version" : "1.0.1" - } - }, - { - "identity" : "push-ios", - "kind" : "remoteSourceControl", - "location" : "https://christophhagen.de/git/ch/Push-iOS", - "state" : { - "revision" : "1131cb17c6114a0b41263be1b5788188548adc41", - "version" : "0.3.0" + "revision" : "2049887d460c0101e69922271a54a567dbf31e2c", + "version" : "1.2.2" } }, { @@ -44,51 +17,6 @@ "revision" : "c8c33d947d8a1c883aa19fd24e14fd738b06e369", "version" : "3.3.2" } - }, - { - "identity" : "swift-crypto", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-crypto.git", - "state" : { - "revision" : "d9825fa541df64b1a7b182178d61b9a82730d01f", - "version" : "2.1.0" - } - }, - { - "identity" : "swift-log", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-log.git", - "state" : { - "revision" : "5d66f7ba25daf4f94100e7022febf3c75e37a6c7", - "version" : "1.4.2" - } - }, - { - "identity" : "swift-nio", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio.git", - "state" : { - "revision" : "124119f0bb12384cef35aa041d7c3a686108722d", - "version" : "2.40.0" - } - }, - { - "identity" : "swift-nio-http2", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio-http2.git", - "state" : { - "revision" : "72bcaf607b40d7c51044f65b0f5ed8581a911832", - "version" : "1.21.0" - } - }, - { - "identity" : "swift-nio-ssl", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio-ssl.git", - "state" : { - "revision" : "1750873bce84b4129b5303655cce2c3d35b9ed3a", - "version" : "2.19.0" - } } ], "version" : 2 diff --git a/FlurSchnaps.xcodeproj/project.xcworkspace/xcuserdata/imac.xcuserdatad/UserInterfaceState.xcuserstate b/FlurSchnaps.xcodeproj/project.xcworkspace/xcuserdata/imac.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..094c37b Binary files /dev/null and b/FlurSchnaps.xcodeproj/project.xcworkspace/xcuserdata/imac.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/FlurSchnaps/ContentView.swift b/FlurSchnaps/ContentView.swift index f537e77..85d3ff8 100644 --- a/FlurSchnaps/ContentView.swift +++ b/FlurSchnaps/ContentView.swift @@ -1,61 +1,18 @@ import SwiftUI -import APNSwift -import Push -import PushMessageDefinitions import SFSafeSymbols +import UniformTypeIdentifiers struct ContentView: View { @AppStorage("pushToken") - var pushToken: PushToken? + var pushToken: String? var hasPushToken: Bool { pushToken != nil } - - @AppStorage("authToken") - var authToken: AuthenticationToken? - - @State - var isConfirmed = false @State var hasNotificationPermissions: Bool? = nil - - @State - var showDeviceList = false - - @State - var api: PushClient? - - @AppStorage("server") - var server: String = "" - - @AppStorage("application") - var application = "" - - @AppStorage("deviceName") - var deviceName: String = "" - - @State - var deviceList: [DeviceRegistration] = [] - - var couldBeRegistered: Bool { - pushToken != nil && authToken != nil - } - - @AppStorage("pushTitle") - var pushMessageTitle: String = "" - - @AppStorage("pushBody") - var pushMessageText: String = "" - - @State - var includeOwnDeviceInPush = false - - var canSendNotification: Bool { - isConfirmed && (includeOwnDeviceInPush || deviceList.count > 1) - } func statusView(_ state: Bool?) -> some View { let symbol: SFSymbol @@ -95,6 +52,16 @@ struct ContentView: View { } } + @State + private var didTapText = false + + var tapFootnote: String { + if didTapText { + return "Copied to clipboard" + } + return "Double tap to copy token" + } + var body: some View { NavigationView { VStack(spacing: 8) { @@ -106,21 +73,23 @@ struct ContentView: View { statusView(hasNotificationPermissions) Text("notification-permissions-title") } - HStack { - statusView(authToken != nil) - Text("push-server-registration-title") - } - HStack { - statusView(deviceList.count > 1) - Text("other-devices-title") - } - if pushToken == nil { + Spacer() + if let token = pushToken { + Text("push-token-title") + Text(token) + .font(.body.monospaced()) + .padding() + .onTapGesture(count: 2, perform: didDoubleTapToken) + Text(tapFootnote) + .font(.footnote) + } else { Text("register-for-remote-notifications-text") .padding() .multilineTextAlignment(.center) Button("register-for-remote-notifications-button", action: registerForRemoteNotifications) .padding() - } else if hasNotificationPermissions == nil { + } + if hasNotificationPermissions == nil { Button("request-notification-permission-button", action: requestNotificationPermission) .padding() } else if hasNotificationPermissions == false { @@ -129,70 +98,26 @@ struct ContentView: View { .multilineTextAlignment(.center) Button("no-notification-permissions-button", action: openNotificationSettings) .padding() - } else if authToken == nil { - Text("register-device-text") - .padding() - TextEntryField("Server url", placeholder: "register-device-server-placeholder", symbol: .network, showClearButton: true, text: $server) - .padding(.horizontal, 50) - .padding(.top) - TextEntryField("Application", placeholder: "register-device-application-placeholder", symbol: .questionmarkApp, showClearButton: true, text: $application) - .padding(.horizontal, 50) - .padding(.top) - TextEntryField("Device name", placeholder: "register-device-name-placeholder", symbol: .iphone, text: $deviceName) - .padding(.horizontal, 50) - .padding(.top) - Button("register-device-button", action: register) - .disabled(pushToken == nil || authToken != nil || deviceName.isEmpty) - .padding() - } else { - Text("push-message-description") - .padding() - TextEntryField("Push title", placeholder: "push-message-title-placeholder", symbol: .bubbleLeft, showClearButton: true, text: $pushMessageTitle) - .padding(.horizontal, 50) - .disabled(!isConfirmed) - TextEntryField("Push text", placeholder: "push-message-placeholder", symbol: .textformat, showClearButton: true, text: $pushMessageText) - .padding(.horizontal, 50) - .disabled(!isConfirmed) - Toggle("toggle-include-own-device-text", isOn: $includeOwnDeviceInPush) - .padding(.horizontal, 50) - .padding(.top) - Button("send-notification-button", action: sendPush) - .disabled(!canSendNotification) - .padding() - Button("show-device-list-button", action: showDevices) - .disabled(!isConfirmed) - .padding() } Spacer() } .navigationTitle("FlurSchnaps") } - .sheet(isPresented: $showDeviceList) { - if let push = pushToken, let auth = authToken, let api = api { - DeviceList(pushToken: push, - authToken: auth, - api: api, - isPresented: $showDeviceList, - devices: deviceList) - } - }.onAppear { + .onAppear { startPeriodicUpdates() - if server == "" { - server = "https://christophhagen.de/push" - } - if application == "" { - application = "FlurSchnaps" - } - if pushMessageTitle == "" { - pushMessageTitle = "Flur-Schnaps" - } - if pushMessageText == "" { - pushMessageText = "Du hast 30 Sekunden, um im Flur zu erscheinen" - } }.onDisappear { stopPeriodicUpdates() } } + + private func didDoubleTapToken() { + UIPasteboard.general + .setValue(pushToken!, forPasteboardType: UTType.plainText.identifier) + didTapText = true + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) { + self.didTapText = false + } + } @State private var timer: Timer? @@ -211,14 +136,9 @@ struct ContentView: View { timer?.invalidate() timer = nil } - + private func updateState() { updateNotificationPermissionState() - if isConfirmed { - updateDeviceList() - } else if couldBeRegistered { - checkPushRegistrationStatus() - } } func registerForRemoteNotifications() { @@ -239,108 +159,6 @@ struct ContentView: View { UIApplication.shared.open(appSettings) } } - - func register() { - guard let token = pushToken else { - print("No token to register") - return - } - guard let url = URL(string: server) else { - return - } - let api = PushClient(server: url, application: application) - self.api = api - let name = deviceName - Task { - print("Registering...") - guard let auth = await api.register(token: token, name: name) else { - DispatchQueue.main.async { - authToken = nil - isConfirmed = false - } - return - } - print("Registered") - DispatchQueue.main.async { - authToken = auth - isConfirmed = false - updateDeviceList() - } - } - } - - func checkPushRegistrationStatus() { - guard let token = pushToken, - let authToken = authToken, - let api = api else { - return - } - Task { - let confirmed = await api.isConfirmed(token: token, authentication: authToken) - if !confirmed { - print(token.base64EncodedString()) - print(authToken.base64EncodedString()) - } - DispatchQueue.main.async { - isConfirmed = confirmed - } - } - } - - func updateDeviceList() { - guard let authToken = authToken, - let pushToken = pushToken, - let api = api else { - return - } - Task { - let devices = await api.getDeviceList(pushToken: pushToken, authToken: authToken) - DispatchQueue.main.async { - self.deviceList = devices ?? [] - } - } - } - - func showDevices() { - showDeviceList = true - } - - func sendPush() { - guard let authToken = authToken, - let pushToken = pushToken, - let api = api else { - return - } - - var recipients = deviceList.map { $0.pushToken } - guard recipients.count > 0 else { - return - } - if !includeOwnDeviceInPush { - recipients = recipients.filter { $0 != pushToken } - } - let body = pushMessageText - let alert = APNSwiftAlert( - title: pushMessageTitle, - body: body) - let payload = APNSwiftPayload( - alert: alert, - sound: .normal("default")) - let content = PushMessage( - recipients: recipients, - payload: payload, - pushType: .alert) - let sender = DeviceAuthentication( - pushToken: pushToken, - authentication: authToken) - let message = AuthenticatedPushMessage( - sender: sender, - message: content) - Task { - let sent = await api.send(push: message) - print("Sent push message: \(sent)") - } - } } struct ContentView_Previews: PreviewProvider { diff --git a/FlurSchnaps/DeviceList.swift b/FlurSchnaps/DeviceList.swift deleted file mode 100644 index c702a5c..0000000 --- a/FlurSchnaps/DeviceList.swift +++ /dev/null @@ -1,91 +0,0 @@ -import SwiftUI -import PushMessageDefinitions -import Push - -extension String { - - var nonEmpty: String? { - isEmpty ? nil : self - } -} - -struct DeviceList: View { - - let pushToken: PushToken - - let authToken: AuthenticationToken - - let api: PushClient - - @Binding - var isPresented: Bool - - @State - var devices: [DeviceRegistration] - - var body: some View { - NavigationView { - VStack(spacing: 0) { - List(devices) { device in - HStack { - Text(device.name.nonEmpty ?? "Device") - .font(.headline) - Spacer() - VStack(alignment: .leading) { - Text(device.application) - .font(.footnote) - .fontWeight(.bold) - .padding(.bottom, 2) - Text(device.pushToken.prefix(5).hexEncoded + "...") - .font(.caption) - } - } - }.refreshable { - await updateList() - } - }.toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button(action: dismiss) { - Text("Cancel") - } - } - }.navigationBarTitle("device-list-title") - }.onAppear() { - Task { - await updateList() - } - } - } - - private func updateList() async { - let devices = await api.getDeviceList(pushToken: pushToken, authToken: authToken) - print("Updated device list: \(devices?.count ?? -1)") - DispatchQueue.main.async { - self.devices = devices ?? [] - } - } - - private func dismiss() { - isPresented = false - } -} - -struct DeviceList_Previews: PreviewProvider { - static var previews: some View { - DeviceList(pushToken: Data(repeating: 42, count: 32), - authToken: Data(repeating: 42, count: 16), - api: .init(server: URL(string: "https://christophhagen.de/push")!, application: "some"), - isPresented: .constant(true), - devices: [DeviceRegistration( - pushToken: Data([1,2,3,4,5]), - application: "CC Messenger", - name: "Some")]) - } -} - -extension DeviceRegistration: Identifiable { - - public var id: String { - pushToken.prefix(5).hexEncoded - } -} diff --git a/FlurSchnaps/FlurSchnapsApp.swift b/FlurSchnaps/FlurSchnapsApp.swift index 63369b8..11c7869 100644 --- a/FlurSchnaps/FlurSchnapsApp.swift +++ b/FlurSchnaps/FlurSchnapsApp.swift @@ -1,4 +1,5 @@ import SwiftUI +import BinaryCodable @main struct FlurSchnapsApp: App { @@ -15,12 +16,11 @@ struct FlurSchnapsApp: App { class AppDelegate: NSObject, UIApplicationDelegate { - @AppStorage("pushToken") + @AppStorage("deviceToken") var pushToken: Data? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { - // For iOS 10 display notification (sent via APNS) UNUserNotificationCenter.current().delegate = self @@ -31,8 +31,9 @@ class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { - print("Registered with token: \(deviceToken)") - self.pushToken = deviceToken + let token = deviceToken.hexEncoded + print("Registered for remote notifications with token: \(token)") + uploadNewDeviceToken(deviceToken) } func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], @@ -42,6 +43,47 @@ class AppDelegate: NSObject, UIApplicationDelegate { completionHandler(UIBackgroundFetchResult.newData) } + + private func uploadNewDeviceToken(_ token: Data) { + if token == pushToken { + // Device token unchanged + return + } + + Task { + let tokenUpload = TokenUpload(currentToken: token, previousToken: pushToken) + let data: Data + do { + data = try BinaryEncoder().encode(tokenUpload) + + } catch { + print("Failed to encode token upload") + return + } + let result: URLResponse + do { + var request = URLRequest(url: URL(string: "https://christophhagen.de/schnaps/token")!) + request.httpMethod = "POST" + (_, result) = try await URLSession.shared.upload(for: request, from: data) + } catch { + print("Failed to upload token: \(error)") + return + } + guard let response = result as? HTTPURLResponse else { + print("Invalid response \(result)") + return + } + guard response.statusCode == 200 else { + print("Invalid response to token upload: \(response.statusCode)") + return + } + print("Push token uploaded") + DispatchQueue.main.async { + self.pushToken = token + } + } + // Upload new token, possibly with old one + } } extension AppDelegate: UNUserNotificationCenterDelegate { diff --git a/FlurSchnaps/TokenUpload.swift b/FlurSchnaps/TokenUpload.swift new file mode 100644 index 0000000..67a2115 --- /dev/null +++ b/FlurSchnaps/TokenUpload.swift @@ -0,0 +1,13 @@ +import Foundation + +struct TokenUpload: Codable { + + let currentToken: Data + + let previousToken: Data? + + enum CodingKeys: Int, CodingKey { + case currentToken = 1 + case previousToken = 2 + } +} diff --git a/FlurSchnaps/de.lproj/Localizable.strings b/FlurSchnaps/de.lproj/Localizable.strings index 3a2a549..62fb173 100644 --- a/FlurSchnaps/de.lproj/Localizable.strings +++ b/FlurSchnaps/de.lproj/Localizable.strings @@ -39,3 +39,5 @@ "device-list-title" = "Geräte"; "show-device-list-button" = "Liste einzeigen"; + +"push-token-title" = "Geräte-Identifikator"; diff --git a/FlurSchnaps/en.lproj/Localizable.strings b/FlurSchnaps/en.lproj/Localizable.strings index 82b328b..6e00f09 100644 --- a/FlurSchnaps/en.lproj/Localizable.strings +++ b/FlurSchnaps/en.lproj/Localizable.strings @@ -39,3 +39,5 @@ "device-list-title" = "Devices"; "show-device-list-button" = "Show device list"; + +"push-token-title" = "Push token";