Skip to content

Commit

Permalink
Merge pull request #225 from apptentive/branch_5.2.3
Browse files Browse the repository at this point in the history
Release 5.2.3
  • Loading branch information
frankus authored Nov 28, 2018
2 parents 978b403 + d6f1cbf commit 85423d0
Show file tree
Hide file tree
Showing 24 changed files with 312 additions and 36 deletions.
23 changes: 17 additions & 6 deletions Apptentive/Apptentive.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@
01798C021EAF94FE00633164 /* ApptentivePayloadSender.h in Headers */ = {isa = PBXBuildFile; fileRef = 01798C001EAF94FD00633164 /* ApptentivePayloadSender.h */; };
01798C031EAF94FE00633164 /* ApptentivePayloadSender.m in Sources */ = {isa = PBXBuildFile; fileRef = 01798C011EAF94FD00633164 /* ApptentivePayloadSender.m */; };
017E54ED1F3B860E00EA9F81 /* ApptentiveJSONSerializationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 017E54EC1F3B860E00EA9F81 /* ApptentiveJSONSerializationTests.m */; };
018E1CE021936B1400E58F33 /* ApptentiveEngagementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 018E1CDF21936B1300E58F33 /* ApptentiveEngagementTests.swift */; };
018E1CE321936B6600E58F33 /* conversation-4.archive in Resources */ = {isa = PBXBuildFile; fileRef = 018E1CE121936B6600E58F33 /* conversation-4.archive */; };
018E1CE421936B6600E58F33 /* conversation-5.archive in Resources */ = {isa = PBXBuildFile; fileRef = 018E1CE221936B6600E58F33 /* conversation-5.archive */; };
018FAFDF1FC4A9C6007C52FE /* ApptentiveAndClause.h in Headers */ = {isa = PBXBuildFile; fileRef = 018FAFDD1FC4A9C6007C52FE /* ApptentiveAndClause.h */; };
018FAFE01FC4A9C6007C52FE /* ApptentiveAndClause.m in Sources */ = {isa = PBXBuildFile; fileRef = 018FAFDE1FC4A9C6007C52FE /* ApptentiveAndClause.m */; };
018FAFE31FC4AC41007C52FE /* ApptentiveOrClause.h in Headers */ = {isa = PBXBuildFile; fileRef = 018FAFE11FC4AC41007C52FE /* ApptentiveOrClause.h */; };
Expand Down Expand Up @@ -512,6 +515,9 @@
01798C001EAF94FD00633164 /* ApptentivePayloadSender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApptentivePayloadSender.h; sourceTree = "<group>"; };
01798C011EAF94FD00633164 /* ApptentivePayloadSender.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ApptentivePayloadSender.m; sourceTree = "<group>"; };
017E54EC1F3B860E00EA9F81 /* ApptentiveJSONSerializationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ApptentiveJSONSerializationTests.m; sourceTree = "<group>"; };
018E1CDF21936B1300E58F33 /* ApptentiveEngagementTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApptentiveEngagementTests.swift; sourceTree = "<group>"; };
018E1CE121936B6600E58F33 /* conversation-4.archive */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = "conversation-4.archive"; sourceTree = "<group>"; };
018E1CE221936B6600E58F33 /* conversation-5.archive */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; path = "conversation-5.archive"; sourceTree = "<group>"; };
018FAFDD1FC4A9C6007C52FE /* ApptentiveAndClause.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ApptentiveAndClause.h; sourceTree = "<group>"; };
018FAFDE1FC4A9C6007C52FE /* ApptentiveAndClause.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ApptentiveAndClause.m; sourceTree = "<group>"; };
018FAFE11FC4AC41007C52FE /* ApptentiveOrClause.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ApptentiveOrClause.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1024,6 +1030,7 @@
01A2CF9E1E49062800C2103A /* ApptentiveTests */ = {
isa = PBXGroup;
children = (
01917D431E5E0B7400B37D82 /* ApptentiveTests-Bridging-Header.h */,
01201AD21FC637BD00EB3593 /* CodePointAndInteractionTests.m */,
EF4EABA22040A8C5003318C9 /* utils */,
01A2D20F1E4946D500C2103A /* data */,
Expand All @@ -1041,7 +1048,6 @@
01A2D2071E4946D500C2103A /* ApptentiveMigrationTests.m */,
01A2D2091E4946D500C2103A /* ApptentiveStyleSheetTests.m */,
01A2D20A1E4946D500C2103A /* ApptentiveSurveyTests.m */,
01917D431E5E0B7400B37D82 /* ApptentiveTests-Bridging-Header.h */,
01A2D20B1E4946D500C2103A /* ApptentiveUtilitiesTests.m */,
01917D441E5E0B7400B37D82 /* ConversationManagerTests.swift */,
01A2D20D1E4946D500C2103A /* CriteriaTests.h */,
Expand All @@ -1053,6 +1059,7 @@
0123005E20531698000EC3C3 /* ClauseTests.m */,
EF4EAB99203F9821003318C9 /* AppptentiveAsyncLogWriterTests.swift */,
012ED92B2072FABE003D87F3 /* RetryPolicyTests.swift */,
018E1CDF21936B1300E58F33 /* ApptentiveEngagementTests.swift */,
);
path = ApptentiveTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -1645,6 +1652,8 @@
01A2D20F1E4946D500C2103A /* data */ = {
isa = PBXGroup;
children = (
018E1CE121936B6600E58F33 /* conversation-4.archive */,
018E1CE221936B6600E58F33 /* conversation-5.archive */,
EFF4D2A51EC37F0A00FD4EFE /* containers */,
01A2D2161E4946D500C2103A /* criteria */,
01A2D2101E4946D500C2103A /* ATDataModelv1.sqlite */,
Expand Down Expand Up @@ -2081,6 +2090,8 @@
01A2D2551E4946D600C2103A /* testCornerCasesThatShouldBeFalse.json in Resources */,
01A2D2531E4946D600C2103A /* testCodePointInvokesVersion.json in Resources */,
01A2D25F1E4946D600C2103A /* testOperatorGreaterThanOrEqual.json in Resources */,
018E1CE321936B6600E58F33 /* conversation-4.archive in Resources */,
018E1CE421936B6600E58F33 /* conversation-5.archive in Resources */,
01A2D25B1E4946D600C2103A /* testOperatorContains.json in Resources */,
01A2D24E1E4946D600C2103A /* ATDataModelv3.sqlite in Resources */,
01A2D26A1E4946D600C2103A /* testJsonDiffing.1.new.json in Resources */,
Expand Down Expand Up @@ -2280,6 +2291,7 @@
EFF4D2AC1EC39EC000FD4EFE /* ApptentiveAppDataContainer.m in Sources */,
01A2D2481E4946D600C2103A /* ApptentiveSurveyTests.m in Sources */,
01A2D29B1E4963A500C2103A /* ATDataModel v3 to v4.xcmappingmodel in Sources */,
018E1CE021936B1400E58F33 /* ApptentiveEngagementTests.swift in Sources */,
0174772F1EA92D7D00A0A949 /* PayloadTests.swift in Sources */,
01201AD31FC637BE00EB3593 /* CodePointAndInteractionTests.m in Sources */,
01A2D2451E4946D600C2103A /* ApptentiveMigrationTests.m in Sources */,
Expand Down Expand Up @@ -2382,7 +2394,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 20;
CURRENT_PROJECT_VERSION = 23;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
Expand Down Expand Up @@ -2440,7 +2452,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 20;
CURRENT_PROJECT_VERSION = 23;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
Expand Down Expand Up @@ -2472,7 +2484,7 @@
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 86WML2UN43;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 20;
DYLIB_CURRENT_VERSION = 23;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_PREFIX_HEADER = "Apptentive/Misc/ApptentiveConnect-Prefix.pch";
GCC_PREPROCESSOR_DEFINITIONS = "APPTENTIVE_DEBUG=1";
Expand All @@ -2494,7 +2506,7 @@
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 86WML2UN43;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 20;
DYLIB_CURRENT_VERSION = 23;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_PREFIX_HEADER = "Apptentive/Misc/ApptentiveConnect-Prefix.pch";
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
Expand Down Expand Up @@ -2538,7 +2550,6 @@
};
name = Release;
};

/* End XCBuildConfiguration section */

/* Begin XCConfigurationList section */
Expand Down
2 changes: 1 addition & 1 deletion Apptentive/Apptentive/Apptentive.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ FOUNDATION_EXPORT double ApptentiveVersionNumber;
FOUNDATION_EXPORT const unsigned char ApptentiveVersionString[];

/** The version number of the Apptentive SDK. */
#define kApptentiveVersionString @"5.2.2"
#define kApptentiveVersionString @"5.2.3"

/** The version number of the Apptentive API platform. */
#define kApptentiveAPIVersionString @"9"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,8 @@ - (BOOL)updateActiveConversation:(ApptentiveConversation *)conversation withResp

[self saveConversation:self.activeConversation];

self.messageManager.conversation = self.activeConversation;

[self handleConversationStateChange:self.activeConversation];

[self updateManifestIfNeeded];
Expand Down Expand Up @@ -854,10 +856,15 @@ - (BOOL)updateLegacyConversation:(ApptentiveConversation *)conversation withResp
mutableConversation.state = ApptentiveConversationStateAnonymous;
}

