Issue receiving device token for notifications in App Clip

115 Views Asked by At

I am working on an App Clip and I would like to receive push notifications from my server. In my regular app, this functionality works fine. However, in the App Clip, I am unable to receive the device token. I suspect there might be something wrong with my implementation.

I have the following code in my AppDelegate:

class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        FirebaseApp.configure()
        
        return true
    }

    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
        let token = tokenParts.joined()
        print("Device Token: \(token)")
        Task{
            await NotificationManager.shared.sendTokenToServer(token: token)
        }
    }

    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("Failed to register for notifications: \(error)")
    }
    
}

I have enabled push notifications in the App Clip target, and when I launch the App Clip, I do receive a prompt asking for permission to allow notifications. However, even after granting permission, I am still not able to receive the device token.

Additionally, here is the code for my NotificationManager class:

class NotificationManager: NSObject, ObservableObject, UNUserNotificationCenterDelegate {
    @Published var token: String?
    
    static let shared = NotificationManager()
    
    override init() {
        super.init()
        UNUserNotificationCenter.current().delegate = self
    }
    
    func requestAuthorization() {
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
            if granted {
                DispatchQueue.main.async {
                    UIApplication.shared.registerForRemoteNotifications()
                }
            }
        }
    }
    
    func sendTokenToServer(token: String) async {
        let url = URL(string: "\(APIConfig.baseURL)/api/device-token")!
        
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.setValue("application/json", forHTTPHeaderField: "Accept")
        
        do {
            let deviceToken = await FirebaseTokenManager.shared.getToken()
            
            if let deviceToken = deviceToken {
                request.setValue("\(deviceToken)", forHTTPHeaderField: "Authorization")
            }
            
            let bodyData: [String: Any] = [
                "os": "ios", // Stel hier het juiste besturingssysteem in (ios of android)
                "bundle_id": Bundle.main.bundleIdentifier ?? "", // Voeg hier de bundle ID van je iOS-app toe
                "device_token": token
            ]
            
            request.httpBody = try JSONSerialization.data(withJSONObject: bodyData)
            
            let (data, response) = try await URLSession.shared.data(for: request)
            
            if let httpResponse = response as? HTTPURLResponse {
                print("HTTP status code: \(httpResponse.statusCode)")
                
                if (200...299).contains(httpResponse.statusCode) {
                    // Succesvolle response
                    let decoder = JSONDecoder()
                    let apiResponse = try decoder.decode(APICallResponse.self, from: data)
                    print("Success: \(apiResponse.message)")
                } else {
                    // Foutieve response
                    let decoder = JSONDecoder()
                    let errorResponse = try decoder.decode(ErrorResponse.self, from: data)
                    print("Error: \(errorResponse.message)")
                }
            }
            
        } catch {
            print("Error: \(error)")
        }
    }
    
}

In this code, I'm checking the notification settings using UNUserNotificationCenter.current().getNotificationSettings, and if the authorization status is .ephemeral or .authorized, I call notificationManager.requestAuthorization() to request notification permission.

.onAppear {
    activityManager.startCameraActivity(eventName: authenticationViewModel.event?.name ?? "", photosLeft: authenticationViewModel.photosLeft , photosTotal: authenticationViewModel.photoLimit)
    
    let center = UNUserNotificationCenter.current()
    center.getNotificationSettings { (settings) in
        if settings.authorizationStatus == .ephemeral {
            notificationManager.requestAuthorization()
        }
        
        if settings.authorizationStatus == .authorized {
            notificationManager.requestAuthorization()
        }
    }
}

Please note that I am unable to enable background modes for the App Clip because that option is not available. Could this be the cause of the issue? Is there any alternative approach I can take to receive the device token in the App Clip?

0

There are 0 best solutions below