Last active
April 14, 2021 07:54
-
-
Save agileapplications/6707b6829d6bdfad41cafd4c9d8f246b to your computer and use it in GitHub Desktop.
Sample implementation to receive unencrypted ably messages via native Apple Push Notification Service (APNS) delivered by ably in foreground and background.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// AppDelegate.swift | |
// swift-ios | |
// | |
import Foundation | |
import UIKit | |
import Ably | |
class AppDelegate: NSObject, UIApplicationDelegate, ARTPushRegistererDelegate, UNUserNotificationCenterDelegate { | |
var realtime: ARTRealtime! | |
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { | |
// assign ably instance | |
realtime = getAblyRealtime() | |
UNUserNotificationCenter.current().delegate = self | |
// probably this is not necessary if only background notifications are used | |
UNUserNotificationCenter.current().requestAuthorization(options: [.provisional, .badge, .alert]) { granted, _ in | |
print("Permission granted: \(granted)") | |
} | |
// registers device using server authentication to ably with client id | |
realtime.push.activate() | |
// starts APNS registration process | |
UIApplication.shared.registerForRemoteNotifications() | |
// Do I have to call realtime.push.deactivate()? When, why, how? | |
return true | |
} | |
// MARK: APNS Push Message Delegate | |
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { | |
print("APNS: ", userInfo) | |
completionHandler(.newData) | |
} | |
// MARK: APNS Setup Delegate | |
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { | |
print("registering for remote notifications with device token...") | |
ARTPush.didRegisterForRemoteNotifications(withDeviceToken: deviceToken, realtime: realtime) | |
} | |
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { | |
print("ERROR: didFailToRegisterForRemoteNotificationsWithError") | |
ARTPush.didFailToRegisterForRemoteNotificationsWithError(error, realtime: realtime) | |
} | |
// MARK: ARTPushRegistererDelegate | |
func didActivateAblyPush(_ error: ARTErrorInfo?) { | |
print("SUCCESS: didActivateAblyPush") | |
if let error = error { | |
print("ERROR: didActivateAblyPush, err=\(String(describing: error))") | |
return | |
} | |
} | |
func didDeactivateAblyPush(_ error: ARTErrorInfo?) { | |
if let error = error { | |
print("ERROR: didDeactivateAblyPush", error) | |
return | |
} | |
} | |
// MARK: Ably Realtime Client (Singleton) | |
func getAblyRealtime() -> ARTRealtime { | |
if let realtime = realtime { | |
return realtime | |
} | |
realtime = ARTRealtime(options: getOptions()) | |
return realtime | |
} | |
func getOptions() -> ARTClientOptions { | |
let options = ARTClientOptions() | |
// this is dependent on auth method (we use server side authentication) | |
// https://ably.com/tutorials/token-authentication | |
options.authUrl = URL(string: "https://my-server-endpoint/ably_token_requests")! | |
options.authMethod = "POST" | |
options.authHeaders = ["X-API-KEY": "secret"] | |
options.pushRegistererDelegate = self | |
return options | |
} | |
} |
My App uses the latest SwiftUI skeleton with App
and @main
. I had to create the separate AppDelegate
and reference it:
// Main.swift
import SwiftUI
@main
struct Main: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
MainNavigation()
}
}
}
Last 2 questions:
- When, how, why, where and if I have to call
realtime.push.deactivate()
https://gist.github.com/agileapplications/6707b6829d6bdfad41cafd4c9d8f246b#file-appdelegate-swift-L29 - Is there a way to prevent Echos like we can do on the web with the
connectionKey
so that I can send sth to the server with a request and the push to APNS will not happen if the sender was already the device?
-> an idea could be not to send push notification if they came in from specific mobile endpoints, correct? But then I am not able to sync between two mobile phone (edge case, but still not as nice as the connectionKey)
In general what is your recommendation?
App in Background = Use APNS for Message Delivery
App in Foreground = Use Ably Realtime steady connection
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Ably Push Inspector was able to push messages, but local server implementation (ably-ruby) was not, this worked in the end:
Two things I figured out:
notification: { title: "" }
has to be presentapns: { aps: { "content-available": 1 } }
is necessary to also get those messages when app is in the background