[self.messageManager stop];

self.activeConversation = mutableConversation;
self.activeConversation.delegate = self;

[self saveConversation:self.activeConversation];

self.messageManager.conversation = self.activeConversation;

[self handleConversationStateChange:self.activeConversation];

[self updateManifestIfNeeded];
Expand Down
12 changes: 12 additions & 0 deletions Apptentive/Apptentive/Engagement/Model/ApptentiveCount.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,18 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)invoke;


/**
Adds the values from `otherCount` to the current object.
@param oldCount The older count object, presumably from a previous version.
@param newCount The newer count object, which would have been invoked last.
@return The sum of the two count objects.
@discussion If either is nil, the other one is returned. If both are nil, nil is returned.
*/
+ (ApptentiveCount *)mergeOldCount:(nullable ApptentiveCount *)oldCount withNewCount:(nullable ApptentiveCount *)newCount;

@end

NS_ASSUME_NONNULL_END
10 changes: 10 additions & 0 deletions Apptentive/Apptentive/Engagement/Model/ApptentiveCount.m
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,16 @@ - (NSString *)description {
return [NSString stringWithFormat:@"[%@] totalCount=%ld versionCount=%ld buildCount=%ld lastInvoked=%@", NSStringFromClass([self class]), (unsigned long)_totalCount, (unsigned long)_versionCount, (unsigned long)_buildCount, _lastInvoked];
}

