2

I am trying to send an apns token to my server when didRegisterForRemoteNotificationsWithDeviceToken is called. I can successfully print the token to the console, so I know that part is working.

I have also implemented such an endpoint on my web service, which is also working just fine with the rest of my app.

In the Apple Developer documentation, under the last section called Forward Tokens to Your Provider Server it says

Upon receiving a device token, open a network connection from your app to your provider server. Securely forward the device token and any other information you need to identify the specific user to your server. For example, you might include the user's login name or something that connects them to your service.

Practically speaking, how do I include information like this? I can't seem to pass additional parameters into didRegisterForRemoteNotificationsWithDeviceToken, like a user's access token, userid, etc.

Since I'm using SwiftUI, the all the user's info, including their access token, is in an @EnvironmentObject in my view structs. Do I need to switch to a singleton or something?

benpva16
  • 446
  • 6
  • 26

3 Answers3

0

You could encode the struct that holds all the user metadata, including the token, into a JSON JSONEncoder and send it in a request to the server.

cora
  • 1,916
  • 1
  • 10
  • 18
0

Turns out, a singleton is probably a better implementation. Once you're inside didRegisterForRemoteNotificationsWithDeviceToken, you can't access anything from the view, so the @EnvironmentObject is useless.

Until I can restructure my logged in user data entirely as a singleton (involves ripping out/changing a bunch of code), I simply have an ApiAccessToken singleton that I set before I request permission (the user is logged in at that point) and then access the singleton in didRegisterForRemoteNotificationsWithDeviceToken.

ApiTokenSingleton.swift

import Foundation

class ApiTokenSingleton
{
    static let shared = ApiTokenSingleton()
    
    private var token = ""
    
    func getToken() -> String {
        return token
    }
    
    func setToken(newToken: String) {
        token = newToken
    }
}

MyView.swift, onAppear, when I request access. authenticatedUser is the EnvironmentObject

.onAppear() {
    ApiTokenSingleton.shared.setToken(newToken: authenticatedUser.accessToken ?? "")
    appDelegate.registerForPushNotifications()
}

AppDelegate.swift

    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)")
        
        // send token to backend here
        let deviceService = DeviceService()
        deviceService.add(accessToken: ApiTokenSingleton.shared.getToken(), deviceToken: token) { createDeviceResponse in
            print(createDeviceResponse)
        }
        
    }
benpva16
  • 446
  • 6
  • 26
0

You can save apnToken somewhere first - it could be application preferences database, or application preferences state (initialized on application start), where you have an access from your API layer.

Example:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    let encryptedToken = [UInt8](deviceToken).map{String(format: "%02x", $0)}.joined()
    
    // persist encrypted token to application settings DB
}

Get apnToken from database in my API layer and send it to the API, with additional data

private static func subscribeToNotification() {
    guard let apnToken = // get apnToken from app preferences DB

    // ... code for getting other params for API request from different other places

    let result = apiFetcher.request(
        type: ApiRequestType.post,
        path: // url,
        headers: // headers,
        queryParams: [
           "Token": apnToken,
           "Param1": param1,
           "Param2": param2
        ],
        withAuth: true
    )
}