Skip to content

Commit

Permalink
Prepare for release 3.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
chshapiro committed Apr 7, 2020
1 parent 39e7ece commit a1facb6
Show file tree
Hide file tree
Showing 15 changed files with 332 additions and 33 deletions.
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
## 3.0.0

##### Breaking
- Log separate purchases for each product in the `products` array in a `track` call.
- In the past we used the event name as the product ID.
- Now if a `track` call has the event name `Order Completed` or the key `revenue` included in `properties` and also has a `products` array, we will log each object in the array as a separate purchase using `productId` as the product ID. `price` and `quantity` will be read from the individual array if available. All non-Braze recognized fields from the high level `properties` and each individual product will be combined and sent as event properties.
- If there is no `products` array we will continue using the event name as the product ID if the key `revenue` is included in `properties`.

##### Added
- Added a push delegate method for apps using the `UserNotification` framework.
- Follow our [documentation](https://www.braze.com/docs/developer_guide/platform_integration_guides/ios/push_notifications/integration/#using-usernotification-framework-ios-10) for registering for push notifications using the `UserNotification` framework.
- In `userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler` add the following block of code:
```
if ([Appboy sharedInstance] == nil) {
[[SEGAppboyIntegrationFactory instance].appboyHelper saveUserNotificationCenter:center
notificationResponse:response];
}
[[SEGAppboyIntegrationFactory instance].appboyHelper userNotificationCenter:center
receivedNotificationResponse:response];
if (completionHandler) {
completionHandler();
}
```

## 2.3.0

##### Changed
Expand Down
35 changes: 35 additions & 0 deletions Example/Segment-Appboy.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,43 @@
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
Base,
de,
he,
ar,
"zh-Hans",
ja,
"zh-TW",
"zh-HK",
nb,
es,
da,
"es-419",
et,
it,
ms,
sv,
km,
ko,
fil,
"zh-Hant",
my,
pl,
vi,
lo,
"es-MX",
ru,
fr,
fi,
id,
nl,
th,
pt,
"pt-PT",
hi,
zh,
);
mainGroup = 6003F581195388D10070C39A;
productRefGroup = 6003F58B195388D20070C39A /* Products */;
Expand Down
3 changes: 2 additions & 1 deletion Example/Segment-Appboy/SEGAppDelegate.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@import UIKit;
#import <UserNotifications/UserNotifications.h>

@interface SEGAppDelegate : UIResponder <UIApplicationDelegate>
@interface SEGAppDelegate : UIResponder <UIApplicationDelegate, UNUserNotificationCenterDelegate>

@property (strong, nonatomic) UIWindow *window;

Expand Down
48 changes: 37 additions & 11 deletions Example/Segment-Appboy/SEGAppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@

@implementation SEGAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
SEGAnalyticsConfiguration *config = [SEGAnalyticsConfiguration configurationWithWriteKey:@"xNAmGpyITen4FEZg9C2ES6r2iYm8Ommk"];
[config use:[SEGAppboyIntegrationFactory instance]];
[[SEGAppboyIntegrationFactory instance] saveLaunchOptions:launchOptions];
Expand Down Expand Up @@ -45,8 +44,7 @@ - (void)applicationWillTerminate:(UIApplication *)application
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
[[SEGAnalytics sharedAnalytics] receivedRemoteNotification:userInfo];
}

Expand All @@ -58,13 +56,25 @@ - (void)application:(UIApplication *)application didReceiveRemoteNotification:(N
completionHandler(UIBackgroundFetchResultNoData);
}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void (^)(void))completionHandler {
if ([Appboy sharedInstance] == nil) {
[[SEGAppboyIntegrationFactory instance].appboyHelper saveUserNotificationCenter:center
notificationResponse:response];
}
[[SEGAppboyIntegrationFactory instance].appboyHelper userNotificationCenter:center
receivedNotificationResponse:response];
if (completionHandler) {
completionHandler();
}
}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[[SEGAnalytics sharedAnalytics] registeredForRemoteNotificationsWithDeviceToken:deviceToken];
}

- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler
{
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler {
if ([Appboy sharedInstance] == nil) {
[[SEGAppboyIntegrationFactory instance] saveRemoteNotification:userInfo];
}
Expand Down Expand Up @@ -92,8 +102,24 @@ - (void)setupPushCategories {
[likeCategory setActions:@[likeAction, unlikeAction] forContext:UIUserNotificationActionContextDefault];

NSSet *categories = [NSSet setWithObjects:likeCategory, nil];
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge|UIUserNotificationTypeAlert | UIUserNotificationTypeSound) categories:categories];
[[UIApplication sharedApplication] registerForRemoteNotifications];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];

if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_9_x_Max) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
UNAuthorizationOptions options = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
if (@available(iOS 12.0, *)) {
options = options | UNAuthorizationOptionProvisional;
}
[center requestAuthorizationWithOptions:options
completionHandler:^(BOOL granted, NSError * _Nullable error) {
[[Appboy sharedInstance] pushAuthorizationFromUserNotificationCenter:granted];
}];
[[UIApplication sharedApplication] registerForRemoteNotifications];
} else {
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound) categories:categories];
[[UIApplication sharedApplication] registerForRemoteNotifications];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
}
}

@end
26 changes: 26 additions & 0 deletions Example/Segment-Appboy/SEGViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,32 @@ - (IBAction)trackButtonPress:(id)sender {
properties:@{ @"currency": @"CNY", @"revenue" : numberRevenue, @"property" : @"milky white rabbit"}];
[[SEGAnalytics sharedAnalytics] track:@"Purchase"
properties:@{ @"currency": @"CNY", @"revenue" : stringRevenue, @"property" : @"myProperty"}];
[[SEGAnalytics sharedAnalytics] track:@"Order Completed"
properties:@{@"currency": @"CNY",
@"revenue" : numberRevenue,
@"products" : @[@{@"productId" : @"cookies",
@"price" : @"72.3",
@"quantity" : @(29),
@"cookieType" : @"chocolateChip"
},
@{@"productId" : @"muffins",
@"price" : @"24.2",
@"quantity" : @(17),
@"muffinType" : @"blueberry"
}],
@"purchaseType" : @"productsArray"
}];
[[SEGAnalytics sharedAnalytics] track:@"Order Completed"
properties:@{@"currency" : @"USD",
@"products" : @[@{@"productId" : @"phone",
@"price" : @"199.99",
@"quantity" : @(2),
@"phoneType" : @"iPhoneX"},
@{@"productId" : @"tablet",
@"price" : @"149.99",
@"quantity" : @(3),
@"tabletType" : @"iPad"}],
@"store" : @"appleStore"}];
[[SEGAnalytics sharedAnalytics] track:@"Install Attributed"
properties: @{@"provider" : @"Tune/Kochava/Branch",
@"campaign" : @{@"source" : @"Network/FB/AdWords/MoPub/Source",
Expand Down
49 changes: 39 additions & 10 deletions Example/Tests/SEGAppboyIntegrationTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
it(@"initializes appboy if an apiKey is passed", ^{
NSDictionary *settings = @{@"apiKey":@"foo"};
id appboyMock = OCMClassMock([Appboy class]);
OCMExpect([appboyMock startWithApiKey:@"foo" inApplication:[OCMArg any] withLaunchOptions:nil]);
OCMExpect([appboyMock startWithApiKey:@"foo" inApplication:[OCMArg any] withLaunchOptions:nil withAppboyOptions:[OCMArg any]]);
SEGAppboyIntegration *appboyIntegration = [[SEGAppboyIntegration alloc] initWithSettings:settings];
OCMVerifyAllWithDelay(appboyMock, 2);
});
Expand All @@ -29,7 +29,7 @@
id appboyUserMock = OCMClassMock([ABKUser class]);
OCMStub([appboyMock sharedInstance]).andReturn(appboyMock);
OCMStub([appboyMock user]).andReturn(appboyUserMock);
OCMExpect([appboyMock startWithApiKey:@"foo" inApplication:[OCMArg any] withLaunchOptions:nil]);
OCMExpect([appboyMock startWithApiKey:@"foo" inApplication:[OCMArg any] withLaunchOptions:nil withAppboyOptions:[OCMArg any]]);
OCMExpect([appboyMock changeUser:@"testUser"]);
OCMExpect([appboyUserMock setDateOfBirth:testDate]);
OCMExpect([appboyUserMock setEmail:@"[email protected]"]);
Expand Down Expand Up @@ -72,7 +72,7 @@
id appboyUserMock = OCMClassMock([ABKUser class]);
OCMStub([appboyMock sharedInstance]).andReturn(appboyMock);
OCMStub([appboyMock user]).andReturn(appboyUserMock);
OCMExpect([appboyMock startWithApiKey:@"foo" inApplication:[OCMArg any] withLaunchOptions:nil]);
OCMExpect([appboyMock startWithApiKey:@"foo" inApplication:[OCMArg any] withLaunchOptions:nil withAppboyOptions:[OCMArg any]]);
OCMExpect([appboyMock changeUser:@"testUser"]);

SEGAppboyIntegration *appboyIntegration = [[SEGAppboyIntegration alloc] initWithSettings:settings];
Expand Down Expand Up @@ -104,7 +104,7 @@
NSDictionary *settings = @{@"apiKey":@"foo"};
id appboyMock = OCMClassMock([Appboy class]);
OCMStub([appboyMock sharedInstance]).andReturn(appboyMock);
OCMExpect([appboyMock startWithApiKey:@"foo" inApplication:[OCMArg any] withLaunchOptions:nil]);
OCMExpect([appboyMock startWithApiKey:@"foo" inApplication:[OCMArg any] withLaunchOptions:nil withAppboyOptions:[OCMArg any]]);
OCMExpect([appboyMock logPurchase:@"testPurchase" inCurrency:@"USD" atPrice:[NSDecimalNumber decimalNumberWithString:@"55.5"]
withQuantity:1 andProperties:@{@"extraProperty" : @"extraValue"}]);

Expand All @@ -123,12 +123,42 @@
[appboyIntegration track:trackPayload];
OCMVerifyAllWithDelay(appboyMock, 2);
});

it(@"calls logPurchase for each product in the products array", ^{
NSDictionary *settings = @{@"apiKey":@"foo"};
id appboyMock = OCMClassMock([Appboy class]);
OCMStub([appboyMock sharedInstance]).andReturn(appboyMock);
OCMExpect([appboyMock startWithApiKey:@"foo" inApplication:[OCMArg any] withLaunchOptions:nil withAppboyOptions:[OCMArg any]]);
OCMExpect(([appboyMock logPurchase:@"product1" inCurrency:@"USD" atPrice:[NSDecimalNumber decimalNumberWithString:@"72.3"]
withQuantity:29 andProperties:@{@"extraProperty" : @"extraValue",
@"productProperty" : @"productValue"
}]));

SEGAppboyIntegration *appboyIntegration = [[SEGAppboyIntegration alloc] initWithSettings:settings];

NSDictionary *properties = @{
@"currency" : @"USD",
@"extraProperty" : @"extraValue",
@"products" : @[@{@"productId" : @"product1",
@"price" : @"72.3",
@"quantity" : @(29),
@"productProperty" : @"productValue"
}]
};

SEGTrackPayload *trackPayload = [[SEGTrackPayload alloc] initWithEvent:@"Order Completed"
properties:properties
context:nil
integrations:nil];
[appboyIntegration track:trackPayload];
OCMVerifyAllWithDelay(appboyMock, 2);
});

it(@"logs an event if there isn't revenue", ^{
NSDictionary *settings = @{@"apiKey":@"foo"};
id appboyMock = OCMClassMock([Appboy class]);
OCMStub([appboyMock sharedInstance]).andReturn(appboyMock);
OCMExpect([appboyMock startWithApiKey:@"foo" inApplication:[OCMArg any] withLaunchOptions:nil]);
OCMExpect([appboyMock startWithApiKey:@"foo" inApplication:[OCMArg any] withLaunchOptions:nil withAppboyOptions:[OCMArg any]]);
NSDictionary *propertiesDictionary = @{ @"asdf" : @1, @"extraProperty" : @"extraValue"};
OCMExpect([appboyMock logCustomEvent:@"testEvent" withProperties:propertiesDictionary]);

Expand All @@ -147,13 +177,12 @@
});
});