// This is used for migrating version 5.1.0 through 5.2.2 (with unescaped code points) to 5.2.3 and later.
+ (ApptentiveCount *)mergeOldCount:(nullable ApptentiveCount *)oldCount withNewCount:(nullable ApptentiveCount *)newCount {
NSInteger totalCount = oldCount.totalCount + newCount.totalCount;
NSInteger versionCount = newCount.versionCount; // Old count is likely to be for a different version
NSInteger buildCount = newCount.buildCount; // Old count is likely to be for a different build
NSDate *lastInvoked = newCount.lastInvoked ?: oldCount.lastInvoked; // New count, if present, will have been invoked last

return [[ApptentiveCount alloc] initWithTotalCount:totalCount versionCount:versionCount buildCount:buildCount lastInvoked:lastInvoked];
}

@end


Expand Down
4 changes: 4 additions & 0 deletions Apptentive/Apptentive/Engagement/Model/ApptentiveEngagement.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)resetBuild;

// Test only
+ (nullable NSString *)escapedKeyForKey:(NSString *)key;
@property (readonly, nonatomic) NSInteger version;

@end

NS_ASSUME_NONNULL_END
92 changes: 90 additions & 2 deletions Apptentive/Apptentive/Engagement/Model/ApptentiveEngagement.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@

