Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 17 additions & 59 deletions Mixpanel/MixpanelInstance.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
<code>MIXPANEL_NO_IFA</code> flag in your <code>Active Compilation Conditions</code>
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 <code>MIXPANEL_RANDOM_DISTINCT_ID</code> 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
<code>MIXPANEL_UNIQUE_DISTINCT_ID</code> flag in your <code>Active Compilation Conditions</code>
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:`.**
Expand Down
17 changes: 14 additions & 3 deletions MixpanelDemo/MixpanelDemoTests/MixpanelDemoTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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")
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -545,18 +548,22 @@ 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")
XCTAssertTrue(mixpanel.eventsQueue.isEmpty, "events queue failed to reset")
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,
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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")
Expand Down