-
Notifications
You must be signed in to change notification settings - Fork 83
Description
✍️ Issue Description
My app was working fine with the Iterable sdk v6.5.12. I updated the sdk version to 6.6.3. After that I started facing a crash on the app launch. So what we are doing here is we are downloading a fresh instance of our app without having any previous versions of our app. The app launches well, after login we kill the app. Now whenever we launch the app it crashes every time.
Please provide a clear and concise description of the issue you are experiencing.
📋 Steps to Reproduce
- Delete any previous app. Reinstall the app again with the latest iterable sdk 6.6.3.
- Login into the app.
- Kill the app and remove from the stack.
- Now launch the app again it crashes every time and in the Xcode I saw that it gives the BAD ACCESS error.
(List all necessary steps to reliably reproduce the issue.)
👤 Iterable orgId: Enter your organization id
📦 Iterable SDK version: 6.6.3
📲 iOS SDK version: iOS 26, iOS 15.8.3, iOS 18.3.1
The issue is occurring only on 6.6.3, everything was working fine with the 6.5.12. Further I am also putting the method below where the crash is occurring .
Method Name:
func data(forKey key: String) -> Data? {
var keychainQueryDictionary = setupKeychainQueryDictionary(forKey: key)
// Limit search results to one
keychainQueryDictionary[SecMatchLimit] = SecMatchLimitOne
// Specify we want Data/CFData returned
keychainQueryDictionary[SecReturnData] = CFBooleanTrue
// Search
var result: AnyObject?
let status = SecItemCopyMatching(keychainQueryDictionary as CFDictionary, &result)
return status == noErr ? result as? Data : nil
}
Line :45
Class Name : KeychainWrapper.
Please find below our code where we are using the Iterable Config .
import Foundation
import IterableSDK
protocol PushNotificationsService {
func launch(with launchOptions: [UIApplication.LaunchOptionsKey: Any]?)
func register(deviceToken: Data)
func application(
_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
completionHandler: @escaping (UIBackgroundFetchResult) -> Void
)
var handleDeepLinkNotification: ArgumentedClosure? { get set }
}
final class IterablePushNotificationsService: NSObject, PushNotificationsService, IterableInAppDelegate {
private let userService: RegisteredUserServiceProtocol
private let appId: String
private let interactions: InteractionsFactoryProtocol
private let notificationsCoreData: NotificationsCoreDataProtocol
private let eventBroadcaster: EventBroadcasterProtocol
private let config = IterableConfig()
private let observer = RegisteredUserObserver()
private let center = UNUserNotificationCenter.current()
private let iterableAPIService: IterableAPIServiceProtocol
var handleDeepLinkNotification: ArgumentedClosure<URL>?
deinit {
userService.removeObserver(observer)
}
init(
userService: RegisteredUserServiceProtocol,
details: ConfigurationDetailsProviderProtocol,
interactions: InteractionsFactoryProtocol,
notificationsCoreData: NotificationsCoreDataProtocol,
iterableAPIService: IterableAPIServiceProtocol,
eventBroadcaster: EventBroadcasterProtocol
) {
self.interactions = interactions
self.userService = userService
appId = details.iterableAppID()
self.notificationsCoreData = notificationsCoreData
self.iterableAPIService = iterableAPIService
self.eventBroadcaster = eventBroadcaster
super.init()
observer.updateHandler = { [weak self] user in
guard let self = self else { return }
guard user.email != IterableAPI.email else { return }
IterableAPI.logoutUser()
IterableAPI.setEmail(user.email)
}
userService.addObserver(observer)
}
func launch(with launchOptions: [UIApplication.LaunchOptionsKey: Any]?) {
center.delegate = self
config.urlDelegate = self
config.authDelegate = self
config.inAppDelegate = self
config.inAppDisplayInterval = 0.0
config.allowedProtocols = ["nxtr"]
IterableAPI.initialize(
apiKey: appId,
launchOptions: launchOptions,
config: config
)
}
func onNew(message: IterableInAppMessage) -> InAppShowResponse {
let blockedScreens: Set<ScreenName> = [
.offerDetail,
.offersNearMe,
.offersNearMeFilter,
.webBrowser,
.SSOVerification,
.productBundle,
.cardDuration,
.cardDeliveryOptions,
.cashbackApplication,
.cardDeliveryHomeAddressLookup,
.addresInput,
.cardDeliveryPOS,
.personalDetails,
.photoPicker,
.confirmPersonalDetails,
.paymentAdditionalDetails,
.billingAdrresInfo,
.cardOnWay,
.cardEditHolder,
.paymentSheet,
.paymentConfirmation,
.cardDetail,
.cardPurachaseSummary,
.passIDCheckpoint,
.passRejected,
.passTruthfulness,
.journeySuccess,
.passCancelConfirmation,
.passIDRemainingSteps,
.referFDE,
.passWalkThrough,
.passDocumentSelection,
.passDocumentPicker,
.passDocumentScan,
.passConfirmDetails,
.passFlagDetails,
.passPhotoGuidelines,
.passPhotoAcknowledgement,
.passPhotoPopover,
.passphotoCapture,
.passPhotoValidation
]
let current = ScreenTracker.currentScreen
if blockedScreens.contains(current) {
return .skip
}
return .show
}
func register(deviceToken: Data) {
IterableAPI.register(token: deviceToken)
}
func application(
_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
completionHandler: @escaping (UIBackgroundFetchResult) -> Void
) {
IterableAppIntegration.application(
application,
didReceiveRemoteNotification: userInfo,
fetchCompletionHandler: completionHandler
)
}
}
// MARK: - IterableURLDelegate
extension IterablePushNotificationsService: IterableURLDelegate {
func handle(iterableURL url: URL, inContext context: IterableActionContext)
-> Bool {
if !url.isWebURL() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.handleDeepLinkNotification?(url)
}
return true
}
return false
}
}
// MARK: - UNUserNotificationCenterDelegate
extension IterablePushNotificationsService: UNUserNotificationCenterDelegate {
public func userNotificationCenter(
_: UNUserNotificationCenter,
willPresent _: UNNotification,
withCompletionHandler completionHandler:
@escaping (UNNotificationPresentationOptions) -> Void
) {
eventBroadcaster.broadcast(.fetchNewNotifications)
completionHandler([.badge, .sound, .alert])
}
public func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void
) {
IterableAPI.inAppManager.isAutoDisplayPaused = true
try? CoreDataService.shared.readNotificationsWith(
notificationId: response.notification.request.identifier
)
eventBroadcaster.broadcast(.fetchNewNotifications)
var title: String?
if let aps = response.notification.request.content.userInfo["aps"]
as? [String: Any],
let alert = aps["alert"] as? [String: Any],
let alertTitle = alert["title"] as? String {
title = alertTitle
}
if let url = response.notification.request.content.userInfo["url"]
as? String {
guard let webUrl = URL(string: url) else { return }
if webUrl.isWebURL() {
logWebViewWith(link: url, title: title)
} else {
logNotification(link: url)
}
}
IterableAppIntegration.userNotificationCenter(
center,
didReceive: response,
withCompletionHandler: completionHandler
)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.7) {
IterableAPI.inAppManager.isAutoDisplayPaused = false
}
if let itbl = response.notification.request.content.userInfo["itbl"]
as? [String: Any],
let currentMessageId = itbl["messageId"] as? String,
let templateId = itbl["templateId"],
let campaignId = itbl["campaignId"] as? Int64 {
let trackingInfo: [AnyHashable: Any] = [
"templateId": templateId,
"messageId": currentMessageId,
"campaignId": campaignId,
]
IterableAPI.track(pushOpen: trackingInfo, dataFields: nil)
}
}
}
// MARK: - IterableAuthDelegate
extension IterablePushNotificationsService: IterableAuthDelegate {
func onAuthFailure(_ authFailure: IterableSDK.AuthFailure) {
IterableAPI.setEmail(userService.optionalUser()?.email ?? "")
}
func onAuthTokenRequested(completion: @escaping AuthTokenRetrievalHandler) {
guard let email = userService.optionalUser()?.email else { return }
iterableAPIService.fetchIterableJWTAuthToken(email: email) { result in
switch result {
case .success(let response):
completion(response.iterableJwt)
UIApplication.shared.registerForRemoteNotifications()
case .failure(let error):
IterableAPI.setEmail(email)
}
}
}
}
extension IterablePushNotificationsService {
private struct ScreenInteractions {
static let drawerScreenName: String = "notification_drawer"
static let selectWebURLAction: String = "open_web_url"
}
fileprivate func logNotification(link: String) {
guard let contentType = DeeplinkItemType(link: link) else { return }
let contentID = contentType.urlExtractor?.magicTokenFrom(link) ?? ""
interactions
.eventBuilder
.buttonTap()
.tappedOn(contentType.analyticsName)
.ofType(.notificationItem(contentType))
.inScreen(ScreenInteractions.drawerScreenName)
.with(
.init(
section: EventInteractionSection.notification,
contentId: contentID
)
)
.create()
.add(to: interactions.eventBroadcaster)
}
fileprivate func logWebViewWith(link: String, title: String?) {
interactions
.eventBuilder
.buttonTap()
.tappedOn(ScreenInteractions.selectWebURLAction)
.ofType(.notificationItem(.webURL))
.inScreen(ScreenInteractions.drawerScreenName)
.with(
.init(
section: EventInteractionSection.notification,
data1: ("notification_title", title),
data2: ("notification_url", link)
)
)
.create()
.add(to: interactions.eventBroadcaster)
}
}
⚠️ Beta Software Notice
Important: Our team does not provide support for issues encountered on beta or pre-release versions of operating systems, development tools, or other software. Please verify that the issue occurs on stable, officially released software before submitting this report. Thank you for your understanding.