import Foundation #if canImport(UIKit) import UIKit #endif /// Swissapp Pushs — client iOS /// CDN: https://sdk.pushs.swissapp.net/native/ios/SwissappPushs.swift public final class SwissappPushs { public static let version = "1.0.0" public let apiKey: String public let apiURL: URL public var externalUserId: String? public init( apiKey: String, apiURL: URL = URL(string: "https://api.pushs.swissapp.net")!, externalUserId: String? = nil ) { self.apiKey = apiKey self.apiURL = apiURL self.externalUserId = externalUserId } public static func tokenHex(from deviceToken: Data) -> String { deviceToken.map { String(format: "%02.2hhx", $0) }.joined() } @discardableResult public func register(deviceToken: Data, deviceName: String? = nil) async throws -> [String: Any] { #if canImport(UIKit) let name = deviceName ?? UIDevice.current.name let model = UIDevice.current.model #else let name = deviceName let model: String? = nil #endif let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String return try await register( pushToken: Self.tokenHex(from: deviceToken), platform: "ios", deviceName: name, deviceModel: model, appVersion: appVersion ) } @discardableResult public func register( pushToken: String, platform: String = "ios", deviceName: String? = nil, deviceModel: String? = nil, appVersion: String? = nil, externalUserId: String? = nil ) async throws -> [String: Any] { var body: [String: Any] = [ "push_token": pushToken, "platform": platform, "locale": Locale.current.identifier, "timezone": TimeZone.current.identifier ] if let ext = externalUserId ?? self.externalUserId { body["external_user_id"] = ext } if let deviceName { body["device_name"] = deviceName } if let deviceModel { body["device_model"] = deviceModel } if let appVersion { body["app_version"] = appVersion } return try await post(path: "/api/devices/register", body: body) } @discardableResult public func send( title: String? = nil, message: String, externalUserId: String? = nil, data: [String: Any]? = nil ) async throws -> [String: Any] { var body: [String: Any] = ["message": message] if let title { body["title"] = title } if let data { body["data"] = data } if let ext = externalUserId ?? self.externalUserId { body["external_user_id"] = ext } return try await post(path: "/api/send", body: body) } private func post(path: String, body: [String: Any]) async throws -> [String: Any] { let base = apiURL.absoluteString.trimmingCharacters(in: CharacterSet(charactersIn: "/")) var req = URLRequest(url: URL(string: base + path)!) req.httpMethod = "POST" req.setValue("application/json", forHTTPHeaderField: "Content-Type") req.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization") req.setValue("ios/\(Self.version)", forHTTPHeaderField: "X-Swissapp-SDK") req.httpBody = try JSONSerialization.data(withJSONObject: body) let (data, response) = try await URLSession.shared.data(for: req) let http = response as? HTTPURLResponse let json = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any] ?? [:] if let http, !(200...299).contains(http.statusCode) { let msg = json["error"] as? String ?? "HTTP \(http.statusCode)" throw NSError(domain: "SwissappPushs", code: http.statusCode, userInfo: [NSLocalizedDescriptionKey: msg]) } if let ok = json["success"] as? Bool, ok == false { throw NSError(domain: "SwissappPushs", code: 400, userInfo: [NSLocalizedDescriptionKey: json["error"] as? String ?? "Erreur"]) } return json } } /* // AppDelegate UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { _, _ in DispatchQueue.main.async { UIApplication.shared.registerForRemoteNotifications() } } func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { Task { let push = SwissappPushs(apiKey: "pushs_…", externalUserId: "user_123") _ = try? await push.register(deviceToken: deviceToken) } } */