AppsFlyerSDK / AppsFlyerFramework

AppsFlyer Apple SDK
https://support.appsflyer.com/hc/en-us/articles/207032066-AppsFlyer-SDK-Integration-iOS
Other
163 stars 90 forks source link

Crash [AFSDKUserDefaultsStorage incrementInAppCnt] #235

Open danielgarbien opened 1 year ago

danielgarbien commented 1 year ago

Report

SDK Version

6.10.0

What did you do?

Included AppsFlyerLib in the iOS app.

What did you expect to happen?

App kept working.

What happened instead?

App occasionally crashes.

Please provide any other relevant information.

SIGTRAP (#0): Application crash: SIGTRAP (Trace/BPT trap)
Thread 26 Crashed:
0   libobjc.A.dylib                     0x00000001b699dd94 object_getClass + 48
1   Foundation                          0x00000001b7bceec8 _NSKeyValueObservationInfoGetObservances + 248
2   Foundation                          0x00000001b7bd5b00 NSKeyValueWillChange + 176
3   Foundation                          0x00000001b7c03550 -[NSObject(NSKeyValueObservingPrivate) _changeValueForKeys:count:maybeOldValuesDict:maybeNewValuesDict:usingBlock:] + 464
4   Foundation                          0x00000001b7c02678 -[NSObject(NSKeyValueObservingPrivate) _notifyObserversOfChangeFromValuesForKeys:toValuesForKeys:] + 648
5   CoreFoundation                      0x00000001bd941000 -[CFPrefsSource forEachObserver:] + 316
6   CoreFoundation                      0x00000001bd94646c -[CFPrefsSource _notifyObserversOfChangeFromValuesForKeys:toValuesForKeys:] + 112
7   CoreFoundation                      0x00000001bd946368 ___CFPrefsDeliverPendingKVONotificationsGuts_block_invoke + 432
8   CoreFoundation                      0x00000001bd949750 __CFDictionaryApplyFunction_block_invoke + 28
9   CoreFoundation                      0x00000001bd9719b0 CFBasicHashApply + 148
10  CoreFoundation                      0x00000001bd9725d8 CFDictionaryApplyFunction + 320
11  CoreFoundation                      0x00000001bd91a254 _CFPrefsDeliverPendingKVONotificationsGuts + 300
12  CoreFoundation                      0x00000001bd9709e8 -[_CFXPreferences _deliverPendingKVONotifications] + 96
13  CoreFoundation                      0x00000001bd9882f8 __108-[_CFXPreferences(SearchListAdditions) withSearchListForIdentifier:container:cloudConfigurationURL:perform:]_block_invoke + 420
14  CoreFoundation                      0x00000001bd973f48 normalizeQuintuplet + 356
15  CoreFoundation                      0x00000001bd9707e0 -[_CFXPreferences withSearchListForIdentifier:container:cloudConfigurationURL:perform:] + 152
16  CoreFoundation                      0x00000001bd9189d4 -[_CFXPreferences setValue:forKey:appIdentifier:container:configurationURL:] + 128
17  CoreFoundation                      0x00000001bd918910 _CFPreferencesSetAppValueWithContainerAndConfiguration + 120
18  Foundation                          0x00000001b7c20ef8 -[NSUserDefaults(NSUserDefaults) setObject:forKey:] + 68
19  MyAppYo                             0x0000000101817564 -[AFSDKUserDefaultsStorage incrementInAppCnt] + 140
20  MyAppYo                             0x0000000101809fe0 __60-[AppsFlyerLib __executeRequestWithEvent:completionHandler:]_block_invoke_3 + 348
21  MyAppYo                             0x00000001017f5ed0 __51-[AppsFlyerHTTPClient sendEvent:completionHandler:]_block_invoke.141 + 280
22  libdispatch.dylib                   0x00000001c4db4320 _dispatch_call_block_and_release + 32
23  libdispatch.dylib                   0x00000001c4db5eac _dispatch_client_callout + 20
24  libdispatch.dylib                   0x00000001c4dbd534 _dispatch_lane_serial_drain + 668
25  libdispatch.dylib                   0x00000001c4dbe0a4 _dispatch_lane_invoke + 384
26  libdispatch.dylib                   0x00000001c4dc8cdc _dispatch_workloop_worker_thread + 648
27  libsystem_pthread.dylib             0x000000021d277ddc _pthread_wqthread + 288
28  libsystem_pthread.dylib             0x000000021d277b7c start_wqthread + 8
danielgarbien commented 1 year ago

Here's a similar issue from 2018 triggered by updating UserDefaults on a background thread.

There, it was suggested to swizzle UserDefaults method and run the change on the main thread. @amit-kremer93 is it still the way to go?

danielgarbien commented 1 year ago

@andr-ggn, does the workaround you proposed here still applies?

danielgarbien commented 5 months ago

This is my workaround:

extension UserDefaults {

    static func swizzleInstanceMethodsForAppFlyerWorkaround() {
        let originalSelector = #selector(set(_:forKey:) as (UserDefaults) -> (Any?, String) -> Void)
        let swizzledSelector = #selector(swizzled_set(_:forKey:))

        guard let originalMethod = class_getInstanceMethod(self, originalSelector),
              let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)
        else {
            assertionFailure("Not able to swizzle UserDefaults methods.")
            return
        }

        method_exchangeImplementations(originalMethod, swizzledMethod)
    }
}

private extension UserDefaults {

    @objc func swizzled_set(_ value: Any?, forKey key: String) {
        let appsFlyerInAppCounterKey = "AppsFlyerInAppCounter"
        guard
            !Thread.isMainThread,
            key == appsFlyerInAppCounterKey,
            let intValue = value as? Int
        else {
            swizzled_set(value, forKey: key)
            return
        }
        let diff = intValue - integer(forKey: appsFlyerInAppCounterKey)
        DispatchQueue.main.async {
            let newValue = self.integer(forKey: appsFlyerInAppCounterKey) + diff
            self.swizzled_set(newValue, forKey: key)
        }
    }
}