describe(@"flush", ^{
it(@"calls [[Appboy sharedInstance] flushDataAndProcessRequestQueue]", ^{
NSDictionary *settings = @{@"apiKey":@"foo"};
id appboyMock = OCMClassMock([Appboy class]);
OCMStub([appboyMock sharedInstance]).andReturn(appboyMock);
OCMExpect([appboyMock startWithApiKey:@"foo" inApplication:[OCMArg any] withLaunchOptions:nil]);
OCMExpect([appboyMock startWithApiKey:@"foo" inApplication:[OCMArg any] withLaunchOptions:nil withAppboyOptions:[OCMArg any]]);
OCMExpect([appboyMock flushDataAndProcessRequestQueue]);
SEGAppboyIntegration *appboyIntegration = [[SEGAppboyIntegration alloc] initWithSettings:settings];
[appboyIntegration flush];
Expand All @@ -167,8 +196,8 @@
NSData *registerData = [[NSData alloc] init];
id appboyMock = OCMClassMock([Appboy class]);
OCMStub([appboyMock sharedInstance]).andReturn(appboyMock);
OCMExpect([appboyMock startWithApiKey:@"foo" inApplication:[OCMArg any] withLaunchOptions:nil]);
OCMExpect([appboyMock registerPushToken:[OCMArg any]]);
OCMExpect([appboyMock startWithApiKey:@"foo" inApplication:[OCMArg any] withLaunchOptions:nil withAppboyOptions:[OCMArg any]]);
OCMExpect([appboyMock registerDeviceToken:[OCMArg any]]);
SEGAppboyIntegration *appboyIntegration = [[SEGAppboyIntegration alloc] initWithSettings:settings];
[appboyIntegration registeredForRemoteNotificationsWithDeviceToken:registerData];
OCMVerifyAllWithDelay(appboyMock, 2);
Expand All @@ -181,7 +210,7 @@
NSDictionary *userInfo = @{@"test":@"userInfo"};
id appboyMock = OCMClassMock([Appboy class]);
OCMStub([appboyMock sharedInstance]).andReturn(appboyMock);
OCMExpect([appboyMock startWithApiKey:@"foo" inApplication:[OCMArg any] withLaunchOptions:nil]);
OCMExpect([appboyMock startWithApiKey:@"foo" inApplication:[OCMArg any] withLaunchOptions:nil withAppboyOptions:[OCMArg any]]);
OCMExpect([appboyMock registerApplication:[OCMArg any] didReceiveRemoteNotification:userInfo]);
SEGAppboyIntegration *appboyIntegration = [[SEGAppboyIntegration alloc] initWithSettings:settings];
[appboyIntegration receivedRemoteNotification:userInfo];
Expand Down
33 changes: 33 additions & 0 deletions Example/fastlane/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
fastlane documentation
================
# Installation

Make sure you have the latest version of the Xcode command line tools installed:

```
xcode-select --install
```

Install _fastlane_ using
```
[sudo] gem install fastlane -NV
```
or alternatively using `brew cask install fastlane`

# Available Actions
### matchFullAccess
```
fastlane matchFullAccess
```

### matchReadOnly
```
fastlane matchReadOnly
```


----

This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run.
More information about fastlane can be found on [fastlane.tools](https://fastlane.tools).
The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools).
23 changes: 23 additions & 0 deletions Example/fastlane/report.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
<testsuite name="fastlane.lanes">




<testcase classname="fastlane.lanes" name="0: Verifying fastlane version" time="0.056385">

</testcase>


<testcase classname="fastlane.lanes" name="1: match" time="55.5746">

</testcase>


<testcase classname="fastlane.lanes" name="2: match" time="54.038703">

</testcase>

</testsuite>
</testsuites>
12 changes: 12 additions & 0 deletions Pod/Classes/SEGAppboyHelper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#import <Foundation/Foundation.h>
#import <UserNotifications/UserNotifications.h>

@interface SEGAppboyHelper : NSObject

- (void)applicationDidFinishLaunching;
- (void)saveUserNotificationCenter:(UNUserNotificationCenter *)center
notificationResponse:(UNNotificationResponse *)response NS_AVAILABLE_IOS(10_0);
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
receivedNotificationResponse:(UNNotificationResponse *)response NS_AVAILABLE_IOS(10_0);

@end
Loading

0 comments on commit a1facb6

Please sign in to comment.