Skip to content

Commit fd06483

Browse files
authored
Merge pull request #1022 from OneSignal/track_cold_restarts
Track cold restarts with track endpoint
2 parents fc53bf2 + 6f5f945 commit fd06483

File tree

6 files changed

+88
-0
lines changed

6 files changed

+88
-0
lines changed

iOS_SDK/OneSignalSDK/Source/OneSignal.m

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1678,6 +1678,7 @@ + (BOOL)isRegisterUserSuccessful {
16781678
return _registerUserSuccessful || isOnSessionSuccessfulForCurrentState;
16791679
}
16801680

1681+
static BOOL _trackedColdRestart = false;
16811682
+ (BOOL)shouldRegisterNow {
16821683
// return if the user has not granted privacy permissions
16831684
if ([self shouldLogMissingPrivacyConsentErrorWithMethodName:nil])
@@ -1709,9 +1710,32 @@ + (BOOL)shouldRegisterNow {
17091710
// Make sure last time we closed app was more than 30 secs ago
17101711
const int minTimeThreshold = 30;
17111712
NSTimeInterval delta = now - lastTimeClosed;
1713+
1714+
// Tracking cold starts within 30 seconds of last close.
1715+
// Depending on the results of our tracking we will change this case
1716+
// from a tracking request to return true
1717+
if (delta < minTimeThreshold && appId && !_registerUserFinished && !_trackedColdRestart) {
1718+
[OneSignal trackColdRestart];
1719+
}
17121720
return delta >= minTimeThreshold;
17131721
}
17141722

1723+
+ (void)trackColdRestart {
1724+
[OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"trackColdRestart"];
1725+
// Set to true even if it doesn't pass the sample check
1726+
_trackedColdRestart = true;
1727+
// Sample /track calls to avoid hitting our endpoint too hard
1728+
int randomSample = arc4random_uniform(100);
1729+
if (randomSample == 99) {
1730+
NSString *osUsageData = [NSString stringWithFormat:@"kind=sdk, version=%@, source=iOS_SDK, name=cold_restart, lockScreenApp=false", ONESIGNAL_VERSION];
1731+
[[OneSignalClient sharedClient] executeRequest:[OSRequestTrackV1 trackUsageData:osUsageData appId:appId] onSuccess:^(NSDictionary *result) {
1732+
[OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"trackColdRestart: successfully tracked cold restart"];
1733+
} onFailure:^(NSError *error) {
1734+
[OneSignal onesignal_Log:ONE_S_LL_ERROR message:[NSString stringWithFormat:@"trackColdRestart: Failed to track cold restart: %@", error.localizedDescription]];
1735+
}];
1736+
}
1737+
}
1738+
17151739
+ (void)registerUserAfterDelay {
17161740
[OneSignal onesignal_Log:ONE_S_LL_VERBOSE message:@"registerUserAfterDelay"];
17171741
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(registerUser) object:nil];

iOS_SDK/OneSignalSDK/Source/OneSignalRequest.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
@property (nonatomic) HTTPMethod method;
3939
@property (strong, nonatomic, nonnull) NSString *path;
4040
@property (strong, nonatomic, nullable) NSDictionary *parameters;
41+
@property (strong, nonatomic, nullable) NSDictionary<NSString *, NSString *> *additionalHeaders;
4142
@property (nonatomic) int reattemptCount;
4243
@property (nonatomic) BOOL dataRequest; //false for JSON based requests
4344
-(BOOL)missingAppId; //for requests that don't require an appId parameter, the subclass should override this method and return false

iOS_SDK/OneSignalSDK/Source/OneSignalRequest.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ -(NSMutableURLRequest *)urlRequest {
6060

6161
let request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
6262

63+
for (NSString *key in self.additionalHeaders) {
64+
[request setValue:self.additionalHeaders[key] forHTTPHeaderField:key];
65+
}
66+
6367
if (!self.dataRequest)
6468
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
6569

iOS_SDK/OneSignalSDK/Source/Requests.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,5 +203,9 @@ NS_ASSUME_NONNULL_END
203203
+ (instancetype _Nonnull)withPlayerId:(NSString * _Nullable)playerId notificationId:(NSString * _Nonnull)notificationId appId:(NSString * _Nonnull)appId;
204204
@end
205205

206+
@interface OSRequestTrackV1 : OneSignalRequest
207+
+ (instancetype _Nonnull)trackUsageData:(NSString * _Nonnull)osUsageData
208+
appId:(NSString * _Nonnull)appId;
209+
@end
206210
#endif /* Requests_h */
207211

iOS_SDK/OneSignalSDK/Source/Requests.m

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,3 +749,20 @@ + (instancetype)measureOutcomeEvent:(OSOutcomeEventParams *)outcome appId:(NSStr
749749
return request;
750750
}
751751
@end
752+
753+
@implementation OSRequestTrackV1
754+
NSString * const OS_USAGE_DATA = @"OS-Usage-Data";
755+
+ (instancetype)trackUsageData:(NSString *)osUsageData appId:(NSString *)appId {
756+
let request = [OSRequestTrackV1 new];
757+
let params = [NSMutableDictionary new];
758+
let headers = [NSMutableDictionary new];
759+
params[APP_ID] = appId;
760+
headers[APP_ID] = appId;
761+
headers[OS_USAGE_DATA] = osUsageData;
762+
request.method = POST;
763+
request.path = @"v1/track";
764+
request.parameters = params;
765+
request.additionalHeaders = headers;
766+
return request;
767+
}
768+
@end

iOS_SDK/OneSignalSDK/UnitTests/RequestTests.m

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,10 @@ BOOL checkHttpBody(NSData *bodyData, NSDictionary *correct) {
167167
return dictionariesAreEquivalent(serialized, correct);
168168
}
169169

170+
BOOL checkHttpHeaders(NSDictionary *additionalHeaders, NSDictionary *correct) {
171+
return dictionariesAreEquivalent(additionalHeaders, correct);
172+
}
173+
170174
- (void)testBuildGetTags {
171175
let request = [OSRequestGetTags withUserId:testUserId appId:testAppId];
172176

@@ -743,4 +747,38 @@ - (void)testSendExternalWithAuthUserId {
743747
XCTAssertTrue(checkHttpBody(request.urlRequest.HTTPBody, @{@"app_id" : testAppId, @"external_user_id" : testExternalUserId, @"external_user_id_auth_hash" : testExternalUserIdHashToken}));
744748
}
745749

750+
- (void)testSendTrackUsageRequest {
751+
NSString *testUsageData = @"test usage data";
752+
let request = [OSRequestTrackV1 trackUsageData:testUsageData appId:testAppId];
753+
let correctUrl = correctUrlWithPath(@"v1/track");
754+
755+
XCTAssertTrue([correctUrl isEqualToString:request.urlRequest.URL.absoluteString]);
756+
XCTAssertTrue(checkHttpBody(request.urlRequest.HTTPBody, @{@"app_id" : testAppId}));
757+
XCTAssertTrue(checkHttpHeaders(request.additionalHeaders, @{@"app_id" : testAppId,
758+
@"OS-Usage-Data" : testUsageData,
759+
}));
760+
}
761+
762+
- (void)testAdditionalHeaders {
763+
// Create a fake request
764+
let request = [OneSignalRequest new];
765+
let params = [NSMutableDictionary new];
766+
let headers = [NSMutableDictionary new];
767+
params[@"app_id"] = testAppId;
768+
headers[@"app_id"] = testAppId;
769+
headers[@"test-header"] = @"test_header_value";
770+
request.method = POST;
771+
request.path = @"test/path";
772+
request.parameters = params;
773+
request.additionalHeaders = headers;
774+
775+
// Properties must be set in the request before accessing urlRequest
776+
let urlRequest = request.urlRequest;
777+
let requestHeaders = urlRequest.allHTTPHeaderFields;
778+
// Verify that all headers we added via additionalHeaders are in the request's header fields
779+
for (NSString *key in headers) {
780+
XCTAssertTrue(requestHeaders[key] != nil);
781+
}
782+
}
783+
746784
@end

0 commit comments

Comments
 (0)