MarketingCloudSDK Crashes SwiftUI App in Beta TestFlight
We've implemented Push Notifications through SalesForce Marketing Cloud and after some beta testing with internal testers it seems the SFMCSDK is causing our app to Crash intermittently due to "_dispatch_once". Not sure if this is an issue with the way we've implemented the SDK or simply a bug from the SDK itself, when we open the crash in project we only get the following information:
TestFlight metrics include # crashes
crash details from Xcode Organizer
Screenshot of crash in project
We've followed the documentation to setup the SDK / Push Notifications and standard push notifications are working as expected. We have an issue receiving/reading openDirect urls from a terminated app state (works in foreground/background) but we removed those urls in the hopes that they were causing the crash, it seems they were not.
I also found an article that said setting 'Other Linker Flags' in Xcode Build Settings can cause the "_dispatch_once" crash but we checked and we don't define any.
We implement everything through AppDelegate in SwiftUI:
import SFMCSDK
import MarketingCloudSDK
import Foundation
import SwiftUI
import UIKit
class AppDelegate: NSObject, UIApplicationDelegate, ObservableObject, URLHandlingDelegate {
let appId = "correct appId String"
let accessToken = "correct accessToken String"
let appEndpoint = URL(string:"correct marketingCloud appEndpoint URL")!
let mid = "correct marketing cloud ID"
func configureSDK() {
#if DEBUG
SFMCSdk.setLogger(logLevel: .debug)
#endif
let mobilePushConfiguration = PushConfigBuilder(appId: appId)
.setAccessToken(accessToken)
.setMarketingCloudServerUrl(appEndpoint)
.setDelayRegistrationUntilContactKeyIsSet(true)
.setMid(mid)
.setInboxEnabled(false)
.setLocationEnabled(false)
.setAnalyticsEnabled(true)
.build()
let completionHandler: (OperationResult) -> () = { result in
if result == .success {
// module is fully configured and ready for use
SFMCSdk.mp.setURLHandlingDelegate(self)
} else if result == .error {
// module failed to initialize, check logs for more details
} else if result == .cancelled {
// module initialization was cancelled
} else if result == .timeout {
// module failed to initialize due to timeout, check logs for more details
}
}
SFMCSdk.initializeSdk(ConfigBuilder().setPush(config: mobilePushConfiguration,
onCompletion: completionHandler).build())
}
func registerPush(contactID:String?) {
#if !targetEnvironment(simulator)
#if DEBUG
SFMCSdk.identity.setProfileId("[email protected]")
setupMobilePush()
#else
if let contactKey = contactID {
SFMCSdk.identity.setProfileId(contactKey)
setupMobilePush()
}
#endif
#endif
}
func sfmc_handleURL(_ url: URL, type: String) {
print(url.description)
}
}
extension AppDelegate: UNUserNotificationCenterDelegate {
func setupMobilePush() {
DispatchQueue.main.async {
UNUserNotificationCenter.current().delegate = self
// Request authorization from the user for push notification alerts.
UNUserNotificationCenter.current().requestAuthorization(
options: [.alert, .sound, .badge], completionHandler: {
(_ granted: Bool, _ error: Error?) -> Void in
if error == nil {
if granted == true {
// Logic if authorized
}
} else {
print(error!.localizedDescription)
}
})
UIApplication.shared.registerForRemoteNotifications()
}
}
// SDK: REQUIRED IMPLEMENTATION
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.configureSDK()
return true
}
// MobilePush SDK: REQUIRED IMPLEMENTATION
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
SFMCSdk.mp.setDeviceToken(deviceToken)
}
// MobilePush SDK: REQUIRED IMPLEMENTATION
func application(_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error) {
print(error)
}
// MobilePush SDK: REQUIRED IMPLEMENTATION
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo:
[AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping
(UIBackgroundFetchResult) -> Void) {
SFMCSdk.mp.setNotificationUserInfo(userInfo)
completionHandler(.newData)
}
// MobilePush SDK: REQUIRED IMPLEMENTATION
@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response:
UNNotificationResponse, withCompletionHandler completionHandler: @escaping () ->
Void) {
SFMCSdk.mp.setNotificationRequest(response.notification.request)
completionHandler()
}
// MobilePush SDK: REQUIRED IMPLEMENTATION
@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent
notification: UNNotification, withCompletionHandler completionHandler: @escaping
(UNNotificationPresentationOptions) -> Void) {
completionHandler(.alert)
}
}
Any insight would be most appreciated!