#import "ApptentiveEngagement.h"
#import "ApptentiveCount.h"
#import "ApptentiveBackend+Engagement.h"

NS_ASSUME_NONNULL_BEGIN

static NSString *const InteractionsKey = @"interactions";
static NSString *const CodePointsKey = @"codePoints";
static NSString *const VersionKey = @"version";

// Legacy keys
static NSString *const ATEngagementCodePointsInvokesTotalKey = @"ATEngagementCodePointsInvokesTotalKey";
Expand All @@ -23,23 +25,24 @@
static NSString *const ATEngagementInteractionsInvokesVersionKey = @"ATEngagementInteractionsInvokesVersionKey";
static NSString *const ATEngagementInteractionsInvokesBuildKey = @"ATEngagementInteractionsInvokesBuildKey";
static NSString *const ATEngagementInteractionsInvokesLastDateKey = @"ATEngagementInteractionsInvokesLastDateKey";

static NSInteger const CurrentVersion = 2;

@interface ApptentiveEngagement ()

@property (strong, nonatomic) NSMutableDictionary<NSString *, ApptentiveCount *> *mutableInteractions;
@property (strong, nonatomic) NSMutableDictionary<NSString *, ApptentiveCount *> *mutableCodePoints;
@property (assign, nonatomic) NSInteger version;

@end


@implementation ApptentiveEngagement

- (instancetype)init {
self = [super init];
if (self) {
_mutableInteractions = [NSMutableDictionary dictionary];
_mutableCodePoints = [NSMutableDictionary dictionary];
_version = CurrentVersion;
}
return self;
}
Expand All @@ -49,6 +52,20 @@ - (nullable instancetype)initWithCoder:(NSCoder *)coder {
if (self) {
_mutableInteractions = [coder decodeObjectOfClass:[NSMutableDictionary class] forKey:InteractionsKey];
_mutableCodePoints = [coder decodeObjectOfClass:[NSMutableDictionary class] forKey:CodePointsKey];
if ([coder containsValueForKey:VersionKey]) {
_version = [coder decodeIntegerForKey:VersionKey];
} else {
_version = 1;
}

@try {
if (_version != CurrentVersion) {
[self migrateFrom:_version to:CurrentVersion];
}
} @catch(NSException *exception) {
ApptentiveLogError(ApptentiveLogTagConversation, @"Caught exception %e when migrating engagement data. Starting over.", exception);
return [self init];
}
}
return self;
}
Expand All @@ -57,8 +74,10 @@ - (void)encodeWithCoder:(NSCoder *)coder {
[super encodeWithCoder:coder];
[coder encodeObject:self.mutableInteractions forKey:InteractionsKey];
[coder encodeObject:self.mutableCodePoints forKey:CodePointsKey];
[coder encodeInteger:self.version forKey:VersionKey];
}

