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
6 changes: 3 additions & 3 deletions mParticle-UrbanAirship.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ Pod::Spec.new do |s|
s.source = { :git => "https://github.com/mparticle-integrations/mparticle-apple-integration-urbanairship.git", :tag => "v" + s.version.to_s }
s.social_media_url = "https://twitter.com/mparticle"

s.ios.deployment_target = "14.0"
s.ios.source_files = 'mParticle-UrbanAirship/*.{h,m,mm}'
s.ios.deployment_target = "15.0"
s.ios.source_files = 'mParticle-UrbanAirship/*.{h,m,mm,swift}'
s.ios.resource_bundles = { 'mParticle-UrbanAirship-Privacy' => ['mParticle-UrbanAirship/PrivacyInfo.xcprivacy'] }
s.ios.dependency 'mParticle-Apple-SDK/mParticle', '~> 8.22'
s.ios.dependency 'Airship', '~> 18.2'
s.ios.dependency 'Airship/ObjectiveC', '~> 19.1'
end

149 changes: 83 additions & 66 deletions mParticle-UrbanAirship/MPKitUrbanAirship.m
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,19 @@ - (void)start {
dispatch_once(&kitPredicate, ^{
self->_started = YES;

UAConfig *config = [UAConfig defaultConfig];
NSError *error = nil;
UAConfig *config = [UAConfig config];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh dang, so this is going to change some behavior that I am not sure if anyone is relying on. defaultConfig loads the plist values into the config if available. config is just a factory method. We did not expose a defaultConfig version so we can either not worry about, wait for the next release, or we can add some code here to try to use the loadFromplist method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rlepinski What if we did something like this?

Suggested change
UAConfig *config = [UAConfig config];
NSError *error = nil;
UAConfig *config = [UAConfig fromPlistWithContentsOfFile:@"AirshipConfig.plist" error:&error];
if (error) {
NSLog(@"Airship config failed to initialize based off AirshipConfig.plist: %@", error);
NSLog(@"mParticle will attempt to manually construct UA Config based off your Connection Settings");
config = [UAConfig config];
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You will get 2 types of errors here:

  • If the file does not exist you will get an error. I would imagine you would want to ignore this one for your plugin since some apps will probably rely on mParticle to construct the needed bits.
  • Some parsing error, this one you will want to log

How about adding a file exists check before logging those errors?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know what you think @rlepinski

NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *pListPath = @"AirshipConfig.plist";
if ([fileManager fileExistsAtPath:pListPath]) {
config = [UAConfig fromPlistWithContentsOfFile:pListPath error:&error];
if (error) {
NSLog(@"Airship config failed to initialize based off AirshipConfig.plist: %@", error);
NSLog(@"mParticle will attempt to manually construct UA Config based off your Connection Settings");
config = [UAConfig config];
}
}

config.isAutomaticSetupEnabled = NO;

// Enable passive APNS registration
Expand All @@ -151,14 +163,18 @@ - (void)start {
if ([MParticle sharedInstance].environment == MPEnvironmentDevelopment) {
config.developmentAppKey = self.configuration[UAConfigAppKey];
config.developmentAppSecret = self.configuration[UAConfigAppSecret];
config.inProduction = NO;
config.inProduction = @NO;
} else {
config.productionAppKey = self.configuration[UAConfigAppKey];
config.productionAppSecret = self.configuration[UAConfigAppSecret];
config.inProduction = YES;
config.inProduction = @YES;
}

[UAirship takeOff:config launchOptions:_launchOptions error:&error];
if (error) {
NSLog(@"Airship.takeOff failed: %@", error);
}

[UAirship takeOff:config launchOptions:_launchOptions];
UAirship.push.userPushNotificationsEnabled = YES;

NSDictionary *userInfo = @{mParticleKitInstanceKey:[[self class] kitCode]};
Expand All @@ -170,7 +186,7 @@ - (void)start {

[notificationCenter addObserver:self
selector:@selector(updateChannelIntegration)
name:UAirshipNotificationChannelCreated.name
name:@"com.urbanairship.channel.channel_created" // https://github.com/mparticle-integrations/mparticle-apple-integration-urbanairship/pull/31#discussion_r2003658925
object:nil];

[self updateChannelIntegration];
Expand Down Expand Up @@ -278,8 +294,7 @@ - (MPKitExecStatus *)routeCommerceEvent:(MPCommerceEvent *)commerceEvent {
}

- (MPKitExecStatus *)logLTVIncrease:(double)increaseAmount event:(MPEvent *)event {
UACustomEvent *customEvent = [UACustomEvent eventWithName:event.name
value:[NSNumber numberWithDouble:increaseAmount]];
UACustomEvent *customEvent = [[UACustomEvent alloc] initWithName:event.name value:increaseAmount];

[customEvent track];

Expand Down Expand Up @@ -351,10 +366,9 @@ - (MPKitExecStatus *)setUserAttribute:(NSString *)key value:(NSString *)value {
}

if (uaTag) {
[UAirship.channel editTags:^(UATagEditor *editor) {
[editor addTag:uaTag];
}];

UATagEditor *editor = [UAirship.channel editTags];
[editor addTag:uaTag];
[editor apply];
returnCode = MPKitReturnCodeSuccess;
} else {
returnCode = MPKitReturnCodeRequirementsNotMet;
Expand All @@ -377,10 +391,9 @@ - (MPKitExecStatus *)setUserTag:(NSString *)tag {
}

if (uaTag) {
[UAirship.channel editTags:^(UATagEditor *editor) {
[editor addTag:uaTag];
}];

UATagEditor *editor = [UAirship.channel editTags];
[editor addTag:uaTag];
[editor apply];
returnCode = MPKitReturnCodeSuccess;
} else {
returnCode = MPKitReturnCodeRequirementsNotMet;
Expand All @@ -403,11 +416,9 @@ - (nonnull MPKitExecStatus *)removeUserAttribute:(nonnull NSString *)key {
}

if (uaTag) {
[[UAirship channel] editTags:^(UATagEditor * _Nonnull editor) {
[editor removeTag:key];
[editor apply];
}];

UATagEditor *editor = [UAirship.channel editTags];
[editor removeTag:uaTag];
[editor apply];
returnCode = MPKitReturnCodeSuccess;
} else {
returnCode = MPKitReturnCodeRequirementsNotMet;
Expand Down Expand Up @@ -436,9 +447,9 @@ - (MPKitExecStatus *)setUserIdentity:(NSString *)identityString identityType:(MP

- (MPKitExecStatus *)setOptOut:(BOOL)optOut {
if(!optOut) {
UAirship.privacyManager.enabledFeatures = UAFeaturesAll;
UAirship.privacyManager.enabledFeatures = UAFeature.all;
} else {
UAirship.privacyManager.enabledFeatures = UAFeaturesNone;
UAirship.privacyManager.enabledFeatures = UAFeature.none;
}

return [[MPKitExecStatus alloc] initWithSDKCode:[MPKitUrbanAirship kitCode]
Expand Down Expand Up @@ -526,15 +537,19 @@ - (BOOL)setAssociatedIdentifier:(NSString *)identityString identityType:(MPUserI
}

UAAssociatedIdentifiers *identifiers = [UAirship.analytics currentAssociatedDeviceIdentifiers];
[identifiers setIdentifier:identityString forKey:key];
[UAirship.analytics associateDeviceIdentifiers:identifiers];
[identifiers setWithIdentifier:identityString key:key];
[UAirship.analytics associateDeviceIdentifier:identifiers];

return YES;
}

- (void)logUrbanAirshipEvent:(MPEvent *)event {
UACustomEvent *customEvent = [UACustomEvent eventWithName:event.name];
customEvent.properties = event.info;
UACustomEvent *customEvent = [[UACustomEvent alloc] initWithName:event.name];
NSError *error = nil;
[customEvent setProperties:event.info error:&error];
if (error) {
NSLog(@"Failed to set properties: %@\non Event: %@\n failed: %@", event.info, event.name, error);
}

[customEvent track];
}
Expand All @@ -548,45 +563,45 @@ - (BOOL)logAirshipRetailEventFromCommerceEvent:(MPCommerceEvent *)commerceEvent
case MPCommerceEventActionPurchase:

for (id product in commerceEvent.products) {
UARetailEventTemplate *template = [UARetailEventTemplate purchasedTemplate];
[self populateRetailEventTemplate:template commerceEvent:commerceEvent product:product];
UACustomEventRetailTemplate *template = [UACustomEventRetailTemplate purchased];
UACustomEvent *customEvent = [self populateRetailEventTemplate:template commerceEvent:commerceEvent product:product];

NSString *transactionId = commerceEvent.transactionAttributes.transactionId;
if (transactionId) {
template.transactionID = transactionId;
}
customEvent.transactionID = transactionId;

[[template createEvent] track];
[customEvent track];
}

return YES;

case MPCommerceEventActionAddToCart:

for (id product in commerceEvent.products) {
UARetailEventTemplate *template = [UARetailEventTemplate addedToCartTemplate];
[self populateRetailEventTemplate:template commerceEvent:commerceEvent product:product];
[[template createEvent] track];
UACustomEventRetailTemplate *template = [UACustomEventRetailTemplate addedToCart];
UACustomEvent *customEvent = [self populateRetailEventTemplate:template commerceEvent:commerceEvent product:product];

[customEvent track];
}

return YES;

case MPCommerceEventActionClick:

for (id product in commerceEvent.products) {
UARetailEventTemplate *template = [UARetailEventTemplate browsedTemplate];
[self populateRetailEventTemplate:template commerceEvent:commerceEvent product:product];
[[template createEvent] track];
UACustomEventRetailTemplate *template = [UACustomEventRetailTemplate browsed];
UACustomEvent *customEvent = [self populateRetailEventTemplate:template commerceEvent:commerceEvent product:product];

[customEvent track];
}

return YES;

case MPCommerceEventActionAddToWishList:

for (id product in commerceEvent.products) {
UARetailEventTemplate *template = [UARetailEventTemplate starredProductTemplate];
[self populateRetailEventTemplate:template commerceEvent:commerceEvent product:product];
[[template createEvent] track];
UACustomEventRetailTemplate *template = [UACustomEventRetailTemplate starred];
UACustomEvent *customEvent = [self populateRetailEventTemplate:template commerceEvent:commerceEvent product:product];
[customEvent track];
}

return YES;
Expand All @@ -596,24 +611,26 @@ - (BOOL)logAirshipRetailEventFromCommerceEvent:(MPCommerceEvent *)commerceEvent
}
}

- (void)populateRetailEventTemplate:(UARetailEventTemplate *)template
- (UACustomEvent *)populateRetailEventTemplate:(UACustomEventRetailTemplate *)template
commerceEvent:(MPCommerceEvent *)commerceEvent
product:(MPProduct *)product {
UACustomEventRetailProperties *properties = [[UACustomEventRetailProperties alloc] initWithId:product.sku category:product.category type:nil eventDescription:product.name isLTV:nil brand:product.brand isNewItem:nil currency:nil];

template.category = product.category;
template.identifier = product.sku;
template.eventDescription = product.name;
template.brand = product.brand;

UACustomEvent *customEvent = [[UACustomEvent alloc] initWithRetailTemplate:template properties:properties];

NSDecimal eventValue;
if (product.price == nil) {
template.eventValue = [NSDecimalNumber zero];
eventValue = [NSDecimalNumber zero].decimalValue;
} else if (product.quantity == nil) {
template.eventValue = [NSDecimalNumber decimalNumberWithDecimal:[product.price decimalValue]];
eventValue = [NSDecimalNumber decimalNumberWithDecimal:[product.price decimalValue]].decimalValue;
} else {
NSDecimalNumber *decimalPrice = [NSDecimalNumber decimalNumberWithDecimal:[product.price decimalValue]];
NSDecimalNumber *decimalQuantity = [NSDecimalNumber decimalNumberWithDecimal:[product.quantity decimalValue]];
template.eventValue = [decimalPrice decimalNumberByMultiplyingBy:decimalQuantity];
eventValue = [decimalPrice decimalNumberByMultiplyingBy:decimalQuantity].decimalValue;
}
customEvent.eventValue = eventValue;

return customEvent;
}

- (void)updateChannelIntegration {
Expand Down Expand Up @@ -676,9 +693,9 @@ - (void)setTagMappings:(NSArray<MPUATagMapping *> *)tagMappings forCommerceEvent

if (matchTagMappings.count > 0) {
[matchTagMappings enumerateObjectsUsingBlock:^(MPUATagMapping * _Nonnull tagMapping, NSUInteger idx, BOOL * _Nonnull stop) {
[UAirship.channel editTags:^(UATagEditor *editor) {
[editor addTag:tagMapping.value];
}];
UATagEditor *editor = [UAirship.channel editTags];
[editor addTag:tagMapping.value];
[editor apply];
}];
}
}
Expand All @@ -696,9 +713,9 @@ - (void)setTagMappings:(NSArray<MPUATagMapping *> *)tagMappings forEvent:(MPEven

if (matchTagMappings.count > 0) {
[matchTagMappings enumerateObjectsUsingBlock:^(MPUATagMapping * _Nonnull tagMapping, NSUInteger idx, BOOL * _Nonnull stop) {
[UAirship.channel editTags:^(UATagEditor *editor) {
[editor addTag:tagMapping.value];
}];
UATagEditor *editor = [UAirship.channel editTags];
[editor addTag:tagMapping.value];
[editor apply];
}];
}
}
Expand Down Expand Up @@ -733,10 +750,10 @@ - (void)setTagMappings:(NSArray<MPUATagMapping *> *)tagMappings forAttributesInC

if (attributeString) {
NSString *tagPlusAttributeValue = [NSString stringWithFormat:@"%@-%@", tagMapping.value, attributeString];
[UAirship.channel editTags:^(UATagEditor *editor) {
[editor addTag:tagPlusAttributeValue];
[editor addTag:tagMapping.value];
}];
UATagEditor *editor = [UAirship.channel editTags];
[editor addTag:tagPlusAttributeValue];
[editor addTag:tagMapping.value];
[editor apply];
}
}];
}
Expand All @@ -763,10 +780,10 @@ - (void)setTagMappings:(NSArray<MPUATagMapping *> *)tagMappings forAttributesInE

if (attributeString) {
NSString *tagPlusAttributeValue = [NSString stringWithFormat:@"%@-%@", tagMapping.value, attributeString];
[UAirship.channel editTags:^(UATagEditor *editor) {
[editor addTag:tagPlusAttributeValue];
[editor addTag:tagMapping.value];
}];
UATagEditor *editor = [UAirship.channel editTags];
[editor addTag:tagPlusAttributeValue];
[editor addTag:tagMapping.value];
[editor apply];
}
}];
}
Expand Down Expand Up @@ -794,14 +811,14 @@ - (MPKitExecStatus *)setDeviceToken:(NSData *)deviceToken {
}

- (nonnull MPKitExecStatus *)userNotificationCenter:(nonnull UNUserNotificationCenter *)center willPresentNotification:(nonnull UNNotification *)notification API_AVAILABLE(ios(10.0)){
[UAAppIntegration userNotificationCenterWithCenter:center willPresentNotification:notification withCompletionHandler:^(UNNotificationPresentationOptions options) {}];
[UAAppIntegration userNotificationCenter:center willPresentNotification:notification withCompletionHandler:^(UNNotificationPresentationOptions options) {}];

MPKitExecStatus *execStatus = [[MPKitExecStatus alloc] initWithSDKCode:[MPKitUrbanAirship kitCode] returnCode:MPKitReturnCodeSuccess];
return execStatus;
}

- (nonnull MPKitExecStatus *)userNotificationCenter:(nonnull UNUserNotificationCenter *)center didReceiveNotificationResponse:(nonnull UNNotificationResponse *)response API_AVAILABLE(ios(10.0)){
[UAAppIntegration userNotificationCenterWithCenter:center didReceiveNotificationResponse:response withCompletionHandler:^{}];
[UAAppIntegration userNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:^{}];

MPKitExecStatus *execStatus = [[MPKitExecStatus alloc] initWithSDKCode:[MPKitUrbanAirship kitCode] returnCode:MPKitReturnCodeSuccess];
return execStatus;
Expand Down