diff --git a/.gitignore b/.gitignore index 8a97bc7..ba97882 100644 --- a/.gitignore +++ b/.gitignore @@ -67,3 +67,4 @@ fastlane/test_output **/*.xcworkspace **/*.DS_Store *.DS_Store +Package.resolved diff --git a/Package.swift b/Package.swift index 475d1d1..92429f4 100644 --- a/Package.swift +++ b/Package.swift @@ -1,6 +1,5 @@ // swift-tools-version:5.3 // The swift-tools-version declares the minimum version of Swift required to build this package. - import PackageDescription let package = Package( diff --git a/mParticle-Iterable.podspec b/mParticle-Iterable.podspec index e81b876..56f3db0 100644 --- a/mParticle-Iterable.podspec +++ b/mParticle-Iterable.podspec @@ -12,7 +12,7 @@ Pod::Spec.new do |s| s.social_media_url = "https://twitter.com/mparticle" s.ios.deployment_target = "11.0" - s.ios.source_files = 'mParticle-Iterable/*.{h,m,mm}' + s.ios.source_files = 'mParticle-Iterable/*.{h,m,mm,swift}' s.ios.dependency 'mParticle-Apple-SDK/mParticle', '~> 8.0' s.ios.dependency 'Iterable-iOS-SDK', '~> 6.4' end diff --git a/mParticle-Iterable.xcodeproj/project.pbxproj b/mParticle-Iterable.xcodeproj/project.pbxproj index 9dbe0c5..65d50a5 100644 --- a/mParticle-Iterable.xcodeproj/project.pbxproj +++ b/mParticle-Iterable.xcodeproj/project.pbxproj @@ -3,28 +3,26 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ - 535CF23F285CD8D60043F267 /* mParticle_Apple_SDK.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 535CF23D285CD8D60043F267 /* mParticle_Apple_SDK.xcframework */; }; - 535CF242285CDCB10043F267 /* IterableSDK.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 535CF241285CDCB10043F267 /* IterableSDK.xcframework */; }; DB7E05A61CB819D300967FDF /* MPKitIterable.h in Headers */ = {isa = PBXBuildFile; fileRef = DB7E05A41CB819D300967FDF /* MPKitIterable.h */; settings = {ATTRIBUTES = (Public, ); }; }; DB7E05A71CB819D300967FDF /* MPKitIterable.m in Sources */ = {isa = PBXBuildFile; fileRef = DB7E05A51CB819D300967FDF /* MPKitIterable.m */; }; DB9401701CB703F2007ABB18 /* mParticle_Iterable.h in Headers */ = {isa = PBXBuildFile; fileRef = DB94016F1CB703F2007ABB18 /* mParticle_Iterable.h */; settings = {ATTRIBUTES = (Public, ); }; }; DB96D2AA1F61AA6200D2289F /* IterableMPHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = DB96D2A81F61AA6200D2289F /* IterableMPHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; DB96D2AB1F61AA6200D2289F /* IterableMPHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = DB96D2A91F61AA6200D2289F /* IterableMPHelper.m */; }; + E9ABED382B15EB39007A291E /* mParticle-Apple-SDK in Frameworks */ = {isa = PBXBuildFile; productRef = E9ABED372B15EB39007A291E /* mParticle-Apple-SDK */; }; + E9ABED3B2B15EB44007A291E /* IterableSDK in Frameworks */ = {isa = PBXBuildFile; productRef = E9ABED3A2B15EB44007A291E /* IterableSDK */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 535CF23D285CD8D60043F267 /* mParticle_Apple_SDK.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = mParticle_Apple_SDK.xcframework; path = Carthage/Build/mParticle_Apple_SDK.xcframework; sourceTree = ""; }; - 535CF241285CDCB10043F267 /* IterableSDK.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = IterableSDK.xcframework; path = Carthage/Build/IterableSDK.xcframework; sourceTree = ""; }; DB7E05A41CB819D300967FDF /* MPKitIterable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPKitIterable.h; sourceTree = ""; }; DB7E05A51CB819D300967FDF /* MPKitIterable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPKitIterable.m; sourceTree = ""; }; DB94016C1CB703F2007ABB18 /* mParticle_Iterable.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = mParticle_Iterable.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DB94016F1CB703F2007ABB18 /* mParticle_Iterable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mParticle_Iterable.h; sourceTree = ""; }; DB9401711CB703F2007ABB18 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - DB96D2A81F61AA6200D2289F /* IterableMPHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IterableMPHelper.h; path = "mParticle-iterable/IterableMPHelper.h"; sourceTree = SOURCE_ROOT; }; + DB96D2A81F61AA6200D2289F /* IterableMPHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IterableMPHelper.h; path = "mParticle-Iterable/IterableMPHelper.h"; sourceTree = SOURCE_ROOT; }; DB96D2A91F61AA6200D2289F /* IterableMPHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IterableMPHelper.m; path = "mParticle-iterable/IterableMPHelper.m"; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ @@ -33,8 +31,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 535CF242285CDCB10043F267 /* IterableSDK.xcframework in Frameworks */, - 535CF23F285CD8D60043F267 /* mParticle_Apple_SDK.xcframework in Frameworks */, + E9ABED382B15EB39007A291E /* mParticle-Apple-SDK in Frameworks */, + E9ABED3B2B15EB44007A291E /* IterableSDK in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -44,8 +42,6 @@ DB9401621CB703F2007ABB18 = { isa = PBXGroup; children = ( - 535CF241285CDCB10043F267 /* IterableSDK.xcframework */, - 535CF23D285CD8D60043F267 /* mParticle_Apple_SDK.xcframework */, DB94016E1CB703F2007ABB18 /* mParticle-Iterable */, DB94016D1CB703F2007ABB18 /* Products */, ); @@ -62,11 +58,11 @@ DB94016E1CB703F2007ABB18 /* mParticle-Iterable */ = { isa = PBXGroup; children = ( - DB96D2A81F61AA6200D2289F /* IterableMPHelper.h */, DB96D2A91F61AA6200D2289F /* IterableMPHelper.m */, + DB94016F1CB703F2007ABB18 /* mParticle_Iterable.h */, + DB96D2A81F61AA6200D2289F /* IterableMPHelper.h */, DB7E05A41CB819D300967FDF /* MPKitIterable.h */, DB7E05A51CB819D300967FDF /* MPKitIterable.m */, - DB94016F1CB703F2007ABB18 /* mParticle_Iterable.h */, DB9401711CB703F2007ABB18 /* Info.plist */, ); path = "mParticle-Iterable"; @@ -102,6 +98,10 @@ dependencies = ( ); name = "mParticle-Iterable"; + packageProductDependencies = ( + E9ABED372B15EB39007A291E /* mParticle-Apple-SDK */, + E9ABED3A2B15EB44007A291E /* IterableSDK */, + ); productName = "mParticle-Iterable"; productReference = DB94016C1CB703F2007ABB18 /* mParticle_Iterable.framework */; productType = "com.apple.product-type.framework"; @@ -118,6 +118,7 @@ DB94016B1CB703F2007ABB18 = { CreatedOnToolsVersion = 7.3; DevelopmentTeam = Q948K5LXGZ; + LastSwiftMigration = 1500; }; }; }; @@ -130,6 +131,10 @@ en, ); mainGroup = DB9401621CB703F2007ABB18; + packageReferences = ( + E9ABED362B15EB39007A291E /* XCRemoteSwiftPackageReference "mparticle-apple-sdk" */, + E9ABED392B15EB44007A291E /* XCRemoteSwiftPackageReference "swift-sdk" */, + ); productRefGroup = DB94016D1CB703F2007ABB18 /* Products */; projectDirPath = ""; projectRoot = ""; @@ -256,6 +261,7 @@ DB9401751CB703F2007ABB18 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -275,12 +281,15 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.mparticle.mParticle-Iterable"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; }; name = Debug; }; DB9401761CB703F2007ABB18 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_MODULES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -300,6 +309,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.mparticle.mParticle-Iterable"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -325,6 +335,38 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + E9ABED362B15EB39007A291E /* XCRemoteSwiftPackageReference "mparticle-apple-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/mParticle/mparticle-apple-sdk.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 8.4.0; + }; + }; + E9ABED392B15EB44007A291E /* XCRemoteSwiftPackageReference "swift-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/Iterable/swift-sdk.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 6.4.16; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + E9ABED372B15EB39007A291E /* mParticle-Apple-SDK */ = { + isa = XCSwiftPackageProductDependency; + package = E9ABED362B15EB39007A291E /* XCRemoteSwiftPackageReference "mparticle-apple-sdk" */; + productName = "mParticle-Apple-SDK"; + }; + E9ABED3A2B15EB44007A291E /* IterableSDK */ = { + isa = XCSwiftPackageProductDependency; + package = E9ABED392B15EB44007A291E /* XCRemoteSwiftPackageReference "swift-sdk" */; + productName = IterableSDK; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = DB9401631CB703F2007ABB18 /* Project object */; } diff --git a/mParticle-iterable/Info.plist b/mParticle-Iterable/Info.plist similarity index 100% rename from mParticle-iterable/Info.plist rename to mParticle-Iterable/Info.plist diff --git a/mParticle-Iterable/IterableMPHelper.swift b/mParticle-Iterable/IterableMPHelper.swift new file mode 100644 index 0000000..fb3fbe4 --- /dev/null +++ b/mParticle-Iterable/IterableMPHelper.swift @@ -0,0 +1,14 @@ +// +// IterableMPHelper.swift +// Pods +// +// Created by David Truong on 4/21/17. +// +// + +import Foundation + +// Keys in the linkInfo passed to the onAttributionComplete handler +public let IterableDestinationURLKey: String = "IterableDestinationURLKey" +public let IterableClickedURLKey: String = "IterableClickedURLKey" + diff --git a/mParticle-Iterable/MPKitIterable.swift b/mParticle-Iterable/MPKitIterable.swift new file mode 100644 index 0000000..c9c0315 --- /dev/null +++ b/mParticle-Iterable/MPKitIterable.swift @@ -0,0 +1,251 @@ +import Foundation +import mParticle_Apple_SDK +import IterableSDK + +@objcMembers public class MPKitIterable: NSObject, MPKitProtocol, IterableURLDelegate { + + private var _kitApi: MPKitAPI? + public var configuration: [AnyHashable: Any] = [:] + public var launchOptions: [AnyHashable: Any]? + public var started: Bool = false + public var userAttributes: [String: Any]? + public var userIdentities: [[String: Any]]? + public var mpidEnabled: Bool = false + + static private var customConfig: IterableConfig? + static private var customUrlDelegate: IterableURLDelegate? + static private var clickedURL: URL? + static private var _prefersUserId: Bool = false + + public static func setCustomConfig(_ config: IterableConfig?) { + customConfig = config + customUrlDelegate = config?.urlDelegate + } + + public static func prefersUserId() -> Bool { + return _prefersUserId + } + + public static func kitCode() -> NSNumber { + return 1003 + } + + public static func setPrefersUserId(_ prefers: Bool) { + _prefersUserId = prefers + } + + public func handle(iterableURL url: URL, inContext context: IterableSDK.IterableActionContext) -> Bool { + var result = true + + if MPKitIterable.customUrlDelegate === self { + print("mParticle -> Error: Iterable urlDelegate was set in custom config but points to the MPKitIterable instance. It should be a different object.") + } else if let customUrlDelegate = MPKitIterable.customUrlDelegate as? NSObject, customUrlDelegate.responds(to: #selector(IterableURLDelegate.handle(iterableURL:inContext:))) { + if let customResult = customUrlDelegate.perform(#selector(IterableURLDelegate.handle(iterableURL:inContext:)), with: url, with: context)?.takeUnretainedValue() as? Bool { + result = customResult + } + } else if MPKitIterable.customUrlDelegate != nil { + print("mParticle -> Error: Iterable urlDelegate was set in custom config but didn't respond to the selector 'handleIterableURL:context:'") + } + + let destinationURL = url.absoluteString + var getAndTrackParams: [String: Any]? + let clickedUrlString = MPKitIterable.clickedURL?.absoluteString ?? "" + MPKitIterable.clickedURL = nil + + if destinationURL.isEmpty || clickedUrlString == destinationURL { + getAndTrackParams = [IterableClickedURLKey: clickedUrlString] + } else { + getAndTrackParams = [IterableDestinationURLKey: destinationURL, IterableClickedURLKey: clickedUrlString] + } + + let attributionResult = MPAttributionResult() + attributionResult.linkInfo = getAndTrackParams ?? [:] + + _ = _kitApi?.onAttributionComplete(with: attributionResult, error: nil) + + return result + } + + // MARK: - MPKitInstanceProtocol methods + + // MARK: Kit instance and lifecycle + public func didFinishLaunching(withConfiguration configuration: [AnyHashable: Any]) -> MPKitExecStatus { + self.configuration = configuration + start() + return MPKitExecStatus(sdkCode: MPKitIterable.kitCode(), returnCode: .success) + } + + public func start() { + struct OnceToken { + static var token = false + } + + if !OnceToken.token { + if let apiKey = self.configuration["apiKey"] as? String, + let apnsProdIntegrationName = self.configuration["apnsProdIntegrationName"] as? String, + let apnsSandboxIntegrationName = self.configuration["apnsSandboxIntegrationName"] as? String, + let userIdField = self.configuration["userIdField"] as? String { + + self.mpidEnabled = userIdField == "mpid" + + var config = Self.customConfig + if config == nil { + config = IterableConfig() + } + + config?.pushIntegrationName = apnsProdIntegrationName + config?.sandboxPushIntegrationName = apnsSandboxIntegrationName + config?.urlDelegate = self + + if let config = config { + IterableAPI.initialize(apiKey: apiKey, config: config) + initIntegrationAttributes() + + self.started = true + + DispatchQueue.main.async { + let userInfo = [mParticleKitInstanceKey: MPKitIterable.kitCode()] + + NotificationCenter.default.post(name: NSNotification.Name(NSNotification.Name.mParticleKitDidBecomeActive.rawValue), + object: nil, + userInfo: userInfo) + } + } + } + } + + func continueUserActivity(_ userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> MPKitExecStatus { + MPKitIterable.clickedURL = userActivity.webpageURL + + if let clickedURL = MPKitIterable.clickedURL { + IterableAPI.handle(universalLink: clickedURL) + } + + return MPKitExecStatus(sdkCode: MPKitIterable.kitCode(), returnCode: .success) + } + + func initIntegrationAttributes() { + let integrationAttributes = [ + "Iterable.sdkVersion": IterableAPI.sdkVersion + ] + MParticle.sharedInstance().setIntegrationAttributes(integrationAttributes, forKit: MPKitIterable.kitCode()) + } + + func getUserEmail(_ user: FilteredMParticleUser) -> String? { + return user.userIdentities[NSNumber(value: MPUserIdentity.email.rawValue)] + } + + func getCustomerId(_ user: FilteredMParticleUser) -> String? { + return user.userIdentities[NSNumber(value: MPUserIdentity.customerId.rawValue)] + } + + func onLoginComplete(_ user: FilteredMParticleUser, request: FilteredMPIdentityApiRequest) -> MPKitExecStatus { + updateIdentity(user) + return MPKitExecStatus(sdkCode: MPKitIterable.kitCode(), returnCode: .success) + } + + func onLogoutComplete(_ user: FilteredMParticleUser, request: FilteredMPIdentityApiRequest) -> MPKitExecStatus { + updateIdentity(user) + return MPKitExecStatus(sdkCode: MPKitIterable.kitCode(), returnCode: .success) + } + + func onIdentifyComplete(_ user: FilteredMParticleUser, request: FilteredMPIdentityApiRequest) -> MPKitExecStatus { + updateIdentity(user) + return MPKitExecStatus(sdkCode: MPKitIterable.kitCode(), returnCode: .success) + } + + func getUserId(_ user: FilteredMParticleUser) -> String? { + var userId: String? = nil + if mpidEnabled { + if user.userId != 0 { + userId = user.userId.stringValue + } + } else { + userId = UIDevice.current.identifierForVendor?.uuidString.lowercased() + + if userId?.isEmpty ?? true { + userId = advertiserId()?.lowercased() + } + + if userId?.isEmpty ?? true { + userId = getCustomerId(user) + } + + if userId?.isEmpty ?? true { + userId = MParticle.sharedInstance().identity.deviceApplicationStamp + } + } + return userId + } + + func getPlaceholderEmail(_ userId: String?) -> String? { + guard let userId = userId, !userId.isEmpty else { + return nil + } + return "\(userId)@placeholder.email" + } + + func updateIdentity(_ user: FilteredMParticleUser) { + if let userId = getUserId(user), MPKitIterable._prefersUserId { + IterableAPI.setUserId(userId) + return + } + + let email = getUserEmail(user) + let placeholderEmail = getPlaceholderEmail(getUserId(user)) + + if let email = email, !email.isEmpty { + IterableAPI.setEmail(email) + } else if let placeholderEmail = placeholderEmail, !placeholderEmail.isEmpty { + IterableAPI.setEmail(placeholderEmail) + } else { + // No identifier, log out + IterableAPI.setEmail(nil) + } + } + + func currentUser() -> FilteredMParticleUser? { + return _kitApi?.getCurrentUser(withKit: self) + } + + func setDeviceToken(_ deviceToken: Data) -> MPKitExecStatus { + IterableAPI.register(token: deviceToken) + return MPKitExecStatus(sdkCode: MPKitIterable.kitCode(), returnCode: .success) + } + +#if os(iOS) + @available(iOS 10.0, *) + func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) -> MPKitExecStatus { + IterableAppIntegration.userNotificationCenter(center, didReceive: response, withCompletionHandler: {}) + return MPKitExecStatus(sdkCode: MPKitIterable.kitCode(), returnCode: .success) + } +#endif + + func receivedUserNotification(_ userInfo: [AnyHashable: Any]) -> MPKitExecStatus { + IterableAppIntegration.application(UIApplication.shared, didReceiveRemoteNotification: userInfo, fetchCompletionHandler: { _ in }) + return MPKitExecStatus(sdkCode: MPKitIterable.kitCode(), returnCode: .success) + } + + // MARK: - Accessors + func advertiserId() -> String? { + var advertiserId: String? + + if let MPIdentifierManagerClass = NSClassFromString("ASIdentifierManager") as? NSObject.Type { + let selector = NSSelectorFromString("sharedManager") + if let adIdentityManager = MPIdentifierManagerClass.perform(selector)?.takeUnretainedValue() as? NSObject { + let isAdvertisingTrackingEnabledSelector = NSSelectorFromString("isAdvertisingTrackingEnabled") + if let isAdvertisingTrackingEnabled = adIdentityManager.perform(isAdvertisingTrackingEnabledSelector)?.takeUnretainedValue() as? NSNumber, isAdvertisingTrackingEnabled.boolValue { + let advertisingIdentifierSelector = NSSelectorFromString("advertisingIdentifier") + if let advertisingIdentifier = adIdentityManager.perform(advertisingIdentifierSelector)?.takeUnretainedValue() as? NSUUID { + advertiserId = advertisingIdentifier.uuidString + } + } + } + } + + return advertiserId + } + + + } +} diff --git a/mParticle-iterable/mParticle_Iterable.h b/mParticle-Iterable/mParticle_Iterable.h similarity index 70% rename from mParticle-iterable/mParticle_Iterable.h rename to mParticle-Iterable/mParticle_Iterable.h index 9062f63..3b113f7 100644 --- a/mParticle-iterable/mParticle_Iterable.h +++ b/mParticle-Iterable/mParticle_Iterable.h @@ -7,9 +7,3 @@ FOUNDATION_EXPORT double mParticle_IterableVersionNumber; FOUNDATION_EXPORT const unsigned char mParticle_IterableVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import - -#if defined(__has_include) && __has_include() -#import -#else -#import "MPKitIterable.h" -#endif \ No newline at end of file diff --git a/mParticle-iterable/IterableMPHelper.h b/mParticle-iterable/IterableMPHelper.h deleted file mode 100644 index 65f3f29..0000000 --- a/mParticle-iterable/IterableMPHelper.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// IterableMPHelper.h -// Pods -// -// Created by David Truong on 4/21/17. -// -// - -#ifndef IterableMPHelper_h -#define IterableMPHelper_h - -// Keys in the linkInfo passed to the onAttributionComplete handler -extern NSString * _Nonnull const IterableDestinationURLKey; -extern NSString * _Nonnull const IterableClickedURLKey; - -#endif - -/* IterableMPHelper_h */ diff --git a/mParticle-iterable/IterableMPHelper.m b/mParticle-iterable/IterableMPHelper.m deleted file mode 100644 index b493a2b..0000000 --- a/mParticle-iterable/IterableMPHelper.m +++ /dev/null @@ -1,13 +0,0 @@ -// -// IterableMPHelper.m -// Pods -// -// Created by David Truong on 4/21/17. -// -// - -#import -#import "IterableMPHelper.h" - -NSString *const IterableDestinationURLKey = @"IterableDestinationURLKey"; -NSString *const IterableClickedURLKey = @"IterableClickedURLKey"; diff --git a/mParticle-iterable/MPKitIterable.h b/mParticle-iterable/MPKitIterable.h deleted file mode 100644 index 3d13542..0000000 --- a/mParticle-iterable/MPKitIterable.h +++ /dev/null @@ -1,39 +0,0 @@ -#import -#if defined(__has_include) && __has_include() - #import - #import -#elif defined(__has_include) && __has_include() - #import - #import -#else - #import "mParticle.h" - #import "mParticle_Apple_SDK-Swift.h" -#endif - -#import "IterableMPHelper.h" - -@class IterableConfig; - -@interface MPKitIterable : NSObject - -@property (nonatomic, strong, nonnull) NSDictionary *configuration; -@property (nonatomic, strong, nullable) NSDictionary *launchOptions; -@property (nonatomic, unsafe_unretained, readonly) BOOL started; -@property (nonatomic, strong, nullable) NSDictionary *userAttributes; -@property (nonatomic, strong, nullable) NSArray *> *userIdentities; -@property (nonatomic, readwrite) BOOL mpidEnabled; - -/** - * Set a custom config to be used when initializing Iterable SDK - * @param config `IterableConfig` instance with configuration data for Iterable SDK - */ -+ (void)setCustomConfig:(IterableConfig *_Nullable)config; - -/** - * Declare whether or not to prefer user id in API calls to Iterable. If `YES`, the kit will not - * set an email or create a placeholder.email address - */ -+ (void)setPrefersUserId:(BOOL)prefers; -+ (BOOL)prefersUserId; - -@end diff --git a/mParticle-iterable/MPKitIterable.m b/mParticle-iterable/MPKitIterable.m deleted file mode 100644 index 2b3090c..0000000 --- a/mParticle-iterable/MPKitIterable.m +++ /dev/null @@ -1,257 +0,0 @@ -#import "MPKitIterable.h" -#import -#import -@import IterableSDK; - - -@interface MPKitIterable() -@end - -@implementation MPKitIterable - -@synthesize kitApi = _kitApi; -static __strong IterableConfig *_customConfig = nil; -static __strong id _customUrlDelegate = nil; -static __strong NSURL *_clickedURL = nil; -static BOOL _prefersUserId = NO; - -+ (NSNumber *)kitCode { - return @1003; -} - -+ (void)load { - MPKitRegister *kitRegister = [[MPKitRegister alloc] initWithName:@"Iterable" className:@"MPKitIterable"]; - [MParticle registerExtension:kitRegister]; -} - -+ (void)setCustomConfig:(IterableConfig *_Nullable)config { - _customConfig = config; - _customUrlDelegate = config.urlDelegate; -} - -+ (BOOL)prefersUserId { - return _prefersUserId; -} - -+ (void)setPrefersUserId:(BOOL)prefers { - _prefersUserId = prefers; -} - -- (BOOL)handleIterableURL:(NSURL *)url context:(IterableActionContext *)context { - BOOL result = YES; - if (_customUrlDelegate == self) { - NSLog(@"mParticle -> Error: Iterable urlDelegate was set in custom config but points to the MKKitIterable instance. It should be a different object."); - } else if (_customUrlDelegate != nil && [((NSObject *)_customUrlDelegate) respondsToSelector:@selector(handleIterableURL:context:)]) { - result = [_customUrlDelegate handleIterableURL:url context: context]; - } else if (_customUrlDelegate != nil) { - NSLog(@"mParticle -> Error: Iterable urlDelegate was set in custom config but didn't respond to the selector 'handleIterableURL:context:'"); - } - - NSString *destinationURL = url.absoluteString; - NSDictionary *getAndTrackParams = nil; - NSString *clickedUrlString = _clickedURL.absoluteString; - if (clickedUrlString == nil) { - clickedUrlString = @""; - } - _clickedURL = nil; - if (!destinationURL || [clickedUrlString isEqualToString:destinationURL]) { - getAndTrackParams = [[NSDictionary alloc] initWithObjectsAndKeys: clickedUrlString, IterableClickedURLKey, nil]; - } else { - getAndTrackParams = [[NSDictionary alloc] initWithObjectsAndKeys: destinationURL, IterableDestinationURLKey, clickedUrlString, IterableClickedURLKey, nil]; - } - - MPAttributionResult *attributionResult = [[MPAttributionResult alloc] init]; - attributionResult.linkInfo = getAndTrackParams; - - [self->_kitApi onAttributionCompleteWithResult:attributionResult error:nil]; - return result; -} - -#pragma mark - MPKitInstanceProtocol methods - -#pragma mark Kit instance and lifecycle -- (MPKitExecStatus *)didFinishLaunchingWithConfiguration:(NSDictionary *)configuration { - MPKitExecStatus *execStatus = nil; - - _configuration = configuration; - - [self start]; - - execStatus = [[MPKitExecStatus alloc] initWithSDKCode:[[self class] kitCode] returnCode:MPKitReturnCodeSuccess]; - return execStatus; -} - -- (void)start { - static dispatch_once_t kitPredicate; - - dispatch_once(&kitPredicate, ^{ - - NSString *apiKey = self.configuration[@"apiKey"]; - NSString *apnsProdIntegrationName = self.configuration[@"apnsProdIntegrationName"]; - NSString *apnsSandboxIntegrationName = self.configuration[@"apnsSandboxIntegrationName"]; - NSString *userIdField = self.configuration[@"userIdField"]; - self.mpidEnabled = [userIdField isEqualToString:@"mpid"]; - - IterableConfig *config = _customConfig; - if (!config) { - config = [[IterableConfig alloc] init]; - } - config.pushIntegrationName = apnsProdIntegrationName; - config.sandboxPushIntegrationName = apnsSandboxIntegrationName; - config.urlDelegate = self; - - [IterableAPI initializeWithApiKey:apiKey config:config]; - [self initIntegrationAttributes]; - - self->_started = YES; - - dispatch_async(dispatch_get_main_queue(), ^{ - NSDictionary *userInfo = @{mParticleKitInstanceKey:[[self class] kitCode]}; - - [[NSNotificationCenter defaultCenter] postNotificationName:mParticleKitDidBecomeActiveNotification - object:nil - userInfo:userInfo]; - }); - }); -} - -#pragma mark Application -- (nonnull MPKitExecStatus *)continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(void(^ _Nonnull)(NSArray * _Nullable restorableObjects))restorationHandler { - _clickedURL = userActivity.webpageURL; - - if (_clickedURL != nil) { - [IterableAPI handleUniversalLink:_clickedURL]; - } - - MPKitExecStatus *execStatus = [[MPKitExecStatus alloc] initWithSDKCode:[MPKitIterable kitCode] returnCode:MPKitReturnCodeSuccess]; - return execStatus; -} - -- (void)initIntegrationAttributes { - NSDictionary *integrationAttributes = @{ - @"Iterable.sdkVersion": IterableAPI.sdkVersion - }; - [[MParticle sharedInstance] setIntegrationAttributes:integrationAttributes forKit:MPKitIterable.kitCode]; -} - -- (NSString *)getUserEmail:(FilteredMParticleUser *)user { - return user.userIdentities[@(MPUserIdentityEmail)]; -} - -- (NSString *)getCustomerId:(FilteredMParticleUser *)user { - return user.userIdentities[@(MPUserIdentityCustomerId)]; -} - -- (MPKitExecStatus *)onLoginComplete:(FilteredMParticleUser *)user request:(FilteredMPIdentityApiRequest *)request { - [self updateIdentity:user]; - return [[MPKitExecStatus alloc] initWithSDKCode:[[self class] kitCode] returnCode:MPKitReturnCodeSuccess]; -} - -- (nonnull MPKitExecStatus *)onLogoutComplete:(nonnull FilteredMParticleUser *)user request:(nonnull FilteredMPIdentityApiRequest *)request { - [self updateIdentity:user]; - return [[MPKitExecStatus alloc] initWithSDKCode:[[self class] kitCode] returnCode:MPKitReturnCodeSuccess]; -} - -- (MPKitExecStatus *)onIdentifyComplete:(FilteredMParticleUser *)user request:(FilteredMPIdentityApiRequest *)request { - [self updateIdentity:user]; - return [[MPKitExecStatus alloc] initWithSDKCode:[[self class] kitCode] returnCode:MPKitReturnCodeSuccess]; -} - -- (NSString *)getUserId:(FilteredMParticleUser *)user { - NSString *userId = nil; - if (self.mpidEnabled) { - if (user.userId.longValue != 0) { - userId = user.userId.stringValue; - } - } else { - userId = [[[[UIDevice currentDevice] identifierForVendor] UUIDString] lowercaseString]; - - if (!userId.length) { - userId = [[self advertiserId] lowercaseString]; - } - - if (!userId.length) { - userId = [self getCustomerId:user]; - } - - if (!userId.length) { - userId = [[[MParticle sharedInstance] identity] deviceApplicationStamp]; - } - } - return userId; -} - -- (NSString *)getPlaceholderEmail:(NSString *)userId { - if (userId.length > 0) { - return [NSString stringWithFormat:@"%@@placeholder.email", userId]; - } else { - return nil; - } -} - -- (void)updateIdentity:(FilteredMParticleUser *)user { - NSString *userId = [self getUserId:user]; - if (_prefersUserId) { - [IterableAPI setUserId:userId]; - return; - } - - NSString *email = [self getUserEmail:user]; - NSString *placeholderEmail = [self getPlaceholderEmail:userId]; - if (email != nil && email.length > 0) { - [IterableAPI setEmail:email]; - } else if (placeholderEmail != nil && placeholderEmail.length > 0) { - [IterableAPI setEmail:placeholderEmail]; - } else { - // No identifier, log out - [IterableAPI setEmail:nil]; - } -} - -- (FilteredMParticleUser *)currentUser { - return [[self kitApi] getCurrentUserWithKit:self]; -} - -- (MPKitExecStatus *)setDeviceToken:(NSData *)deviceToken { - [IterableAPI registerToken:deviceToken]; - return [[MPKitExecStatus alloc] initWithSDKCode:[[self class] kitCode] returnCode:MPKitReturnCodeSuccess]; -} - -#if TARGET_OS_IOS == 1 && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 -- (MPKitExecStatus *)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response API_AVAILABLE(ios(10.0)) { - [IterableAppIntegration userNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:^{}]; - return [[MPKitExecStatus alloc] initWithSDKCode:[[self class] kitCode] returnCode:MPKitReturnCodeSuccess]; -} -#endif - -- (MPKitExecStatus *)receivedUserNotification:(NSDictionary *)userInfo { - [IterableAppIntegration application:UIApplication.sharedApplication didReceiveRemoteNotification:userInfo fetchCompletionHandler:^(UIBackgroundFetchResult result){}]; - return [[MPKitExecStatus alloc] initWithSDKCode:[[self class] kitCode] returnCode:MPKitReturnCodeSuccess]; -} - -#pragma mark Accessors -- (NSString *)advertiserId { - NSString *advertiserId = nil; - Class MPIdentifierManager = NSClassFromString(@"ASIdentifierManager"); - if (MPIdentifierManager) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wundeclared-selector" -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" - SEL selector = NSSelectorFromString(@"sharedManager"); - id adIdentityManager = [MPIdentifierManager performSelector:selector]; - - selector = NSSelectorFromString(@"isAdvertisingTrackingEnabled"); - BOOL advertisingTrackingEnabled = ((BOOL (*)(id, SEL))objc_msgSend)(adIdentityManager, selector); - if (advertisingTrackingEnabled) { - selector = NSSelectorFromString(@"advertisingIdentifier"); - advertiserId = [[adIdentityManager performSelector:selector] UUIDString]; - } -#pragma clang diagnostic pop -#pragma clang diagnostic pop - } - - return advertiserId; -} - -@end