// This migrates pre-4.0 data stored in NSUserDefaults to 4.0 and later versions stored in NSCoding archive
- (instancetype)initAndMigrate {
self = [self init];

Expand Down Expand Up @@ -96,6 +115,75 @@ + (void)deleteMigratedData {
[[NSUserDefaults standardUserDefaults] removeObjectForKey:ATEngagementInteractionsInvokesLastDateKey];
}

- (void)migrateFrom:(NSInteger)fromVersion to:(NSInteger)toVersion {
if (fromVersion == 1 && toVersion == 2) {
if ([self escapeUnescapedKeysInCodePoints]) {
_version = toVersion;
}
}
}

- (BOOL)escapeUnescapedKeysInCodePoints {
NSMutableArray *codePointsToMerge = [NSMutableArray array];

for (NSString *key in self.codePoints) {
NSString *escapedKey = [[self class] escapedKeyForKey:key];

if (escapedKey == nil) {
continue;
}

[codePointsToMerge addObject:@[key, escapedKey]];
}

NSMutableDictionary *escapedCodePoints = [NSMutableDictionary dictionaryWithDictionary:self.codePoints];
for (NSArray *keys in codePointsToMerge) {
NSString *key = keys[0];
NSString *escapedKey = keys[1];

ApptentiveCount *oldCount = [self.codePoints objectForKey:key];
ApptentiveCount *newCount = [self.codePoints objectForKey:escapedKey];
escapedCodePoints[escapedKey] = [ApptentiveCount mergeOldCount:oldCount withNewCount:newCount];
[escapedCodePoints removeObjectForKey:key];
}

_mutableCodePoints = escapedCodePoints;

return YES;
}

+ (nullable NSString *)escapedKeyForKey:(NSString *)key {
NSArray *keyParts = [key componentsSeparatedByString:@"#"];

if (keyParts.count < 3) {
ApptentiveLogWarning(ApptentiveLogTagConversation, @"Unable to migrate unencoded code point %@", key);
return nil;
}

NSString *vendor = keyParts[0];
NSString *interaction = keyParts[1];
// If the event name had pound signs in it, then there will be two or more parts starting at index 2.
// We join those parts with a pound sign, which conveniently no-ops in the case of a single part.
NSString *event = [[keyParts subarrayWithRange:NSMakeRange(2, keyParts.count - 2)] componentsJoinedByString:@"#"];

if ([[self class] eventNeedsEscaping:event]) {
return [ApptentiveBackend codePointForVendor:vendor interactionType:interaction event:event];
} else {
return nil;
}
}

// Use some heuristics to see if the event name needs to be escaped and hasn't already been escaped
+ (BOOL)eventNeedsEscaping:(NSString *)event {
// Slashes definitey need escaping
BOOL slashesFound = [event containsString:@"/"];
// Pound signs definitely need escaping
BOOL poundSignsFound = [event containsString:@"#"];
// Third-party percent signs would also need escaping, but there aren't instances of those in our events database, so we good.

return slashesFound || poundSignsFound;
}

- (NSDictionary<NSString *, ApptentiveCount *> *)interactions {
return [NSDictionary dictionaryWithDictionary:self.mutableInteractions];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,6 @@

NS_ASSUME_NONNULL_BEGIN

extern NSString *const ATEngagementInstallDateKey;
extern NSString *const ATEngagementUpgradeDateKey;
extern NSString *const ATEngagementLastUsedVersionKey;
extern NSString *const ATEngagementIsUpdateVersionKey;
extern NSString *const ATEngagementIsUpdateBuildKey;
extern NSString *const ATEngagementCodePointsInvokesTotalKey;
extern NSString *const ATEngagementCodePointsInvokesVersionKey;
extern NSString *const ATEngagementCodePointsInvokesBuildKey;
extern NSString *const ATEngagementCodePointsInvokesLastDateKey;
extern NSString *const ATEngagementInteractionsInvokesTotalKey;
extern NSString *const ATEngagementInteractionsInvokesVersionKey;
extern NSString *const ATEngagementInteractionsInvokesBuildKey;
extern NSString *const ATEngagementInteractionsInvokesLastDateKey;
extern NSString *const ATEngagementInteractionsSDKVersionKey;

extern NSString *const ATEngagementCodePointHostAppVendorKey;
extern NSString *const ATEngagementCodePointHostAppInteractionKey;
extern NSString *const ATEngagementCodePointApptentiveVendorKey;
Expand All @@ -45,6 +30,7 @@ extern NSString *const ApptentiveEngagementMessageCenterEvent;
- (BOOL)canShowInteractionForCodePoint:(NSString *)codePoint;

+ (NSString *)codePointForVendor:(NSString *)vendor interactionType:(NSString *)interactionType event:(NSString *)event;
+ (NSString *)stringByEscapingCodePointSeparatorCharactersInString:(NSString *)string;

- (void)engageApptentiveAppEvent:(NSString *)event;
- (void)engageLocalEvent:(NSString *)event userInfo:(nullable NSDictionary *)userInfo customData:(nullable NSDictionary *)customData extendedData:(nullable NSArray *)extendedData fromViewController:(nullable UIViewController *)viewController;
Expand Down
Loading

0 comments on commit 85423d0

Please sign in to comment.