diff --git a/Mixpanel/MixpanelInstance.swift b/Mixpanel/MixpanelInstance.swift index b30afc696..8c9f0e76e 100644 --- a/Mixpanel/MixpanelInstance.swift +++ b/Mixpanel/MixpanelInstance.swift @@ -605,55 +605,25 @@ open class MixpanelInstance: CustomDebugStringConvertible, FlushDelegate, AEDele } func defaultDistinctId() -> String { - #if MIXPANEL_RANDOM_DISTINCT_ID - let distinctId: String? = UUID().uuidString - #elseif !os(OSX) && !WATCH_OS - var distinctId: String? = IFA() - if distinctId == nil && NSClassFromString("UIDevice") != nil { + #if MIXPANEL_UNIQUE_DISTINCT_ID + #if !os(OSX) && !WATCH_OS + var distinctId: String? = nil + if NSClassFromString("UIDevice") != nil { distinctId = UIDevice.current.identifierForVendor?.uuidString } #elseif os(OSX) let distinctId = MixpanelInstance.macOSIdentifier() - #else - let distinctId: String? = nil - #endif // os(OSX) + #endif + #else // use a random UUID by default + let distinctId: String? = UUID().uuidString + #endif guard let distId = distinctId else { return UUID().uuidString } return distId } - #if !os(OSX) && !WATCH_OS - func IFA() -> String? { - var ifa: String? = nil - #if !MIXPANEL_NO_IFA - if let ASIdentifierManagerClass = NSClassFromString("ASIdentifierManager") { - let sharedManagerSelector = NSSelectorFromString("sharedManager") - if let sharedManagerIMP = ASIdentifierManagerClass.method(for: sharedManagerSelector) { - typealias sharedManagerFunc = @convention(c) (AnyObject, Selector) -> AnyObject? - let curriedImplementation = unsafeBitCast(sharedManagerIMP, to: sharedManagerFunc.self) - if let sharedManager = curriedImplementation(ASIdentifierManagerClass.self, sharedManagerSelector) { - let advertisingTrackingEnabledSelector = NSSelectorFromString("isAdvertisingTrackingEnabled") - if let isTrackingEnabledIMP = sharedManager.method(for: advertisingTrackingEnabledSelector) { - typealias isTrackingEnabledFunc = @convention(c) (AnyObject, Selector) -> Bool - let curriedImplementation2 = unsafeBitCast(isTrackingEnabledIMP, to: isTrackingEnabledFunc.self) - let isTrackingEnabled = curriedImplementation2(self, advertisingTrackingEnabledSelector) - if isTrackingEnabled { - let advertisingIdentifierSelector = NSSelectorFromString("advertisingIdentifier") - if let advertisingIdentifierIMP = sharedManager.method(for: advertisingIdentifierSelector) { - typealias adIdentifierFunc = @convention(c) (AnyObject, Selector) -> NSUUID - let curriedImplementation3 = unsafeBitCast(advertisingIdentifierIMP, to: adIdentifierFunc.self) - ifa = curriedImplementation3(self, advertisingIdentifierSelector).uuidString - } - } - } - } - } - } - #endif - return ifa - } - #elseif os(OSX) + #if os(OSX) static func macOSIdentifier() -> String? { let platformExpert: io_service_t = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice")); let serialNumberAsCFString = IORegistryEntryCreateCFProperty(platformExpert, kIOPlatformSerialNumberKey as CFString, kCFAllocatorDefault, 0); @@ -755,26 +725,14 @@ extension MixpanelInstance { /** Sets the distinct ID of the current user. - Mixpanel will choose a default local distinct ID based on whether you are using the - AdSupport.framework or not. - - If you are not using the AdSupport Framework (iAds), then we use the IFV String - (`UIDevice.current().identifierForVendor`) as the default local distinct ID. This ID will - identify a user across all apps by the same vendor, but cannot be used to link the same - user across apps from different vendors. If we are unable to get the IFV, we will fall - back to generating a random persistent UUID - - If you are showing iAds in your application, you are allowed use the iOS ID - for Advertising (IFA) to identify users. If you have this framework in your - app, Mixpanel will use the IFA as the default local distinct ID. If you have - AdSupport installed but still don't want to use the IFA, you can define the - MIXPANEL_NO_IFA flag in your Active Compilation Conditions - build settings, and Mixpanel will use the IFV as the default local distinct ID. - - If we are unable to get an IFA or IFV, we will fall back to generating a - random persistent UUID. If you want to always use a random persistent UUID - you can define the MIXPANEL_RANDOM_DISTINCT_ID preprocessor flag - in your build settings. + Mixpanel uses a randomly generated persistent UUID as the default local distinct ID. + + If you want to use a unique persistent UUID, you can define the + MIXPANEL_UNIQUE_DISTINCT_ID flag in your Active Compilation Conditions + build settings. It then uses the IFV String (`UIDevice.current().identifierForVendor`) as + the default local distinct ID. This ID will identify a user across all apps by the same vendor, but cannot be + used to link the same user across apps from different vendors. If we are unable to get an IFV, we will fall + back to generating a random persistent UUID. For tracking events, you do not need to call `identify:`. However, **Mixpanel User profiles always requires an explicit call to `identify:`.** diff --git a/MixpanelDemo/MixpanelDemoTests/MixpanelDemoTests.swift b/MixpanelDemo/MixpanelDemoTests/MixpanelDemoTests.swift index ac018a351..6999f529a 100644 --- a/MixpanelDemo/MixpanelDemoTests/MixpanelDemoTests.swift +++ b/MixpanelDemo/MixpanelDemoTests/MixpanelDemoTests.swift @@ -168,12 +168,14 @@ class MixpanelDemoTests: MixpanelBaseTests { // run this twice to test reset works correctly wrt to distinct ids let distinctId: String = "d1" // try this for ODIN and nil + #if MIXPANEL_UNIQUE_DISTINCT_ID XCTAssertEqual(mixpanel.distinctId, mixpanel.defaultDistinctId(), "mixpanel identify failed to set default distinct id") XCTAssertEqual(mixpanel.anonymousId, mixpanel.defaultDistinctId(), "mixpanel failed to set default anonymous id") + #endif XCTAssertNil(mixpanel.people.distinctId, "mixpanel people distinct id should default to nil") XCTAssertNil(mixpanel.people.distinctId, @@ -182,9 +184,11 @@ class MixpanelDemoTests: MixpanelBaseTests { waitForTrackingQueue() XCTAssertTrue(mixpanel.eventsQueue.count == 1, "events should be sent right away with default distinct id") + #if MIXPANEL_UNIQUE_DISTINCT_ID XCTAssertEqual((mixpanel.eventsQueue.last?["properties"] as? InternalProperties)?["distinct_id"] as? String, mixpanel.defaultDistinctId(), "events should use default distinct id if none set") + #endif XCTAssertEqual((mixpanel.eventsQueue.last?["properties"] as? InternalProperties)?["$lib_version"] as? String, AutomaticProperties.libVersion(), "events should has lib version in internal properties") @@ -275,10 +279,9 @@ class MixpanelDemoTests: MixpanelBaseTests { let p: InternalProperties = e["properties"] as! InternalProperties XCTAssertEqual(p["distinct_id"] as? String, newDistinctId, "wrong distinct_id") XCTAssertEqual(p["$anon_distinct_id"] as? String, prevDistinctId, "wrong $anon_distinct_id") - #if MIXPANEL_RANDOM_DISTINCT_ID XCTAssertNotEqual(prevDistinctId, originalDistinctId, "After reset, UUID will be used - never the same"); - #else - XCTAssertEqual(prevDistinctId, originalDistinctId, "After reset, IFA/UIDevice id will be used - always the same"); + #if MIXPANEL_UNIQUE_DISTINCT_ID + XCTAssertEqual(prevDistinctId, originalDistinctId, "After reset, IFV will be used - always the same"); #endif mixpanel.reset() waitForTrackingQueue() @@ -545,9 +548,11 @@ class MixpanelDemoTests: MixpanelBaseTests { mixpanel.archive() mixpanel.reset() waitForTrackingQueue() + #if MIXPANEL_UNIQUE_DISTINCT_ID XCTAssertEqual(mixpanel.distinctId, mixpanel.defaultDistinctId(), "distinct id failed to reset") + #endif XCTAssertNil(mixpanel.people.distinctId, "people distinct id failed to reset") XCTAssertTrue(mixpanel.currentSuperProperties().isEmpty, "super properties failed to reset") @@ -555,8 +560,10 @@ class MixpanelDemoTests: MixpanelBaseTests { XCTAssertTrue(mixpanel.people.peopleQueue.isEmpty, "people queue failed to reset") mixpanel = Mixpanel.initialize(token: kTestToken, launchOptions: nil, flushInterval: 60) waitForTrackingQueue() + #if MIXPANEL_UNIQUE_DISTINCT_ID XCTAssertEqual(mixpanel.distinctId, mixpanel.defaultDistinctId(), "distinct id failed to reset after archive") + #endif XCTAssertNil(mixpanel.people.distinctId, "people distinct id failed to reset after archive") XCTAssertTrue(mixpanel.currentSuperProperties().isEmpty, @@ -599,8 +606,10 @@ class MixpanelDemoTests: MixpanelBaseTests { func testArchive() { let testToken = randomId() mixpanel = Mixpanel.initialize(token: testToken, launchOptions: nil, flushInterval: 60) + #if MIXPANEL_UNIQUE_DISTINCT_ID XCTAssertEqual(mixpanel.distinctId, mixpanel.defaultDistinctId(), "default distinct id archive failed") + #endif XCTAssertTrue(mixpanel.currentSuperProperties().isEmpty, "default super properties archive failed") XCTAssertTrue(mixpanel.eventsQueue.isEmpty, "default events queue archive failed") @@ -700,8 +709,10 @@ class MixpanelDemoTests: MixpanelBaseTests { Persistence.deleteMPUserDefaultsData(token: testToken) mixpanel = Mixpanel.initialize(token: testToken, launchOptions: nil, flushInterval: 60) waitForTrackingQueue() + #if MIXPANEL_UNIQUE_DISTINCT_ID XCTAssertEqual(mixpanel.distinctId, mixpanel.defaultDistinctId(), "default distinct id from garbage failed") + #endif XCTAssertTrue(mixpanel.currentSuperProperties().isEmpty, "default super properties from garbage failed") XCTAssertNotNil(mixpanel.eventsQueue, "default events queue from garbage is nil")