Configured colours and added additional images to ready app for iOS 13 dark mode

This commit is contained in:
Deniz Duezgoeren
2019-10-08 21:37:42 +02:00
parent b7bc097664
commit 85efe3955d
310 changed files with 6512 additions and 4492 deletions
@@ -14,18 +14,18 @@
* limitations under the License.
*/
#import "GDTLibrary/Private/GDTAssert.h"
#import "GDTCORLibrary/Public/GDTCORAssert.h"
GDTAssertionBlock GDTAssertionBlockToRunInsteadOfNSAssert(void) {
GDTCORAssertionBlock GDTCORAssertionBlockToRunInstead(void) {
// This class is only compiled in by unit tests, and this should fail quickly in optimized builds.
Class GDTAssertClass = NSClassFromString(@"GDTAssertHelper");
if (__builtin_expect(!!GDTAssertClass, 0)) {
Class GDTCORAssertClass = NSClassFromString(@"GDTCORAssertHelper");
if (__builtin_expect(!!GDTCORAssertClass, 0)) {
SEL assertionBlockSEL = NSSelectorFromString(@"assertionBlock");
if (assertionBlockSEL) {
IMP assertionBlockIMP = [GDTAssertClass methodForSelector:assertionBlockSEL];
IMP assertionBlockIMP = [GDTCORAssertClass methodForSelector:assertionBlockSEL];
if (assertionBlockIMP) {
GDTAssertionBlock assertionBlock =
((GDTAssertionBlock(*)(id, SEL))assertionBlockIMP)(GDTAssertClass, assertionBlockSEL);
GDTCORAssertionBlock assertionBlock = ((GDTCORAssertionBlock(*)(id, SEL))assertionBlockIMP)(
GDTCORAssertClass, assertionBlockSEL);
if (assertionBlock) {
return assertionBlock;
}
@@ -14,7 +14,7 @@
* limitations under the License.
*/
#import "GDTLibrary/Public/GDTClock.h"
#import "GDTCORLibrary/Public/GDTCORClock.h"
#import <sys/sysctl.h>
@@ -74,7 +74,7 @@ static int64_t UptimeInNanoseconds() {
}
// TODO: Consider adding a 'trustedTime' property that can be populated by the response from a BE.
@implementation GDTClock
@implementation GDTCORClock
- (instancetype)init {
self = [super init];
@@ -90,17 +90,17 @@ static int64_t UptimeInNanoseconds() {
return self;
}
+ (GDTClock *)snapshot {
return [[GDTClock alloc] init];
+ (GDTCORClock *)snapshot {
return [[GDTCORClock alloc] init];
}
+ (instancetype)clockSnapshotInTheFuture:(uint64_t)millisInTheFuture {
GDTClock *snapshot = [self snapshot];
GDTCORClock *snapshot = [self snapshot];
snapshot->_timeMillis += millisInTheFuture;
return snapshot;
}
- (BOOL)isAfter:(GDTClock *)otherClock {
- (BOOL)isAfter:(GDTCORClock *)otherClock {
// These clocks are trivially comparable when they share a kernel boot time.
if (_kernelBootTime == otherClock->_kernelBootTime) {
int64_t timeDiff = (_timeMillis + _timezoneOffsetSeconds) -
@@ -126,16 +126,16 @@ static int64_t UptimeInNanoseconds() {
#pragma mark - NSSecureCoding
/** NSKeyedCoder key for timeMillis property. */
static NSString *const kGDTClockTimeMillisKey = @"GDTClockTimeMillis";
static NSString *const kGDTCORClockTimeMillisKey = @"GDTCORClockTimeMillis";
/** NSKeyedCoder key for timezoneOffsetMillis property. */
static NSString *const kGDTClockTimezoneOffsetSeconds = @"GDTClockTimezoneOffsetSeconds";
static NSString *const kGDTCORClockTimezoneOffsetSeconds = @"GDTCORClockTimezoneOffsetSeconds";
/** NSKeyedCoder key for _kernelBootTime ivar. */
static NSString *const kGDTClockKernelBootTime = @"GDTClockKernelBootTime";
static NSString *const kGDTCORClockKernelBootTime = @"GDTCORClockKernelBootTime";
/** NSKeyedCoder key for _uptime ivar. */
static NSString *const kGDTClockUptime = @"GDTClockUptime";
static NSString *const kGDTCORClockUptime = @"GDTCORClockUptime";
+ (BOOL)supportsSecureCoding {
return YES;
@@ -146,19 +146,19 @@ static NSString *const kGDTClockUptime = @"GDTClockUptime";
if (self) {
// TODO: If the kernelBootTime is more recent, we need to change the kernel boot time and
// uptimeMillis ivars
_timeMillis = [aDecoder decodeInt64ForKey:kGDTClockTimeMillisKey];
_timezoneOffsetSeconds = [aDecoder decodeInt64ForKey:kGDTClockTimezoneOffsetSeconds];
_kernelBootTime = [aDecoder decodeInt64ForKey:kGDTClockKernelBootTime];
_uptime = [aDecoder decodeInt64ForKey:kGDTClockUptime];
_timeMillis = [aDecoder decodeInt64ForKey:kGDTCORClockTimeMillisKey];
_timezoneOffsetSeconds = [aDecoder decodeInt64ForKey:kGDTCORClockTimezoneOffsetSeconds];
_kernelBootTime = [aDecoder decodeInt64ForKey:kGDTCORClockKernelBootTime];
_uptime = [aDecoder decodeInt64ForKey:kGDTCORClockUptime];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeInt64:_timeMillis forKey:kGDTClockTimeMillisKey];
[aCoder encodeInt64:_timezoneOffsetSeconds forKey:kGDTClockTimezoneOffsetSeconds];
[aCoder encodeInt64:_kernelBootTime forKey:kGDTClockKernelBootTime];
[aCoder encodeInt64:_uptime forKey:kGDTClockUptime];
[aCoder encodeInt64:_timeMillis forKey:kGDTCORClockTimeMillisKey];
[aCoder encodeInt64:_timezoneOffsetSeconds forKey:kGDTCORClockTimezoneOffsetSeconds];
[aCoder encodeInt64:_kernelBootTime forKey:kGDTCORClockKernelBootTime];
[aCoder encodeInt64:_uptime forKey:kGDTCORClockUptime];
}
@end
@@ -14,20 +14,20 @@
* limitations under the License.
*/
#import "GDTLibrary/Public/GDTConsoleLogger.h"
#import "GDTCORLibrary/Public/GDTCORConsoleLogger.h"
/** The console logger prefix. */
static NSString *kGDTConsoleLogger = @"[GoogleDataTransport]";
static NSString *kGDTCORConsoleLogger = @"[GoogleDataTransport]";
NSString *GDTMessageCodeEnumToString(GDTMessageCode code) {
return [[NSString alloc] initWithFormat:@"I-GDT%06ld", (long)code];
NSString *GDTCORMessageCodeEnumToString(GDTCORMessageCode code) {
return [[NSString alloc] initWithFormat:@"I-GDTCOR%06ld", (long)code];
}
void GDTLog(GDTMessageCode code, NSString *format, ...) {
void GDTCORLog(GDTCORMessageCode code, NSString *format, ...) {
// Don't log anything in not debug builds.
#ifndef NDEBUG
NSString *logFormat = [NSString
stringWithFormat:@"%@[%@] %@", kGDTConsoleLogger, GDTMessageCodeEnumToString(code), format];
NSString *logFormat = [NSString stringWithFormat:@"%@[%@] %@", kGDTCORConsoleLogger,
GDTCORMessageCodeEnumToString(code), format];
va_list args;
va_start(args, format);
NSLogv(logFormat, args);
@@ -14,9 +14,9 @@
* limitations under the License.
*/
#import <GoogleDataTransport/GDTDataFuture.h>
#import <GoogleDataTransport/GDTCORDataFuture.h>
@implementation GDTDataFuture
@implementation GDTCORDataFuture
- (instancetype)initWithFileURL:(NSURL *)fileURL {
self = [super init];
@@ -38,25 +38,25 @@
#pragma mark - NSSecureCoding
/** Coding key for _fileURL ivar. */
static NSString *kGDTDataFutureFileURLKey = @"GDTDataFutureFileURLKey";
static NSString *kGDTCORDataFutureFileURLKey = @"GDTCORDataFutureFileURLKey";
/** Coding key for _data ivar. */
static NSString *kGDTDataFutureDataKey = @"GDTDataFutureDataKey";
static NSString *kGDTCORDataFutureDataKey = @"GDTCORDataFutureDataKey";
+ (BOOL)supportsSecureCoding {
return YES;
}
- (void)encodeWithCoder:(nonnull NSCoder *)aCoder {
[aCoder encodeObject:_fileURL forKey:kGDTDataFutureFileURLKey];
[aCoder encodeObject:_originalData forKey:kGDTDataFutureDataKey];
[aCoder encodeObject:_fileURL forKey:kGDTCORDataFutureFileURLKey];
[aCoder encodeObject:_originalData forKey:kGDTCORDataFutureDataKey];
}
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder {
self = [self init];
if (self) {
_fileURL = [aDecoder decodeObjectOfClass:[NSURL class] forKey:kGDTDataFutureFileURLKey];
_originalData = [aDecoder decodeObjectOfClass:[NSData class] forKey:kGDTDataFutureDataKey];
_fileURL = [aDecoder decodeObjectOfClass:[NSURL class] forKey:kGDTCORDataFutureFileURLKey];
_originalData = [aDecoder decodeObjectOfClass:[NSData class] forKey:kGDTCORDataFutureDataKey];
}
return self;
}
@@ -14,29 +14,32 @@
* limitations under the License.
*/
#import <GoogleDataTransport/GDTEvent.h>
#import <GoogleDataTransport/GDTCOREvent.h>
#import <GoogleDataTransport/GDTStoredEvent.h>
#import <GoogleDataTransport/GDTCORAssert.h>
#import <GoogleDataTransport/GDTCORStoredEvent.h>
#import "GDTLibrary/Private/GDTAssert.h"
#import "GDTLibrary/Private/GDTEvent_Private.h"
#import "GDTCORLibrary/Private/GDTCOREvent_Private.h"
@implementation GDTEvent
@implementation GDTCOREvent
- (instancetype)initWithMappingID:(NSString *)mappingID target:(NSInteger)target {
GDTAssert(mappingID.length > 0, @"Please give a valid mapping ID");
GDTAssert(target > 0, @"A target cannot be negative or 0");
GDTCORAssert(mappingID.length > 0, @"Please give a valid mapping ID");
GDTCORAssert(target > 0, @"A target cannot be negative or 0");
if (mappingID == nil || mappingID.length == 0 || target <= 0) {
return nil;
}
self = [super init];
if (self) {
_mappingID = mappingID;
_target = target;
_qosTier = GDTEventQosDefault;
_qosTier = GDTCOREventQosDefault;
}
return self;
}
- (instancetype)copy {
GDTEvent *copy = [[GDTEvent alloc] initWithMappingID:_mappingID target:_target];
GDTCOREvent *copy = [[GDTCOREvent alloc] initWithMappingID:_mappingID target:_target];
copy.dataObject = _dataObject;
copy.dataObjectTransportBytes = _dataObjectTransportBytes;
copy.qosTier = _qosTier;
@@ -57,7 +60,7 @@
return [self hash] == [object hash];
}
- (void)setDataObject:(id<GDTEventDataObject>)dataObject {
- (void)setDataObject:(id<GDTCOREventDataObject>)dataObject {
// If you're looking here because of a performance issue in -transportBytes slowing the assignment
// of -dataObject, one way to address this is to add a queue to this class,
// dispatch_(barrier_ if concurrent)async here, and implement the getter with a dispatch_sync.
@@ -67,8 +70,8 @@
}
}
- (GDTStoredEvent *)storedEventWithDataFuture:(GDTDataFuture *)dataFuture {
return [[GDTStoredEvent alloc] initWithEvent:self dataFuture:dataFuture];
- (GDTCORStoredEvent *)storedEventWithDataFuture:(GDTCORDataFuture *)dataFuture {
return [[GDTCORStoredEvent alloc] initWithEvent:self dataFuture:dataFuture];
}
#pragma mark - NSSecureCoding and NSCoding Protocols
@@ -100,7 +103,7 @@ static NSString *clockSnapshotKey = @"_clockSnapshot";
_dataObjectTransportBytes = [aDecoder decodeObjectOfClass:[NSData class]
forKey:dataObjectTransportBytesKey];
_qosTier = [aDecoder decodeIntegerForKey:qosTierKey];
_clockSnapshot = [aDecoder decodeObjectOfClass:[GDTClock class] forKey:clockSnapshotKey];
_clockSnapshot = [aDecoder decodeObjectOfClass:[GDTCORClock class] forKey:clockSnapshotKey];
}
return self;
}
@@ -0,0 +1,119 @@
/*
* Copyright 2019 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "GDTCORLibrary/Public/GDTCORLifecycle.h"
#import <GoogleDataTransport/GDTCOREvent.h>
#import "GDTCORLibrary/Private/GDTCORRegistrar_Private.h"
#import "GDTCORLibrary/Private/GDTCORStorage_Private.h"
#import "GDTCORLibrary/Private/GDTCORTransformer_Private.h"
#import "GDTCORLibrary/Private/GDTCORUploadCoordinator.h"
@implementation GDTCORLifecycle
+ (void)load {
[self sharedInstance];
}
/** Creates/returns the singleton instance of this class.
*
* @return The singleton instance of this class.
*/
+ (instancetype)sharedInstance {
static GDTCORLifecycle *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[GDTCORLifecycle alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
selector:@selector(applicationDidEnterBackground:)
name:kGDTCORApplicationDidEnterBackgroundNotification
object:nil];
[notificationCenter addObserver:self
selector:@selector(applicationWillEnterForeground:)
name:kGDTCORApplicationWillEnterForegroundNotification
object:nil];
NSString *name = kGDTCORApplicationWillTerminateNotification;
[notificationCenter addObserver:self
selector:@selector(applicationWillTerminate:)
name:name
object:nil];
}
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)applicationDidEnterBackground:(NSNotification *)notification {
GDTCORApplication *application = [GDTCORApplication sharedApplication];
if ([[GDTCORTransformer sharedInstance] respondsToSelector:@selector(appWillBackground:)]) {
[[GDTCORTransformer sharedInstance] appWillBackground:application];
}
if ([[GDTCORStorage sharedInstance] respondsToSelector:@selector(appWillBackground:)]) {
[[GDTCORStorage sharedInstance] appWillBackground:application];
}
if ([[GDTCORUploadCoordinator sharedInstance] respondsToSelector:@selector(appWillBackground:)]) {
[[GDTCORUploadCoordinator sharedInstance] appWillBackground:application];
}
if ([[GDTCORRegistrar sharedInstance] respondsToSelector:@selector(appWillBackground:)]) {
[[GDTCORRegistrar sharedInstance] appWillBackground:application];
}
}
- (void)applicationWillEnterForeground:(NSNotification *)notification {
GDTCORApplication *application = [GDTCORApplication sharedApplication];
if ([[GDTCORTransformer sharedInstance] respondsToSelector:@selector(appWillForeground:)]) {
[[GDTCORTransformer sharedInstance] appWillForeground:application];
}
if ([[GDTCORStorage sharedInstance] respondsToSelector:@selector(appWillForeground:)]) {
[[GDTCORStorage sharedInstance] appWillForeground:application];
}
if ([[GDTCORUploadCoordinator sharedInstance] respondsToSelector:@selector(appWillForeground:)]) {
[[GDTCORUploadCoordinator sharedInstance] appWillForeground:application];
}
if ([[GDTCORRegistrar sharedInstance] respondsToSelector:@selector(appWillForeground:)]) {
[[GDTCORRegistrar sharedInstance] appWillForeground:application];
}
}
- (void)applicationWillTerminate:(NSNotification *)notification {
GDTCORApplication *application = [GDTCORApplication sharedApplication];
if ([[GDTCORTransformer sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) {
[[GDTCORTransformer sharedInstance] appWillTerminate:application];
}
if ([[GDTCORStorage sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) {
[[GDTCORStorage sharedInstance] appWillTerminate:application];
}
if ([[GDTCORUploadCoordinator sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) {
[[GDTCORUploadCoordinator sharedInstance] appWillTerminate:application];
}
if ([[GDTCORRegistrar sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) {
[[GDTCORRegistrar sharedInstance] appWillTerminate:application];
}
}
@end
@@ -14,20 +14,22 @@
* limitations under the License.
*/
#import <GoogleDataTransport/GDTPlatform.h>
#import <GoogleDataTransport/GDTCORPlatform.h>
const GDTBackgroundIdentifier GDTBackgroundIdentifierInvalid = 0;
#import <GoogleDataTransport/GDTCORAssert.h>
NSString *const kGDTApplicationDidEnterBackgroundNotification =
@"GDTApplicationDidEnterBackgroundNotification";
const GDTCORBackgroundIdentifier GDTCORBackgroundIdentifierInvalid = 0;
NSString *const kGDTApplicationWillEnterForegroundNotification =
@"GDTApplicationWillEnterForegroundNotification";
NSString *const kGDTCORApplicationDidEnterBackgroundNotification =
@"GDTCORApplicationDidEnterBackgroundNotification";
NSString *const kGDTApplicationWillTerminateNotification =
@"GDTApplicationWillTerminateNotification";
NSString *const kGDTCORApplicationWillEnterForegroundNotification =
@"GDTCORApplicationWillEnterForegroundNotification";
BOOL GDTReachabilityFlagsContainWWAN(SCNetworkReachabilityFlags flags) {
NSString *const kGDTCORApplicationWillTerminateNotification =
@"GDTCORApplicationWillTerminateNotification";
BOOL GDTCORReachabilityFlagsContainWWAN(SCNetworkReachabilityFlags flags) {
#if TARGET_OS_IOS
return (flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN;
#else
@@ -35,22 +37,23 @@ BOOL GDTReachabilityFlagsContainWWAN(SCNetworkReachabilityFlags flags) {
#endif // TARGET_OS_IOS
}
@implementation GDTApplication
@implementation GDTCORApplication
+ (void)load {
#if TARGET_OS_IOS || TARGET_OS_TV
// If this asserts, please file a bug at https://github.com/firebase/firebase-ios-sdk/issues.
NSAssert(GDTBackgroundIdentifierInvalid == UIBackgroundTaskInvalid,
@"GDTBackgroundIdentifierInvalid and UIBackgroundTaskInvalid should be the same.");
GDTCORFatalAssert(
GDTCORBackgroundIdentifierInvalid == UIBackgroundTaskInvalid,
@"GDTCORBackgroundIdentifierInvalid and UIBackgroundTaskInvalid should be the same.");
#endif
[self sharedApplication];
}
+ (nullable GDTApplication *)sharedApplication {
static GDTApplication *application;
+ (nullable GDTCORApplication *)sharedApplication {
static GDTCORApplication *application;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
application = [[GDTApplication alloc] init];
application = [[GDTCORApplication alloc] init];
});
return application;
}
@@ -74,6 +77,20 @@ BOOL GDTReachabilityFlagsContainWWAN(SCNetworkReachabilityFlags flags) {
selector:@selector(iOSApplicationWillTerminate:)
name:name
object:nil];
#if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
if (@available(iOS 13, tvOS 13.0, *)) {
[notificationCenter addObserver:self
selector:@selector(iOSApplicationWillEnterForeground:)
name:UISceneWillEnterForegroundNotification
object:nil];
[notificationCenter addObserver:self
selector:@selector(iOSApplicationDidEnterBackground:)
name:UISceneWillDeactivateNotification
object:nil];
}
#endif // defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
#elif TARGET_OS_OSX
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
@@ -85,13 +102,15 @@ BOOL GDTReachabilityFlagsContainWWAN(SCNetworkReachabilityFlags flags) {
return self;
}
- (GDTBackgroundIdentifier)beginBackgroundTaskWithExpirationHandler:(void (^)(void))handler {
- (GDTCORBackgroundIdentifier)beginBackgroundTaskWithExpirationHandler:(void (^)(void))handler {
return
[[self sharedApplicationForBackgroundTask] beginBackgroundTaskWithExpirationHandler:handler];
}
- (void)endBackgroundTask:(GDTBackgroundIdentifier)bgID {
[[self sharedApplicationForBackgroundTask] endBackgroundTask:bgID];
- (void)endBackgroundTask:(GDTCORBackgroundIdentifier)bgID {
if (bgID != GDTCORBackgroundIdentifierInvalid) {
[[self sharedApplicationForBackgroundTask] endBackgroundTask:bgID];
}
}
#pragma mark - App environment helpers
@@ -131,17 +150,17 @@ BOOL GDTReachabilityFlagsContainWWAN(SCNetworkReachabilityFlags flags) {
#if TARGET_OS_IOS || TARGET_OS_TV
- (void)iOSApplicationDidEnterBackground:(NSNotification *)notif {
NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter];
[notifCenter postNotificationName:kGDTApplicationDidEnterBackgroundNotification object:nil];
[notifCenter postNotificationName:kGDTCORApplicationDidEnterBackgroundNotification object:nil];
}
- (void)iOSApplicationWillEnterForeground:(NSNotification *)notif {
NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter];
[notifCenter postNotificationName:kGDTApplicationWillEnterForegroundNotification object:nil];
[notifCenter postNotificationName:kGDTCORApplicationWillEnterForegroundNotification object:nil];
}
- (void)iOSApplicationWillTerminate:(NSNotification *)notif {
NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter];
[notifCenter postNotificationName:kGDTApplicationWillTerminateNotification object:nil];
[notifCenter postNotificationName:kGDTCORApplicationWillTerminateNotification object:nil];
}
#endif // TARGET_OS_IOS || TARGET_OS_TV
@@ -150,7 +169,7 @@ BOOL GDTReachabilityFlagsContainWWAN(SCNetworkReachabilityFlags flags) {
#if TARGET_OS_OSX
- (void)macOSApplicationWillTerminate:(NSNotification *)notif {
NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter];
[notifCenter postNotificationName:kGDTApplicationWillTerminateNotification object:nil];
[notifCenter postNotificationName:kGDTCORApplicationWillTerminateNotification object:nil];
}
#endif // TARGET_OS_OSX
@@ -14,10 +14,10 @@
* limitations under the License.
*/
#import "GDTLibrary/Private/GDTReachability.h"
#import "GDTLibrary/Private/GDTReachability_Private.h"
#import "GDTCORLibrary/Private/GDTCORReachability.h"
#import "GDTCORLibrary/Private/GDTCORReachability_Private.h"
#import <GoogleDataTransport/GDTConsoleLogger.h>
#import <GoogleDataTransport/GDTCORConsoleLogger.h>
#import <netinet/in.h>
@@ -27,11 +27,11 @@
* @param flags The new flag values.
* @param info Any data that might be passed in by the callback.
*/
static void GDTReachabilityCallback(SCNetworkReachabilityRef reachability,
SCNetworkReachabilityFlags flags,
void *info);
static void GDTCORReachabilityCallback(SCNetworkReachabilityRef reachability,
SCNetworkReachabilityFlags flags,
void *info);
@implementation GDTReachability {
@implementation GDTCORReachability {
/** The reachability object. */
SCNetworkReachabilityRef _reachabilityRef;
@@ -47,18 +47,18 @@ static void GDTReachabilityCallback(SCNetworkReachabilityRef reachability,
}
+ (instancetype)sharedInstance {
static GDTReachability *sharedInstance;
static GDTCORReachability *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[GDTReachability alloc] init];
sharedInstance = [[GDTCORReachability alloc] init];
});
return sharedInstance;
}
+ (SCNetworkReachabilityFlags)currentFlags {
__block SCNetworkReachabilityFlags currentFlags;
dispatch_sync([GDTReachability sharedInstance] -> _reachabilityQueue, ^{
GDTReachability *reachability = [GDTReachability sharedInstance];
dispatch_sync([GDTCORReachability sharedInstance] -> _reachabilityQueue, ^{
GDTCORReachability *reachability = [GDTCORReachability sharedInstance];
currentFlags = reachability->_flags ? reachability->_flags : reachability->_callbackFlags;
});
return currentFlags;
@@ -72,16 +72,18 @@ static void GDTReachabilityCallback(SCNetworkReachabilityRef reachability,
zeroAddress.sin_len = sizeof(zeroAddress);
zeroAddress.sin_family = AF_INET;
_reachabilityQueue = dispatch_queue_create("com.google.GDTReachability", DISPATCH_QUEUE_SERIAL);
_reachabilityQueue =
dispatch_queue_create("com.google.GDTCORReachability", DISPATCH_QUEUE_SERIAL);
_reachabilityRef = SCNetworkReachabilityCreateWithAddress(
kCFAllocatorDefault, (const struct sockaddr *)&zeroAddress);
Boolean success = SCNetworkReachabilitySetDispatchQueue(_reachabilityRef, _reachabilityQueue);
if (!success) {
GDTLogWarning(GDTMCWReachabilityFailed, @"%@", @"The reachability queue wasn't set.");
GDTCORLogWarning(GDTCORMCWReachabilityFailed, @"%@", @"The reachability queue wasn't set.");
}
success = SCNetworkReachabilitySetCallback(_reachabilityRef, GDTReachabilityCallback, NULL);
success = SCNetworkReachabilitySetCallback(_reachabilityRef, GDTCORReachabilityCallback, NULL);
if (!success) {
GDTLogWarning(GDTMCWReachabilityFailed, @"%@", @"The reachability callback wasn't set.");
GDTCORLogWarning(GDTCORMCWReachabilityFailed, @"%@",
@"The reachability callback wasn't set.");
}
// Get the initial set of flags.
@@ -103,8 +105,8 @@ static void GDTReachabilityCallback(SCNetworkReachabilityRef reachability,
@end
static void GDTReachabilityCallback(SCNetworkReachabilityRef reachability,
SCNetworkReachabilityFlags flags,
void *info) {
[[GDTReachability sharedInstance] setCallbackFlags:flags];
static void GDTCORReachabilityCallback(SCNetworkReachabilityRef reachability,
SCNetworkReachabilityFlags flags,
void *info) {
[[GDTCORReachability sharedInstance] setCallbackFlags:flags];
}
@@ -14,23 +14,23 @@
* limitations under the License.
*/
#import "GDTLibrary/Public/GDTRegistrar.h"
#import "GDTCORLibrary/Public/GDTCORRegistrar.h"
#import "GDTLibrary/Private/GDTRegistrar_Private.h"
#import "GDTCORLibrary/Private/GDTCORRegistrar_Private.h"
@implementation GDTRegistrar {
@implementation GDTCORRegistrar {
/** Backing ivar for targetToUploader property. */
NSMutableDictionary<NSNumber *, id<GDTUploader>> *_targetToUploader;
NSMutableDictionary<NSNumber *, id<GDTCORUploader>> *_targetToUploader;
/** Backing ivar for targetToPrioritizer property. */
NSMutableDictionary<NSNumber *, id<GDTPrioritizer>> *_targetToPrioritizer;
NSMutableDictionary<NSNumber *, id<GDTCORPrioritizer>> *_targetToPrioritizer;
}
+ (instancetype)sharedInstance {
static GDTRegistrar *sharedInstance;
static GDTCORRegistrar *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[GDTRegistrar alloc] init];
sharedInstance = [[GDTCORRegistrar alloc] init];
});
return sharedInstance;
}
@@ -38,38 +38,39 @@
- (instancetype)init {
self = [super init];
if (self) {
_registrarQueue = dispatch_queue_create("com.google.GDTRegistrar", DISPATCH_QUEUE_CONCURRENT);
_registrarQueue =
dispatch_queue_create("com.google.GDTCORRegistrar", DISPATCH_QUEUE_CONCURRENT);
_targetToPrioritizer = [[NSMutableDictionary alloc] init];
_targetToUploader = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void)registerUploader:(id<GDTUploader>)backend target:(GDTTarget)target {
__weak GDTRegistrar *weakSelf = self;
- (void)registerUploader:(id<GDTCORUploader>)backend target:(GDTCORTarget)target {
__weak GDTCORRegistrar *weakSelf = self;
dispatch_barrier_async(_registrarQueue, ^{
GDTRegistrar *strongSelf = weakSelf;
GDTCORRegistrar *strongSelf = weakSelf;
if (strongSelf) {
strongSelf->_targetToUploader[@(target)] = backend;
}
});
}
- (void)registerPrioritizer:(id<GDTPrioritizer>)prioritizer target:(GDTTarget)target {
__weak GDTRegistrar *weakSelf = self;
- (void)registerPrioritizer:(id<GDTCORPrioritizer>)prioritizer target:(GDTCORTarget)target {
__weak GDTCORRegistrar *weakSelf = self;
dispatch_barrier_async(_registrarQueue, ^{
GDTRegistrar *strongSelf = weakSelf;
GDTCORRegistrar *strongSelf = weakSelf;
if (strongSelf) {
strongSelf->_targetToPrioritizer[@(target)] = prioritizer;
}
});
}
- (NSMutableDictionary<NSNumber *, id<GDTUploader>> *)targetToUploader {
__block NSMutableDictionary<NSNumber *, id<GDTUploader>> *targetToUploader;
__weak GDTRegistrar *weakSelf = self;
- (NSMutableDictionary<NSNumber *, id<GDTCORUploader>> *)targetToUploader {
__block NSMutableDictionary<NSNumber *, id<GDTCORUploader>> *targetToUploader;
__weak GDTCORRegistrar *weakSelf = self;
dispatch_sync(_registrarQueue, ^{
GDTRegistrar *strongSelf = weakSelf;
GDTCORRegistrar *strongSelf = weakSelf;
if (strongSelf) {
targetToUploader = strongSelf->_targetToUploader;
}
@@ -77,11 +78,11 @@
return targetToUploader;
}
- (NSMutableDictionary<NSNumber *, id<GDTPrioritizer>> *)targetToPrioritizer {
__block NSMutableDictionary<NSNumber *, id<GDTPrioritizer>> *targetToPrioritizer;
__weak GDTRegistrar *weakSelf = self;
- (NSMutableDictionary<NSNumber *, id<GDTCORPrioritizer>> *)targetToPrioritizer {
__block NSMutableDictionary<NSNumber *, id<GDTCORPrioritizer>> *targetToPrioritizer;
__weak GDTCORRegistrar *weakSelf = self;
dispatch_sync(_registrarQueue, ^{
GDTRegistrar *strongSelf = weakSelf;
GDTCORRegistrar *strongSelf = weakSelf;
if (strongSelf) {
targetToPrioritizer = strongSelf->_targetToPrioritizer;
}
@@ -89,16 +90,16 @@
return targetToPrioritizer;
}
#pragma mark - GDTLifecycleProtocol
#pragma mark - GDTCORLifecycleProtocol
- (void)appWillBackground:(nonnull GDTApplication *)app {
- (void)appWillBackground:(nonnull GDTCORApplication *)app {
dispatch_async(_registrarQueue, ^{
for (id<GDTUploader> uploader in [self->_targetToUploader allValues]) {
for (id<GDTCORUploader> uploader in [self->_targetToUploader allValues]) {
if ([uploader respondsToSelector:@selector(appWillBackground:)]) {
[uploader appWillBackground:app];
}
}
for (id<GDTPrioritizer> prioritizer in [self->_targetToPrioritizer allValues]) {
for (id<GDTCORPrioritizer> prioritizer in [self->_targetToPrioritizer allValues]) {
if ([prioritizer respondsToSelector:@selector(appWillBackground:)]) {
[prioritizer appWillBackground:app];
}
@@ -106,14 +107,14 @@
});
}
- (void)appWillForeground:(nonnull GDTApplication *)app {
- (void)appWillForeground:(nonnull GDTCORApplication *)app {
dispatch_async(_registrarQueue, ^{
for (id<GDTUploader> uploader in [self->_targetToUploader allValues]) {
for (id<GDTCORUploader> uploader in [self->_targetToUploader allValues]) {
if ([uploader respondsToSelector:@selector(appWillForeground:)]) {
[uploader appWillForeground:app];
}
}
for (id<GDTPrioritizer> prioritizer in [self->_targetToPrioritizer allValues]) {
for (id<GDTCORPrioritizer> prioritizer in [self->_targetToPrioritizer allValues]) {
if ([prioritizer respondsToSelector:@selector(appWillForeground:)]) {
[prioritizer appWillForeground:app];
}
@@ -121,14 +122,14 @@
});
}
- (void)appWillTerminate:(nonnull GDTApplication *)app {
- (void)appWillTerminate:(nonnull GDTCORApplication *)app {
dispatch_sync(_registrarQueue, ^{
for (id<GDTUploader> uploader in [self->_targetToUploader allValues]) {
for (id<GDTCORUploader> uploader in [self->_targetToUploader allValues]) {
if ([uploader respondsToSelector:@selector(appWillTerminate:)]) {
[uploader appWillTerminate:app];
}
}
for (id<GDTPrioritizer> prioritizer in [self->_targetToPrioritizer allValues]) {
for (id<GDTCORPrioritizer> prioritizer in [self->_targetToPrioritizer allValues]) {
if ([prioritizer respondsToSelector:@selector(appWillTerminate:)]) {
[prioritizer appWillTerminate:app];
}
@@ -0,0 +1,323 @@
/*
* Copyright 2018 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "GDTCORLibrary/Private/GDTCORStorage.h"
#import "GDTCORLibrary/Private/GDTCORStorage_Private.h"
#import <GoogleDataTransport/GDTCORAssert.h>
#import <GoogleDataTransport/GDTCORConsoleLogger.h>
#import <GoogleDataTransport/GDTCORLifecycle.h>
#import <GoogleDataTransport/GDTCORPrioritizer.h>
#import <GoogleDataTransport/GDTCORStoredEvent.h>
#import "GDTCORLibrary/Private/GDTCOREvent_Private.h"
#import "GDTCORLibrary/Private/GDTCORRegistrar_Private.h"
#import "GDTCORLibrary/Private/GDTCORUploadCoordinator.h"
/** Creates and/or returns a singleton NSString that is the shared storage path.
*
* @return The SDK event storage path.
*/
static NSString *GDTCORStoragePath() {
static NSString *storagePath;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *cachePath =
NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
storagePath = [NSString stringWithFormat:@"%@/google-sdks-events", cachePath];
});
return storagePath;
}
@implementation GDTCORStorage
+ (NSString *)archivePath {
static NSString *archivePath;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
archivePath = [GDTCORStoragePath() stringByAppendingPathComponent:@"GDTCORStorageArchive"];
});
return archivePath;
}
+ (instancetype)sharedInstance {
static GDTCORStorage *sharedStorage;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedStorage = [[GDTCORStorage alloc] init];
});
return sharedStorage;
}
- (instancetype)init {
self = [super init];
if (self) {
_storageQueue = dispatch_queue_create("com.google.GDTCORStorage", DISPATCH_QUEUE_SERIAL);
_targetToEventSet = [[NSMutableDictionary alloc] init];
_storedEvents = [[NSMutableOrderedSet alloc] init];
_uploadCoordinator = [GDTCORUploadCoordinator sharedInstance];
}
return self;
}
- (void)storeEvent:(GDTCOREvent *)event {
if (event == nil) {
return;
}
[self createEventDirectoryIfNotExists];
__block GDTCORBackgroundIdentifier bgID = GDTCORBackgroundIdentifierInvalid;
if (_runningInBackground) {
bgID = [[GDTCORApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
if (bgID != GDTCORBackgroundIdentifierInvalid) {
[[GDTCORApplication sharedApplication] endBackgroundTask:bgID];
bgID = GDTCORBackgroundIdentifierInvalid;
}
}];
}
dispatch_async(_storageQueue, ^{
// Check that a backend implementation is available for this target.
NSInteger target = event.target;
// Check that a prioritizer is available for this target.
id<GDTCORPrioritizer> prioritizer =
[GDTCORRegistrar sharedInstance].targetToPrioritizer[@(target)];
GDTCORAssert(prioritizer, @"There's no prioritizer registered for the given target.");
// Write the transport bytes to disk, get a filename.
GDTCORAssert(event.dataObjectTransportBytes, @"The event should have been serialized to bytes");
NSURL *eventFile = [self saveEventBytesToDisk:event.dataObjectTransportBytes
eventHash:event.hash];
GDTCORDataFuture *dataFuture = [[GDTCORDataFuture alloc] initWithFileURL:eventFile];
GDTCORStoredEvent *storedEvent = [event storedEventWithDataFuture:dataFuture];
// Add event to tracking collections.
[self addEventToTrackingCollections:storedEvent];
// Have the prioritizer prioritize the event.
[prioritizer prioritizeEvent:storedEvent];
// Check the QoS, if it's high priority, notify the target that it has a high priority event.
if (event.qosTier == GDTCOREventQoSFast) {
[self.uploadCoordinator forceUploadForTarget:target];
}
// Write state to disk.
if (self->_runningInBackground) {
if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self
requiringSecureCoding:YES
error:nil];
[data writeToFile:[GDTCORStorage archivePath] atomically:YES];
} else {
#if !defined(TARGET_OS_MACCATALYST)
[NSKeyedArchiver archiveRootObject:self toFile:[GDTCORStorage archivePath]];
#endif
}
}
// If running in the background, save state to disk and end the associated background task.
if (bgID != GDTCORBackgroundIdentifierInvalid) {
[[GDTCORApplication sharedApplication] endBackgroundTask:bgID];
bgID = GDTCORBackgroundIdentifierInvalid;
}
});
}
- (void)removeEvents:(NSSet<GDTCORStoredEvent *> *)events {
NSSet<GDTCORStoredEvent *> *eventsToRemove = [events copy];
dispatch_async(_storageQueue, ^{
for (GDTCORStoredEvent *event in eventsToRemove) {
// Remove from disk, first and foremost.
NSError *error;
if (event.dataFuture.fileURL) {
NSURL *fileURL = event.dataFuture.fileURL;
[[NSFileManager defaultManager] removeItemAtURL:fileURL error:&error];
GDTCORAssert(error == nil, @"There was an error removing an event file: %@", error);
}
// Remove from the tracking collections.
[self.storedEvents removeObject:event];
[self.targetToEventSet[event.target] removeObject:event];
}
});
}
#pragma mark - Private helper methods
/** Creates the storage directory if it does not exist. */
- (void)createEventDirectoryIfNotExists {
NSError *error;
BOOL result = [[NSFileManager defaultManager] createDirectoryAtPath:GDTCORStoragePath()
withIntermediateDirectories:YES
attributes:0
error:&error];
if (!result || error) {
GDTCORLogError(GDTCORMCEDirectoryCreationError, @"Error creating the directory: %@", error);
}
}
/** Saves the event's dataObjectTransportBytes to a file using NSData mechanisms.
*
* @note This method should only be called from a method within a block on _storageQueue to maintain
* thread safety.
*
* @param transportBytes The transport bytes of the event.
* @param eventHash The hash value of the event.
* @return The filename
*/
- (NSURL *)saveEventBytesToDisk:(NSData *)transportBytes eventHash:(NSUInteger)eventHash {
NSString *storagePath = GDTCORStoragePath();
NSString *event = [NSString stringWithFormat:@"event-%lu", (unsigned long)eventHash];
NSURL *eventFilePath = [NSURL fileURLWithPath:[storagePath stringByAppendingPathComponent:event]];
GDTCORAssert(![[NSFileManager defaultManager] fileExistsAtPath:eventFilePath.path],
@"An event shouldn't already exist at this path: %@", eventFilePath.path);
BOOL writingSuccess = [transportBytes writeToURL:eventFilePath atomically:YES];
if (!writingSuccess) {
GDTCORLogError(GDTCORMCEFileWriteError, @"An event file could not be written: %@",
eventFilePath);
}
return eventFilePath;
}
/** Adds the event to internal tracking collections.
*
* @note This method should only be called from a method within a block on _storageQueue to maintain
* thread safety.
*
* @param event The event to track.
*/
- (void)addEventToTrackingCollections:(GDTCORStoredEvent *)event {
[_storedEvents addObject:event];
NSMutableSet<GDTCORStoredEvent *> *events = self.targetToEventSet[event.target];
events = events ? events : [[NSMutableSet alloc] init];
[events addObject:event];
_targetToEventSet[event.target] = events;
}
#pragma mark - GDTCORLifecycleProtocol
- (void)appWillForeground:(GDTCORApplication *)app {
if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) {
NSData *data = [NSData dataWithContentsOfFile:[GDTCORStorage archivePath]];
[NSKeyedUnarchiver unarchivedObjectOfClass:[GDTCORStorage class] fromData:data error:nil];
} else {
#if !defined(TARGET_OS_MACCATALYST)
[NSKeyedUnarchiver unarchiveObjectWithFile:[GDTCORStorage archivePath]];
#endif
}
}
- (void)appWillBackground:(GDTCORApplication *)app {
self->_runningInBackground = YES;
dispatch_async(_storageQueue, ^{
if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self
requiringSecureCoding:YES
error:nil];
[data writeToFile:[GDTCORStorage archivePath] atomically:YES];
} else {
#if !defined(TARGET_OS_MACCATALYST)
[NSKeyedArchiver archiveRootObject:self toFile:[GDTCORStorage archivePath]];
#endif
}
});
// Create an immediate background task to run until the end of the current queue of work.
__block GDTCORBackgroundIdentifier bgID = [app beginBackgroundTaskWithExpirationHandler:^{
if (bgID != GDTCORBackgroundIdentifierInvalid) {
[app endBackgroundTask:bgID];
bgID = GDTCORBackgroundIdentifierInvalid;
}
}];
dispatch_async(_storageQueue, ^{
if (bgID != GDTCORBackgroundIdentifierInvalid) {
[app endBackgroundTask:bgID];
bgID = GDTCORBackgroundIdentifierInvalid;
}
});
}
- (void)appWillTerminate:(GDTCORApplication *)application {
if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self
requiringSecureCoding:YES
error:nil];
[data writeToFile:[GDTCORStorage archivePath] atomically:YES];
} else {
#if !defined(TARGET_OS_MACCATALYST)
[NSKeyedArchiver archiveRootObject:self toFile:[GDTCORStorage archivePath]];
#endif
}
}
#pragma mark - NSSecureCoding
/** The NSKeyedCoder key for the storedEvents property. */
static NSString *const kGDTCORStorageStoredEventsKey = @"GDTCORStorageStoredEventsKey";
/** The NSKeyedCoder key for the targetToEventSet property. */
static NSString *const kGDTCORStorageTargetToEventSetKey = @"GDTCORStorageTargetToEventSetKey";
/** The NSKeyedCoder key for the uploadCoordinator property. */
static NSString *const kGDTCORStorageUploadCoordinatorKey = @"GDTCORStorageUploadCoordinatorKey";
+ (BOOL)supportsSecureCoding {
return YES;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
// Create the singleton and populate its ivars.
GDTCORStorage *sharedInstance = [self.class sharedInstance];
dispatch_sync(sharedInstance.storageQueue, ^{
NSSet *classes =
[NSSet setWithObjects:[NSMutableOrderedSet class], [GDTCORStoredEvent class], nil];
sharedInstance->_storedEvents = [aDecoder decodeObjectOfClasses:classes
forKey:kGDTCORStorageStoredEventsKey];
classes = [NSSet setWithObjects:[NSMutableDictionary class], [NSMutableSet class],
[GDTCORStoredEvent class], nil];
sharedInstance->_targetToEventSet =
[aDecoder decodeObjectOfClasses:classes forKey:kGDTCORStorageTargetToEventSetKey];
sharedInstance->_uploadCoordinator =
[aDecoder decodeObjectOfClass:[GDTCORUploadCoordinator class]
forKey:kGDTCORStorageUploadCoordinatorKey];
});
return sharedInstance;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
GDTCORStorage *sharedInstance = [self.class sharedInstance];
NSMutableOrderedSet<GDTCORStoredEvent *> *storedEvents = sharedInstance->_storedEvents;
if (storedEvents) {
[aCoder encodeObject:storedEvents forKey:kGDTCORStorageStoredEventsKey];
}
NSMutableDictionary<NSNumber *, NSMutableSet<GDTCORStoredEvent *> *> *targetToEventSet =
sharedInstance->_targetToEventSet;
if (targetToEventSet) {
[aCoder encodeObject:targetToEventSet forKey:kGDTCORStorageTargetToEventSetKey];
}
GDTCORUploadCoordinator *uploadCoordinator = sharedInstance->_uploadCoordinator;
if (uploadCoordinator) {
[aCoder encodeObject:uploadCoordinator forKey:kGDTCORStorageUploadCoordinatorKey];
}
}
@end
@@ -14,15 +14,16 @@
* limitations under the License.
*/
#import <GoogleDataTransport/GDTStoredEvent.h>
#import <GoogleDataTransport/GDTCORStoredEvent.h>
#import <GoogleDataTransport/GDTClock.h>
#import <GoogleDataTransport/GDTCORClock.h>
#import "GDTLibrary/Private/GDTStorage_Private.h"
#import "GDTCORLibrary/Private/GDTCORStorage_Private.h"
@implementation GDTStoredEvent
@implementation GDTCORStoredEvent
- (instancetype)initWithEvent:(GDTEvent *)event dataFuture:(nonnull GDTDataFuture *)dataFuture {
- (instancetype)initWithEvent:(GDTCOREvent *)event
dataFuture:(nonnull GDTCORDataFuture *)dataFuture {
self = [super init];
if (self) {
_dataFuture = dataFuture;
@@ -38,22 +39,22 @@
#pragma mark - NSSecureCoding
/** Coding key for the dataFuture ivar. */
static NSString *kDataFutureKey = @"GDTStoredEventDataFutureKey";
static NSString *kDataFutureKey = @"GDTCORStoredEventDataFutureKey";
/** Coding key for mappingID ivar. */
static NSString *kMappingIDKey = @"GDTStoredEventMappingIDKey";
static NSString *kMappingIDKey = @"GDTCORStoredEventMappingIDKey";
/** Coding key for target ivar. */
static NSString *kTargetKey = @"GDTStoredEventTargetKey";
static NSString *kTargetKey = @"GDTCORStoredEventTargetKey";
/** Coding key for qosTier ivar. */
static NSString *kQosTierKey = @"GDTStoredEventQosTierKey";
static NSString *kQosTierKey = @"GDTCORStoredEventQosTierKey";
/** Coding key for clockSnapshot ivar. */
static NSString *kClockSnapshotKey = @"GDTStoredEventClockSnapshotKey";
static NSString *kClockSnapshotKey = @"GDTCORStoredEventClockSnapshotKey";
/** Coding key for customPrioritizationParams ivar. */
static NSString *kCustomPrioritizationParamsKey = @"GDTStoredEventcustomPrioritizationParamsKey";
static NSString *kCustomPrioritizationParamsKey = @"GDTCORStoredEventcustomPrioritizationParamsKey";
+ (BOOL)supportsSecureCoding {
return YES;
@@ -71,19 +72,19 @@ static NSString *kCustomPrioritizationParamsKey = @"GDTStoredEventcustomPrioriti
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder {
self = [self init];
if (self) {
_dataFuture = [aDecoder decodeObjectOfClass:[GDTDataFuture class] forKey:kDataFutureKey];
_dataFuture = [aDecoder decodeObjectOfClass:[GDTCORDataFuture class] forKey:kDataFutureKey];
_mappingID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kMappingIDKey];
_target = [aDecoder decodeObjectOfClass:[NSNumber class] forKey:kTargetKey];
NSNumber *qosTier = [aDecoder decodeObjectOfClass:[NSNumber class] forKey:kQosTierKey];
_qosTier = [qosTier intValue];
_clockSnapshot = [aDecoder decodeObjectOfClass:[GDTClock class] forKey:kClockSnapshotKey];
_clockSnapshot = [aDecoder decodeObjectOfClass:[GDTCORClock class] forKey:kClockSnapshotKey];
_customPrioritizationParams = [aDecoder decodeObjectOfClass:[NSDictionary class]
forKey:kCustomPrioritizationParamsKey];
}
return self;
}
- (BOOL)isEqual:(GDTStoredEvent *)other {
- (BOOL)isEqual:(GDTCORStoredEvent *)other {
return [self hash] == [other hash];
}
@@ -0,0 +1,113 @@
/*
* Copyright 2018 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "GDTCORLibrary/Private/GDTCORTransformer.h"
#import "GDTCORLibrary/Private/GDTCORTransformer_Private.h"
#import <GoogleDataTransport/GDTCORAssert.h>
#import <GoogleDataTransport/GDTCORConsoleLogger.h>
#import <GoogleDataTransport/GDTCOREventTransformer.h>
#import <GoogleDataTransport/GDTCORLifecycle.h>
#import "GDTCORLibrary/Private/GDTCORStorage.h"
@implementation GDTCORTransformer
+ (instancetype)sharedInstance {
static GDTCORTransformer *eventTransformer;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
eventTransformer = [[self alloc] init];
});
return eventTransformer;
}
- (instancetype)init {
self = [super init];
if (self) {
_eventWritingQueue =
dispatch_queue_create("com.google.GDTCORTransformer", DISPATCH_QUEUE_SERIAL);
_storageInstance = [GDTCORStorage sharedInstance];
}
return self;
}
- (void)transformEvent:(GDTCOREvent *)event
withTransformers:(NSArray<id<GDTCOREventTransformer>> *)transformers {
GDTCORAssert(event, @"You can't write a nil event");
__block GDTCORBackgroundIdentifier bgID = GDTCORBackgroundIdentifierInvalid;
if (_runningInBackground) {
bgID = [[GDTCORApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
if (bgID != GDTCORBackgroundIdentifierInvalid) {
[[GDTCORApplication sharedApplication] endBackgroundTask:bgID];
bgID = GDTCORBackgroundIdentifierInvalid;
}
}];
}
dispatch_async(_eventWritingQueue, ^{
GDTCOREvent *transformedEvent = event;
for (id<GDTCOREventTransformer> transformer in transformers) {
if ([transformer respondsToSelector:@selector(transform:)]) {
transformedEvent = [transformer transform:transformedEvent];
if (!transformedEvent) {
return;
}
} else {
GDTCORLogError(GDTCORMCETransformerDoesntImplementTransform,
@"Transformer doesn't implement transform: %@", transformer);
return;
}
}
[self.storageInstance storeEvent:transformedEvent];
if (self->_runningInBackground) {
[[GDTCORApplication sharedApplication] endBackgroundTask:bgID];
bgID = GDTCORBackgroundIdentifierInvalid;
}
});
}
#pragma mark - GDTCORLifecycleProtocol
- (void)appWillForeground:(GDTCORApplication *)app {
dispatch_async(_eventWritingQueue, ^{
self->_runningInBackground = NO;
});
}
- (void)appWillBackground:(GDTCORApplication *)app {
// Create an immediate background task to run until the end of the current queue of work.
__block GDTCORBackgroundIdentifier bgID = [app beginBackgroundTaskWithExpirationHandler:^{
if (bgID != GDTCORBackgroundIdentifierInvalid) {
[app endBackgroundTask:bgID];
bgID = GDTCORBackgroundIdentifierInvalid;
}
}];
dispatch_async(_eventWritingQueue, ^{
if (bgID != GDTCORBackgroundIdentifierInvalid) {
[app endBackgroundTask:bgID];
bgID = GDTCORBackgroundIdentifierInvalid;
}
});
}
- (void)appWillTerminate:(GDTCORApplication *)application {
// Flush the queue immediately.
dispatch_sync(_eventWritingQueue, ^{
});
}
@end
@@ -0,0 +1,68 @@
/*
* Copyright 2018 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <GoogleDataTransport/GDTCORTransport.h>
#import "GDTCORLibrary/Private/GDTCORTransport_Private.h"
#import <GoogleDataTransport/GDTCORAssert.h>
#import <GoogleDataTransport/GDTCORClock.h>
#import <GoogleDataTransport/GDTCOREvent.h>
#import "GDTCORLibrary/Private/GDTCORTransformer.h"
@implementation GDTCORTransport
- (instancetype)initWithMappingID:(NSString *)mappingID
transformers:(nullable NSArray<id<GDTCOREventTransformer>> *)transformers
target:(NSInteger)target {
GDTCORAssert(mappingID.length > 0, @"A mapping ID cannot be nil or empty");
GDTCORAssert(target > 0, @"A target cannot be negative or 0");
if (mappingID == nil || mappingID.length == 0 || target <= 0) {
return nil;
}
self = [super init];
if (self) {
_mappingID = mappingID;
_transformers = transformers;
_target = target;
_transformerInstance = [GDTCORTransformer sharedInstance];
}
return self;
}
- (void)sendTelemetryEvent:(GDTCOREvent *)event {
// TODO: Determine if sending an event before registration is allowed.
GDTCORAssert(event, @"You can't send a nil event");
GDTCOREvent *copiedEvent = [event copy];
copiedEvent.qosTier = GDTCOREventQoSTelemetry;
copiedEvent.clockSnapshot = [GDTCORClock snapshot];
[self.transformerInstance transformEvent:copiedEvent withTransformers:_transformers];
}
- (void)sendDataEvent:(GDTCOREvent *)event {
// TODO: Determine if sending an event before registration is allowed.
GDTCORAssert(event, @"You can't send a nil event");
GDTCORAssert(event.qosTier != GDTCOREventQoSTelemetry, @"Use -sendTelemetryEvent, please.");
GDTCOREvent *copiedEvent = [event copy];
copiedEvent.clockSnapshot = [GDTCORClock snapshot];
[self.transformerInstance transformEvent:copiedEvent withTransformers:_transformers];
}
- (GDTCOREvent *)eventForTransport {
return [[GDTCOREvent alloc] initWithMappingID:_mappingID target:_target];
}
@end
@@ -14,23 +14,23 @@
* limitations under the License.
*/
#import "GDTLibrary/Private/GDTUploadCoordinator.h"
#import "GDTCORLibrary/Private/GDTCORUploadCoordinator.h"
#import <GoogleDataTransport/GDTClock.h>
#import <GoogleDataTransport/GDTConsoleLogger.h>
#import <GoogleDataTransport/GDTCORAssert.h>
#import <GoogleDataTransport/GDTCORClock.h>
#import <GoogleDataTransport/GDTCORConsoleLogger.h>
#import "GDTLibrary/Private/GDTAssert.h"
#import "GDTLibrary/Private/GDTReachability.h"
#import "GDTLibrary/Private/GDTRegistrar_Private.h"
#import "GDTLibrary/Private/GDTStorage.h"
#import "GDTCORLibrary/Private/GDTCORReachability.h"
#import "GDTCORLibrary/Private/GDTCORRegistrar_Private.h"
#import "GDTCORLibrary/Private/GDTCORStorage.h"
@implementation GDTUploadCoordinator
@implementation GDTCORUploadCoordinator
+ (instancetype)sharedInstance {
static GDTUploadCoordinator *sharedUploader;
static GDTCORUploadCoordinator *sharedUploader;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedUploader = [[GDTUploadCoordinator alloc] init];
sharedUploader = [[GDTCORUploadCoordinator alloc] init];
[sharedUploader startTimer];
});
return sharedUploader;
@@ -40,8 +40,8 @@
self = [super init];
if (self) {
_coordinationQueue =
dispatch_queue_create("com.google.GDTUploadCoordinator", DISPATCH_QUEUE_SERIAL);
_registrar = [GDTRegistrar sharedInstance];
dispatch_queue_create("com.google.GDTCORUploadCoordinator", DISPATCH_QUEUE_SERIAL);
_registrar = [GDTCORRegistrar sharedInstance];
_timerInterval = 30 * NSEC_PER_SEC;
_timerLeeway = 5 * NSEC_PER_SEC;
_targetToInFlightPackages = [[NSMutableDictionary alloc] init];
@@ -49,21 +49,21 @@
return self;
}
- (void)forceUploadForTarget:(GDTTarget)target {
- (void)forceUploadForTarget:(GDTCORTarget)target {
dispatch_async(_coordinationQueue, ^{
GDTUploadConditions conditions = [self uploadConditions];
conditions |= GDTUploadConditionHighPriority;
GDTCORUploadConditions conditions = [self uploadConditions];
conditions |= GDTCORUploadConditionHighPriority;
[self uploadTargets:@[ @(target) ] conditions:conditions];
});
}
#pragma mark - Property overrides
// GDTStorage and GDTUploadCoordinator +sharedInstance methods call each other, so this breaks
// GDTCORStorage and GDTCORUploadCoordinator +sharedInstance methods call each other, so this breaks
// the loop.
- (GDTStorage *)storage {
- (GDTCORStorage *)storage {
if (!_storage) {
_storage = [GDTStorage sharedInstance];
_storage = [GDTCORStorage sharedInstance];
}
return _storage;
}
@@ -81,7 +81,7 @@
self->_timerLeeway);
dispatch_source_set_event_handler(self->_timer, ^{
if (!self->_runningInBackground) {
GDTUploadConditions conditions = [self uploadConditions];
GDTCORUploadConditions conditions = [self uploadConditions];
[self uploadTargets:[self.registrar.targetToUploader allKeys] conditions:conditions];
}
});
@@ -101,9 +101,9 @@
* @param targets An array of targets to trigger.
* @param conditions The set of upload conditions.
*/
- (void)uploadTargets:(NSArray<NSNumber *> *)targets conditions:(GDTUploadConditions)conditions {
- (void)uploadTargets:(NSArray<NSNumber *> *)targets conditions:(GDTCORUploadConditions)conditions {
dispatch_async(_coordinationQueue, ^{
if ((conditions & GDTUploadConditionNoNetwork) == GDTUploadConditionNoNetwork) {
if ((conditions & GDTCORUploadConditionNoNetwork) == GDTCORUploadConditionNoNetwork) {
return;
}
for (NSNumber *target in targets) {
@@ -112,10 +112,10 @@
continue;
}
// Ask the uploader if they can upload and do so, if it can.
id<GDTUploader> uploader = self.registrar.targetToUploader[target];
id<GDTCORUploader> uploader = self.registrar.targetToUploader[target];
if ([uploader readyToUploadWithConditions:conditions]) {
id<GDTPrioritizer> prioritizer = self.registrar.targetToPrioritizer[target];
GDTUploadPackage *package = [prioritizer uploadPackageWithConditions:conditions];
id<GDTCORPrioritizer> prioritizer = self.registrar.targetToPrioritizer[target];
GDTCORUploadPackage *package = [prioritizer uploadPackageWithConditions:conditions];
if (package.events.count) {
self->_targetToInFlightPackages[target] = package;
[uploader uploadPackage:package];
@@ -131,8 +131,8 @@
*
* @return The current upload conditions.
*/
- (GDTUploadConditions)uploadConditions {
SCNetworkReachabilityFlags currentFlags = [GDTReachability currentFlags];
- (GDTCORUploadConditions)uploadConditions {
SCNetworkReachabilityFlags currentFlags = [GDTCORReachability currentFlags];
BOOL reachable =
(currentFlags & kSCNetworkReachabilityFlagsReachable) == kSCNetworkReachabilityFlagsReachable;
BOOL connectionRequired = (currentFlags & kSCNetworkReachabilityFlagsConnectionRequired) ==
@@ -140,14 +140,14 @@
BOOL networkConnected = reachable && !connectionRequired;
if (!networkConnected) {
return GDTUploadConditionNoNetwork;
return GDTCORUploadConditionNoNetwork;
}
BOOL isWWAN = GDTReachabilityFlagsContainWWAN(currentFlags);
BOOL isWWAN = GDTCORReachabilityFlagsContainWWAN(currentFlags);
if (isWWAN) {
return GDTUploadConditionMobileData;
return GDTCORUploadConditionMobileData;
} else {
return GDTUploadConditionWifiData;
return GDTCORUploadConditionWifiData;
}
}
@@ -155,35 +155,42 @@
/** The NSKeyedCoder key for the targetToInFlightPackages property. */
static NSString *const ktargetToInFlightPackagesKey =
@"GDTUploadCoordinatortargetToInFlightPackages";
@"GDTCORUploadCoordinatortargetToInFlightPackages";
+ (BOOL)supportsSecureCoding {
return YES;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
GDTUploadCoordinator *sharedCoordinator = [GDTUploadCoordinator sharedInstance];
sharedCoordinator->_targetToInFlightPackages =
[aDecoder decodeObjectOfClass:[NSMutableDictionary class]
forKey:ktargetToInFlightPackagesKey];
GDTCORUploadCoordinator *sharedCoordinator = [GDTCORUploadCoordinator sharedInstance];
@try {
sharedCoordinator->_targetToInFlightPackages =
[aDecoder decodeObjectOfClass:[NSMutableDictionary class]
forKey:ktargetToInFlightPackagesKey];
} @catch (NSException *exception) {
sharedCoordinator->_targetToInFlightPackages = [NSMutableDictionary dictionary];
}
return sharedCoordinator;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
// All packages that have been given to uploaders need to be tracked so that their expiration
// timers can be called.
[aCoder encodeObject:_targetToInFlightPackages forKey:ktargetToInFlightPackagesKey];
if (_targetToInFlightPackages.count > 0) {
[aCoder encodeObject:_targetToInFlightPackages forKey:ktargetToInFlightPackagesKey];
}
}
#pragma mark - GDTLifecycleProtocol
#pragma mark - GDTCORLifecycleProtocol
- (void)appWillForeground:(GDTApplication *)app {
- (void)appWillForeground:(GDTCORApplication *)app {
// Not entirely thread-safe, but it should be fine.
self->_runningInBackground = NO;
[self startTimer];
}
- (void)appWillBackground:(GDTApplication *)app {
- (void)appWillBackground:(GDTCORApplication *)app {
// Not entirely thread-safe, but it should be fine.
self->_runningInBackground = YES;
@@ -191,49 +198,75 @@ static NSString *const ktargetToInFlightPackagesKey =
[self stopTimer];
// Create an immediate background task to run until the end of the current queue of work.
__block GDTBackgroundIdentifier bgID = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgID];
__block GDTCORBackgroundIdentifier bgID = [app beginBackgroundTaskWithExpirationHandler:^{
if (bgID != GDTCORBackgroundIdentifierInvalid) {
[app endBackgroundTask:bgID];
bgID = GDTCORBackgroundIdentifierInvalid;
}
}];
dispatch_async(_coordinationQueue, ^{
[app endBackgroundTask:bgID];
if (bgID != GDTCORBackgroundIdentifierInvalid) {
[app endBackgroundTask:bgID];
bgID = GDTCORBackgroundIdentifierInvalid;
}
});
}
- (void)appWillTerminate:(GDTApplication *)application {
- (void)appWillTerminate:(GDTCORApplication *)application {
dispatch_sync(_coordinationQueue, ^{
[self stopTimer];
});
}
#pragma mark - GDTUploadPackageProtocol
#pragma mark - GDTCORUploadPackageProtocol
- (void)packageDelivered:(GDTUploadPackage *)package successful:(BOOL)successful {
- (void)packageDelivered:(GDTCORUploadPackage *)package successful:(BOOL)successful {
if (!_coordinationQueue) {
return;
}
dispatch_async(_coordinationQueue, ^{
NSNumber *targetNumber = @(package.target);
[self->_targetToInFlightPackages removeObjectForKey:targetNumber];
id<GDTPrioritizer> prioritizer = self->_registrar.targetToPrioritizer[targetNumber];
if (!prioritizer) {
GDTLogError(GDTMCEPrioritizerError, @"A prioritizer should be registered for this target: %@",
targetNumber);
NSMutableDictionary<NSNumber *, GDTCORUploadPackage *> *targetToInFlightPackages =
self->_targetToInFlightPackages;
GDTCORRegistrar *registrar = self->_registrar;
if (targetToInFlightPackages) {
[targetToInFlightPackages removeObjectForKey:targetNumber];
}
if ([prioritizer respondsToSelector:@selector(packageDelivered:successful:)]) {
[prioritizer packageDelivered:package successful:successful];
if (registrar) {
id<GDTCORPrioritizer> prioritizer = registrar.targetToPrioritizer[targetNumber];
if (!prioritizer) {
GDTCORLogError(GDTCORMCEPrioritizerError,
@"A prioritizer should be registered for this target: %@", targetNumber);
}
if ([prioritizer respondsToSelector:@selector(packageDelivered:successful:)]) {
[prioritizer packageDelivered:package successful:successful];
}
}
[self.storage removeEvents:package.events];
});
}
- (void)packageExpired:(GDTUploadPackage *)package {
- (void)packageExpired:(GDTCORUploadPackage *)package {
if (!_coordinationQueue) {
return;
}
dispatch_async(_coordinationQueue, ^{
NSNumber *targetNumber = @(package.target);
[self->_targetToInFlightPackages removeObjectForKey:targetNumber];
id<GDTPrioritizer> prioritizer = self->_registrar.targetToPrioritizer[targetNumber];
id<GDTUploader> uploader = self->_registrar.targetToUploader[targetNumber];
if ([prioritizer respondsToSelector:@selector(packageExpired:)]) {
[prioritizer packageExpired:package];
NSMutableDictionary<NSNumber *, GDTCORUploadPackage *> *targetToInFlightPackages =
self->_targetToInFlightPackages;
GDTCORRegistrar *registrar = self->_registrar;
if (targetToInFlightPackages) {
[targetToInFlightPackages removeObjectForKey:targetNumber];
}
if ([uploader respondsToSelector:@selector(packageExpired:)]) {
[uploader packageExpired:package];
if (registrar) {
id<GDTCORPrioritizer> prioritizer = registrar.targetToPrioritizer[targetNumber];
id<GDTCORUploader> uploader = registrar.targetToUploader[targetNumber];
if ([prioritizer respondsToSelector:@selector(packageExpired:)]) {
[prioritizer packageExpired:package];
}
if ([uploader respondsToSelector:@selector(packageExpired:)]) {
[uploader packageExpired:package];
}
}
});
}
@@ -14,16 +14,17 @@
* limitations under the License.
*/
#import <GoogleDataTransport/GDTUploadPackage.h>
#import <GoogleDataTransport/GDTCORUploadPackage.h>
#import <GoogleDataTransport/GDTClock.h>
#import <GoogleDataTransport/GDTConsoleLogger.h>
#import <GoogleDataTransport/GDTCORClock.h>
#import <GoogleDataTransport/GDTCORConsoleLogger.h>
#import <GoogleDataTransport/GDTCORStoredEvent.h>
#import "GDTLibrary/Private/GDTStorage_Private.h"
#import "GDTLibrary/Private/GDTUploadCoordinator.h"
#import "GDTLibrary/Private/GDTUploadPackage_Private.h"
#import "GDTCORLibrary/Private/GDTCORStorage_Private.h"
#import "GDTCORLibrary/Private/GDTCORUploadCoordinator.h"
#import "GDTCORLibrary/Private/GDTCORUploadPackage_Private.h"
@implementation GDTUploadPackage {
@implementation GDTCORUploadPackage {
/** If YES, the package's -completeDelivery method has been called. */
BOOL _isDelivered;
@@ -34,13 +35,13 @@
NSTimer *_expirationTimer;
}
- (instancetype)initWithTarget:(GDTTarget)target {
- (instancetype)initWithTarget:(GDTCORTarget)target {
self = [super init];
if (self) {
_target = target;
_storage = [GDTStorage sharedInstance];
_deliverByTime = [GDTClock clockSnapshotInTheFuture:180000];
_handler = [GDTUploadCoordinator sharedInstance];
_storage = [GDTCORStorage sharedInstance];
_deliverByTime = [GDTCORClock clockSnapshotInTheFuture:180000];
_handler = [GDTCORUploadCoordinator sharedInstance];
_expirationTimer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:@selector(checkIfPackageIsExpired:)
@@ -51,7 +52,7 @@
}
- (instancetype)copy {
GDTUploadPackage *newPackage = [[GDTUploadPackage alloc] initWithTarget:_target];
GDTCORUploadPackage *newPackage = [[GDTCORUploadPackage alloc] initWithTarget:_target];
newPackage->_events = [_events copy];
return newPackage;
}
@@ -68,7 +69,7 @@
[_expirationTimer invalidate];
}
- (void)setStorage:(GDTStorage *)storage {
- (void)setStorage:(GDTCORStorage *)storage {
if (storage != _storage) {
_storage = storage;
}
@@ -76,8 +77,8 @@
- (void)completeDelivery {
if (_isDelivered) {
GDTLogError(GDTMCEDeliverTwice, @"%@",
@"It's an API violation to call -completeDelivery twice.");
GDTCORLogError(GDTCORMCEDeliverTwice, @"%@",
@"It's an API violation to call -completeDelivery twice.");
}
_isDelivered = YES;
if (!_isHandled && _handler &&
@@ -98,7 +99,7 @@
}
- (void)checkIfPackageIsExpired:(NSTimer *)timer {
if ([[GDTClock snapshot] isAfter:_deliverByTime]) {
if ([[GDTCORClock snapshot] isAfter:_deliverByTime]) {
if (_handler && [_handler respondsToSelector:@selector(packageExpired:)]) {
_isHandled = YES;
[_expirationTimer invalidate];
@@ -110,19 +111,19 @@
#pragma mark - NSSecureCoding
/** The keyed archiver key for the events property. */
static NSString *const kEventsKey = @"GDTUploadPackageEventsKey";
static NSString *const kEventsKey = @"GDTCORUploadPackageEventsKey";
/** The keyed archiver key for the _isHandled property. */
static NSString *const kDeliverByTimeKey = @"GDTUploadPackageDeliveryByTimeKey";
static NSString *const kDeliverByTimeKey = @"GDTCORUploadPackageDeliveryByTimeKey";
/** The keyed archiver key for the _isHandled ivar. */
static NSString *const kIsHandledKey = @"GDTUploadPackageIsHandledKey";
static NSString *const kIsHandledKey = @"GDTCORUploadPackageIsHandledKey";
/** The keyed archiver key for the handler property. */
static NSString *const kHandlerKey = @"GDTUploadPackageHandlerKey";
static NSString *const kHandlerKey = @"GDTCORUploadPackageHandlerKey";
/** The keyed archiver key for the target property. */
static NSString *const kTargetKey = @"GDTUploadPackageTargetKey";
static NSString *const kTargetKey = @"GDTCORUploadPackageTargetKey";
+ (BOOL)supportsSecureCoding {
return YES;
@@ -137,14 +138,15 @@ static NSString *const kTargetKey = @"GDTUploadPackageTargetKey";
}
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder {
GDTTarget target = [aDecoder decodeIntegerForKey:kTargetKey];
GDTCORTarget target = [aDecoder decodeIntegerForKey:kTargetKey];
self = [self initWithTarget:target];
if (self) {
_events = [aDecoder decodeObjectOfClass:[NSSet class] forKey:kEventsKey];
_deliverByTime = [aDecoder decodeObjectOfClass:[GDTClock class] forKey:kDeliverByTimeKey];
NSSet *classes = [NSSet setWithObjects:[NSSet class], [GDTCORStoredEvent class], nil];
_events = [aDecoder decodeObjectOfClasses:classes forKey:kEventsKey];
_deliverByTime = [aDecoder decodeObjectOfClass:[GDTCORClock class] forKey:kDeliverByTimeKey];
_isHandled = [aDecoder decodeBoolForKey:kIsHandledKey];
// Isn't technically NSSecureCoding, because we don't know the class of this object.
_handler = [aDecoder decodeObjectForKey:kHandlerKey];
// _handler isn't technically NSSecureCoding, because we don't know the class of this object.
// but it gets decoded anyway.
}
return self;
}
@@ -14,13 +14,13 @@
* limitations under the License.
*/
#import <GoogleDataTransport/GDTEvent.h>
#import <GoogleDataTransport/GDTCOREvent.h>
#import <GoogleDataTransport/GDTClock.h>
#import <GoogleDataTransport/GDTCORClock.h>
NS_ASSUME_NONNULL_BEGIN
@interface GDTEvent ()
@interface GDTCOREvent ()
/** The serialized bytes of the event data object. */
@property(nonatomic) NSData *dataObjectTransportBytes;
@@ -21,7 +21,7 @@
NS_ASSUME_NONNULL_BEGIN
/** This class helps determine upload conditions by determining connectivity. */
@interface GDTReachability : NSObject
@interface GDTCORReachability : NSObject
/** The current set flags indicating network conditions */
+ (SCNetworkReachabilityFlags)currentFlags;
@@ -14,9 +14,9 @@
* limitations under the License.
*/
#import "GDTLibrary/Private/GDTReachability.h"
#import "GDTCORLibrary/Private/GDTCORReachability.h"
@interface GDTReachability ()
@interface GDTCORReachability ()
/** Allows manually setting the flags for testing purposes. */
@property(nonatomic, readwrite) SCNetworkReachabilityFlags flags;
@@ -14,9 +14,9 @@
* limitations under the License.
*/
#import <GoogleDataTransport/GDTRegistrar.h>
#import <GoogleDataTransport/GDTCORRegistrar.h>
@interface GDTRegistrar ()
@interface GDTCORRegistrar ()
NS_ASSUME_NONNULL_BEGIN
@@ -24,11 +24,11 @@ NS_ASSUME_NONNULL_BEGIN
@property(nonatomic, readonly) dispatch_queue_t registrarQueue;
/** A map of targets to backend implementations. */
@property(atomic, readonly) NSMutableDictionary<NSNumber *, id<GDTUploader>> *targetToUploader;
@property(atomic, readonly) NSMutableDictionary<NSNumber *, id<GDTCORUploader>> *targetToUploader;
/** A map of targets to prioritizer implementations. */
@property(atomic, readonly)
NSMutableDictionary<NSNumber *, id<GDTPrioritizer>> *targetToPrioritizer;
NSMutableDictionary<NSNumber *, id<GDTCORPrioritizer>> *targetToPrioritizer;
@end
@@ -16,15 +16,15 @@
#import <Foundation/Foundation.h>
#import <GoogleDataTransport/GDTLifecycle.h>
#import <GoogleDataTransport/GDTCORLifecycle.h>
@class GDTEvent;
@class GDTStoredEvent;
@class GDTCOREvent;
@class GDTCORStoredEvent;
NS_ASSUME_NONNULL_BEGIN
/** Manages the storage of events. This class is thread-safe. */
@interface GDTStorage : NSObject <NSSecureCoding, GDTLifecycleProtocol>
@interface GDTCORStorage : NSObject <NSSecureCoding, GDTCORLifecycleProtocol>
/** Creates and/or returns the storage singleton.
*
@@ -33,17 +33,17 @@ NS_ASSUME_NONNULL_BEGIN
+ (instancetype)sharedInstance;
/** Stores event.dataObjectTransportBytes into a shared on-device folder and tracks the event via
* a GDTStoredEvent instance.
* a GDTCORStoredEvent instance.
*
* @param event The event to store.
*/
- (void)storeEvent:(GDTEvent *)event;
- (void)storeEvent:(GDTCOREvent *)event;
/** Removes a set of events from storage specified by their hash.
*
* @param events The set of stored events to remove.
*/
- (void)removeEvents:(NSSet<GDTStoredEvent *> *)events;
- (void)removeEvents:(NSSet<GDTCORStoredEvent *> *)events;
@end
@@ -14,30 +14,30 @@
* limitations under the License.
*/
#import "GDTLibrary/Private/GDTStorage.h"
#import "GDTCORLibrary/Private/GDTCORStorage.h"
@class GDTUploadCoordinator;
@class GDTCORUploadCoordinator;
NS_ASSUME_NONNULL_BEGIN
@interface GDTStorage ()
@interface GDTCORStorage ()
/** The queue on which all storage work will occur. */
@property(nonatomic) dispatch_queue_t storageQueue;
/** A map of targets to a set of stored events. */
@property(nonatomic)
NSMutableDictionary<NSNumber *, NSMutableSet<GDTStoredEvent *> *> *targetToEventSet;
NSMutableDictionary<NSNumber *, NSMutableSet<GDTCORStoredEvent *> *> *targetToEventSet;
/** All the events that have been stored. */
@property(readonly, nonatomic) NSMutableOrderedSet<GDTStoredEvent *> *storedEvents;
@property(readonly, nonatomic) NSMutableOrderedSet<GDTCORStoredEvent *> *storedEvents;
/** The upload coordinator instance used by this storage instance. */
@property(nonatomic) GDTUploadCoordinator *uploadCoordinator;
@property(nonatomic) GDTCORUploadCoordinator *uploadCoordinator;
/** If YES, every call to -storeLog results in background task and serializes the singleton to disk.
*/
@property(nonatomic, readonly) BOOL runningInBackground;
@property(nonatomic) BOOL runningInBackground;
/** Returns the path to the keyed archive of the singleton. This is where the singleton is saved
* to disk during certain app lifecycle events.
@@ -16,11 +16,11 @@
#import <Foundation/Foundation.h>
#import <GoogleDataTransport/GDTLifecycle.h>
#import <GoogleDataTransport/GDTCORLifecycle.h>
@class GDTEvent;
@class GDTCOREvent;
@protocol GDTEventTransformer;
@protocol GDTCOREventTransformer;
NS_ASSUME_NONNULL_BEGIN
@@ -30,7 +30,7 @@ NS_ASSUME_NONNULL_BEGIN
* maintain state (or at least, there's nothing to stop them from doing that) and the same instances
* may be used across multiple instances.
*/
@interface GDTTransformer : NSObject <GDTLifecycleProtocol>
@interface GDTCORTransformer : NSObject <GDTCORLifecycleProtocol>
/** Instantiates or returns the event transformer singleton.
*
@@ -46,8 +46,8 @@ NS_ASSUME_NONNULL_BEGIN
* @param event The event to apply transformers on.
* @param transformers The list of transformers to apply.
*/
- (void)transformEvent:(GDTEvent *)event
withTransformers:(nullable NSArray<id<GDTEventTransformer>> *)transformers;
- (void)transformEvent:(GDTCOREvent *)event
withTransformers:(nullable NSArray<id<GDTCOREventTransformer>> *)transformers;
@end
@@ -14,19 +14,19 @@
* limitations under the License.
*/
#import "GDTLibrary/Private/GDTTransformer.h"
#import "GDTCORLibrary/Private/GDTCORTransformer.h"
@class GDTStorage;
@class GDTCORStorage;
NS_ASSUME_NONNULL_BEGIN
@interface GDTTransformer ()
@interface GDTCORTransformer ()
/** The queue on which all work will occur. */
@property(nonatomic) dispatch_queue_t eventWritingQueue;
/** The storage instance used to store events. Should only be used to inject a testing fake. */
@property(nonatomic) GDTStorage *storageInstance;
@property(nonatomic) GDTCORStorage *storageInstance;
/** If YES, every call to -transformEvent will result in a background task. */
@property(nonatomic, readonly) BOOL runningInBackground;
@@ -14,25 +14,25 @@
* limitations under the License.
*/
#import <GoogleDataTransport/GDTTransport.h>
#import <GoogleDataTransport/GDTCORTransport.h>
@class GDTTransformer;
@class GDTCORTransformer;
NS_ASSUME_NONNULL_BEGIN
@interface GDTTransport ()
@interface GDTCORTransport ()
/** The mapping identifier that the target backend will use to map the transport bytes to proto. */
@property(nonatomic) NSString *mappingID;
/** The transformers that will operate on events sent by this transport. */
@property(nonatomic) NSArray<id<GDTEventTransformer>> *transformers;
@property(nonatomic) NSArray<id<GDTCOREventTransformer>> *transformers;
/** The target backend of this transport. */
@property(nonatomic) NSInteger target;
/** The transformer instance to used to transform events. Allows injecting a fake during testing. */
@property(nonatomic) GDTTransformer *transformerInstance;
@property(nonatomic) GDTCORTransformer *transformerInstance;
@end
@@ -16,21 +16,21 @@
#import <Foundation/Foundation.h>
#import <GoogleDataTransport/GDTLifecycle.h>
#import <GoogleDataTransport/GDTRegistrar.h>
#import <GoogleDataTransport/GDTCORLifecycle.h>
#import <GoogleDataTransport/GDTCORRegistrar.h>
#import "GDTLibrary/Private/GDTUploadPackage_Private.h"
#import "GDTCORLibrary/Private/GDTCORUploadPackage_Private.h"
@class GDTClock;
@class GDTStorage;
@class GDTCORClock;
@class GDTCORStorage;
NS_ASSUME_NONNULL_BEGIN
/** This class connects storage and uploader implementations, providing events to an uploader
* and informing the storage what events were successfully uploaded or not.
*/
@interface GDTUploadCoordinator
: NSObject <NSSecureCoding, GDTLifecycleProtocol, GDTUploadPackageProtocol>
@interface GDTCORUploadCoordinator
: NSObject <NSSecureCoding, GDTCORLifecycleProtocol, GDTCORUploadPackageProtocol>
/** The queue on which all upload coordination will occur. Also used by a dispatch timer. */
/** Creates and/or returrns the singleton.
@@ -51,13 +51,13 @@ NS_ASSUME_NONNULL_BEGIN
/** The map of targets to in-flight packages. */
@property(nonatomic, readonly)
NSMutableDictionary<NSNumber *, GDTUploadPackage *> *targetToInFlightPackages;
NSMutableDictionary<NSNumber *, GDTCORUploadPackage *> *targetToInFlightPackages;
/** The storage object the coordinator will use. Generally used for testing. */
@property(nonatomic) GDTStorage *storage;
@property(nonatomic) GDTCORStorage *storage;
/** The registrar object the coordinator will use. Generally used for testing. */
@property(nonatomic) GDTRegistrar *registrar;
@property(nonatomic) GDTCORRegistrar *registrar;
/** If YES, completion and other operations will result in serializing the singleton to disk. */
@property(nonatomic, readonly) BOOL runningInBackground;
@@ -67,7 +67,7 @@ NS_ASSUME_NONNULL_BEGIN
*
* @param target The target that should force an upload.
*/
- (void)forceUploadForTarget:(GDTTarget)target;
- (void)forceUploadForTarget:(GDTCORTarget)target;
/** Starts the upload timer. */
- (void)startTimer;
@@ -14,16 +14,16 @@
* limitations under the License.
*/
#import <GoogleDataTransport/GDTUploadPackage.h>
#import <GoogleDataTransport/GDTCORUploadPackage.h>
@class GDTStorage;
@class GDTCORStorage;
@interface GDTUploadPackage ()
@interface GDTCORUploadPackage ()
/** The storage object this upload package will use to resolve event hashes to files. */
@property(nonatomic) GDTStorage *storage;
@property(nonatomic) GDTCORStorage *storage;
/** A handler that will receive callbacks for certain events. */
@property(nonatomic) id<NSSecureCoding, GDTUploadPackageProtocol> handler;
@property(nonatomic) id<NSSecureCoding, GDTCORUploadPackageProtocol> handler;
@end
@@ -0,0 +1,91 @@
/*
* Copyright 2019 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <Foundation/Foundation.h>
#import <GoogleDataTransport/GDTCORConsoleLogger.h>
/** A block type that could be run instead of normal assertion logging. No return type, no params.
*/
typedef void (^GDTCORAssertionBlock)(void);
/** Returns the result of executing a soft-linked method present in unit tests that allows a block
* to be run instead of normal assertion logging. This helps ameliorate issues with catching
* exceptions that occur on a dispatch_queue.
*
* @return A block that can be run instead of normal assert printing.
*/
FOUNDATION_EXPORT GDTCORAssertionBlock _Nullable GDTCORAssertionBlockToRunInstead(void);
#if defined(NS_BLOCK_ASSERTIONS)
#define GDTCORAssert(condition, ...) \
do { \
} while (0);
#define GDTCORFatalAssert(condition, ...) \
do { \
} while (0);
#else // defined(NS_BLOCK_ASSERTIONS)
/** Asserts using a console log, unless a block was specified to be run instead.
*
* @param condition The condition you'd expect to be YES.
*/
#define GDTCORAssert(condition, ...) \
do { \
if (__builtin_expect(!(condition), 0)) { \
GDTCORAssertionBlock assertionBlock = GDTCORAssertionBlockToRunInstead(); \
if (assertionBlock) { \
assertionBlock(); \
} else { \
__PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \
NSString *__assert_file__ = [NSString stringWithUTF8String:__FILE__]; \
__assert_file__ = __assert_file__ ? __assert_file__ : @"<Unknown File>"; \
GDTCORLogError(GDTCORMCEGeneralError, @"Assertion failed (%@:%d): %s,", __assert_file__, \
__LINE__, ##__VA_ARGS__); \
__PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \
} \
} \
} while (0);
/** Asserts by logging to the console and throwing an exception if NS_BLOCK_ASSERTIONS is not
* defined.
*
* @param condition The condition you'd expect to be YES.
*/
#define GDTCORFatalAssert(condition, ...) \
do { \
__PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \
if (__builtin_expect(!(condition), 0)) { \
NSString *__assert_file__ = [NSString stringWithUTF8String:__FILE__]; \
__assert_file__ = __assert_file__ ? __assert_file__ : @"<Unknown File>"; \
GDTCORLogError(GDTCORMCEFatalAssertion, \
@"Fatal assertion encountered, please open an issue at " \
"https://github.com/firebase/firebase-ios-sdk/issues " \
"(%@:%d): %s,", \
__assert_file__, __LINE__, ##__VA_ARGS__); \
[[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \
object:self \
file:__assert_file__ \
lineNumber:__LINE__ \
description:@"%@", ##__VA_ARGS__]; \
} \
__PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \
} while (0);
#endif // defined(NS_BLOCK_ASSERTIONS)
@@ -19,7 +19,7 @@
NS_ASSUME_NONNULL_BEGIN
/** This class manages the device clock and produces snapshots of the current time. */
@interface GDTClock : NSObject <NSSecureCoding>
@interface GDTCORClock : NSObject <NSSecureCoding>
/** The wallclock time, UTC, in milliseconds. */
@property(nonatomic, readonly) int64_t timeMillis;
@@ -33,13 +33,13 @@ NS_ASSUME_NONNULL_BEGIN
/** The device uptime when this clock was created. */
@property(nonatomic, readonly) int64_t uptime;
/** Creates a GDTClock object using the current time and offsets.
/** Creates a GDTCORClock object using the current time and offsets.
*
* @return A new GDTClock object representing the current time state.
* @return A new GDTCORClock object representing the current time state.
*/
+ (instancetype)snapshot;
/** Creates a GDTClock object representing a time in the future, relative to now.
/** Creates a GDTCORClock object representing a time in the future, relative to now.
*
* @param millisInTheFuture The millis in the future from now this clock should represent.
* @return An instance representing a future time.
@@ -50,7 +50,7 @@ NS_ASSUME_NONNULL_BEGIN
*
* @return YES if the calling clock's time is after the given clock's time.
*/
- (BOOL)isAfter:(GDTClock *)otherClock;
- (BOOL)isAfter:(GDTCORClock *)otherClock;
@end
@@ -23,57 +23,62 @@
* - MCW => MessageCodeWarning
* - MCE => MessageCodeError
*/
typedef NS_ENUM(NSInteger, GDTMessageCode) {
typedef NS_ENUM(NSInteger, GDTCORMessageCode) {
/** For warning messages concerning transportBytes: not being implemented by a data object. */
GDTMCWDataObjectMissingBytesImpl = 1,
GDTCORMCWDataObjectMissingBytesImpl = 1,
/** For warning messages concerning a failed event upload. */
GDTMCWUploadFailed = 2,
GDTCORMCWUploadFailed = 2,
/** For warning messages concerning a forced event upload. */
GDTMCWForcedUpload = 3,
GDTCORMCWForcedUpload = 3,
/** For warning messages concerning a failed reachability call. */
GDTMCWReachabilityFailed = 4,
GDTCORMCWReachabilityFailed = 4,
/** For error messages concerning transform: not being implemented by an event transformer. */
GDTMCETransformerDoesntImplementTransform = 1000,
GDTCORMCETransformerDoesntImplementTransform = 1000,
/** For error messages concerning the creation of a directory failing. */
GDTMCEDirectoryCreationError = 1001,
GDTCORMCEDirectoryCreationError = 1001,
/** For error messages concerning the writing of a event file. */
GDTMCEFileWriteError = 1002,
GDTCORMCEFileWriteError = 1002,
/** For error messages concerning the lack of a prioritizer for a given backend. */
GDTMCEPrioritizerError = 1003,
GDTCORMCEPrioritizerError = 1003,
/** For error messages concerning a package delivery API violation. */
GDTMCEDeliverTwice = 1004,
GDTCORMCEDeliverTwice = 1004,
/** For error messages concerning an error in an implementation of -transportBytes. */
GDTMCETransportBytesError = 1005,
GDTCORMCETransportBytesError = 1005,
/** For general purpose error messages in a dependency. */
GDTMCEGeneralError = 1006
GDTCORMCEGeneralError = 1006,
/** For fatal errors. Please go to https://github.com/firebase/firebase-ios-sdk/issues and open
* an issue if you encounter an error with this code.
*/
GDTCORMCEFatalAssertion = 1007
};
/** */
FOUNDATION_EXPORT
void GDTLog(GDTMessageCode code, NSString *_Nonnull format, ...);
void GDTCORLog(GDTCORMessageCode code, NSString *_Nonnull format, ...);
/** Returns the string that represents some message code.
*
* @param code The code to convert to a string.
* @return The string representing the message code.
*/
FOUNDATION_EXPORT NSString *_Nonnull GDTMessageCodeEnumToString(GDTMessageCode code);
FOUNDATION_EXPORT NSString *_Nonnull GDTCORMessageCodeEnumToString(GDTCORMessageCode code);
// A define to wrap GULLogWarning with slightly more convenient usage.
#define GDTLogWarning(MESSAGE_CODE, MESSAGE_FORMAT, ...) \
GDTLog(MESSAGE_CODE, MESSAGE_FORMAT, __VA_ARGS__);
#define GDTCORLogWarning(MESSAGE_CODE, MESSAGE_FORMAT, ...) \
GDTCORLog(MESSAGE_CODE, MESSAGE_FORMAT, __VA_ARGS__);
// A define to wrap GULLogError with slightly more convenient usage and a failing assert.
#define GDTLogError(MESSAGE_CODE, MESSAGE_FORMAT, ...) \
GDTLog(MESSAGE_CODE, MESSAGE_FORMAT, __VA_ARGS__);
#define GDTCORLogError(MESSAGE_CODE, MESSAGE_FORMAT, ...) \
GDTCORLog(MESSAGE_CODE, MESSAGE_FORMAT, __VA_ARGS__);
@@ -19,7 +19,7 @@
NS_ASSUME_NONNULL_BEGIN
/** This class represents a future data object, determined at instantiation time. */
@interface GDTDataFuture : NSObject <NSSecureCoding>
@interface GDTCORDataFuture : NSObject <NSSecureCoding>
/** The data, computed on-demand, depending on the initializer. */
@property(nullable, readonly, nonatomic) NSData *data;
@@ -16,36 +16,36 @@
#import <Foundation/Foundation.h>
#import <GoogleDataTransport/GDTEventDataObject.h>
#import <GoogleDataTransport/GDTCOREventDataObject.h>
@class GDTClock;
@class GDTDataFuture;
@class GDTStoredEvent;
@class GDTCORClock;
@class GDTCORDataFuture;
@class GDTCORStoredEvent;
NS_ASSUME_NONNULL_BEGIN
/** The different possible quality of service specifiers. High values indicate high priority. */
typedef NS_ENUM(NSInteger, GDTEventQoS) {
typedef NS_ENUM(NSInteger, GDTCOREventQoS) {
/** The QoS tier wasn't set, and won't ever be sent. */
GDTEventQoSUnknown = 0,
GDTCOREventQoSUnknown = 0,
/** This event is internal telemetry data that should not be sent on its own if possible. */
GDTEventQoSTelemetry = 1,
GDTCOREventQoSTelemetry = 1,
/** This event should be sent, but in a batch only roughly once per day. */
GDTEventQoSDaily = 2,
GDTCOREventQoSDaily = 2,
/** This event should be sent when requested by the uploader. */
GDTEventQosDefault = 3,
GDTCOREventQosDefault = 3,
/** This event should be sent immediately along with any other data that can be batched. */
GDTEventQoSFast = 4,
GDTCOREventQoSFast = 4,
/** This event should only be uploaded on wifi. */
GDTEventQoSWifiOnly = 5,
GDTCOREventQoSWifiOnly = 5,
};
@interface GDTEvent : NSObject <NSSecureCoding>
@interface GDTCOREvent : NSObject <NSSecureCoding>
/** The mapping identifier, to allow backends to map the transport bytes to a proto. */
@property(readonly, nonatomic) NSString *mappingID;
@@ -54,14 +54,14 @@ typedef NS_ENUM(NSInteger, GDTEventQoS) {
@property(readonly, nonatomic) NSInteger target;
/** The data object encapsulated in the transport of your choice, as long as it implements
* the GDTEventDataObject protocol. */
@property(nullable, nonatomic) id<GDTEventDataObject> dataObject;
* the GDTCOREventDataObject protocol. */
@property(nullable, nonatomic) id<GDTCOREventDataObject> dataObject;
/** The quality of service tier this event belongs to. */
@property(nonatomic) GDTEventQoS qosTier;
@property(nonatomic) GDTCOREventQoS qosTier;
/** The clock snapshot at the time of the event. */
@property(nonatomic) GDTClock *clockSnapshot;
@property(nonatomic) GDTCORClock *clockSnapshot;
/** A dictionary provided to aid prioritizers by allowing the passing of arbitrary data. It will be
* retained by a copy in -copy, but not used for -hash.
@@ -82,12 +82,12 @@ typedef NS_ENUM(NSInteger, GDTEventQoS) {
- (instancetype)initWithMappingID:(NSString *)mappingID
target:(NSInteger)target NS_DESIGNATED_INITIALIZER;
/** Returns the GDTStoredEvent equivalent of self.
/** Returns the GDTCORStoredEvent equivalent of self.
*
* @param dataFuture The data future representing the transport bytes of the original event.
* @return An equivalent GDTStoredEvent.
* @return An equivalent GDTCORStoredEvent.
*/
- (GDTStoredEvent *)storedEventWithDataFuture:(GDTDataFuture *)dataFuture;
- (GDTCORStoredEvent *)storedEventWithDataFuture:(GDTCORDataFuture *)dataFuture;
@end
@@ -21,7 +21,7 @@ NS_ASSUME_NONNULL_BEGIN
/** This protocol defines the common interface that event protos should implement regardless of the
* underlying transport technology (protobuf, nanopb, etc).
*/
@protocol GDTEventDataObject <NSObject>
@protocol GDTCOREventDataObject <NSObject>
@required
@@ -16,12 +16,12 @@
#import <Foundation/Foundation.h>
@class GDTEvent;
@class GDTCOREvent;
NS_ASSUME_NONNULL_BEGIN
/** Defines the API that event transformers must adopt. */
@protocol GDTEventTransformer <NSObject>
@protocol GDTCOREventTransformer <NSObject>
@required
@@ -31,7 +31,7 @@ NS_ASSUME_NONNULL_BEGIN
* @param event The event to transform.
* @return A transformed event, or nil if the transformation dropped the event.
*/
- (GDTEvent *)transform:(GDTEvent *)event;
- (GDTCOREvent *)transform:(GDTCOREvent *)event;
@end
@@ -16,35 +16,36 @@
#import <Foundation/Foundation.h>
#import <GoogleDataTransport/GDTPlatform.h>
#import <GoogleDataTransport/GDTCORPlatform.h>
@class GDTEvent;
@class GDTCOREvent;
NS_ASSUME_NONNULL_BEGIN
/** A protocol defining the lifecycle events objects in the library must respond to immediately. */
@protocol GDTLifecycleProtocol <NSObject>
@protocol GDTCORLifecycleProtocol <NSObject>
@optional
/** Indicates an imminent app termination in the rare occurrence when -applicationWillTerminate: has
* been called.
*
* @param app The GDTApplication instance.
* @param app The GDTCORApplication instance.
*/
- (void)appWillTerminate:(GDTApplication *)app;
- (void)appWillTerminate:(GDTCORApplication *)app;
/** Indicates that the app is moving to background and eventual suspension.
/** Indicates that the app is moving to background and eventual suspension or the current UIScene is
* deactivating.
*
* @param app The GDTApplication instance.
* @param app The GDTCORApplication instance.
*/
- (void)appWillBackground:(GDTApplication *)app;
- (void)appWillBackground:(GDTCORApplication *)app;
/** Indicates that the app is resuming operation.
/** Indicates that the app is resuming operation or a UIScene is activating.
*
* @param app The GDTApplication instance.
* @param app The GDTCORApplication instance.
*/
- (void)appWillForeground:(GDTApplication *)app;
- (void)appWillForeground:(GDTCORApplication *)app;
@end
@@ -52,10 +53,10 @@ NS_ASSUME_NONNULL_BEGIN
*
* When backgrounding, the library doesn't stop processing events, it's just that several background
* tasks will end up being created for every event that's sent, and the stateful objects of the
* library (GDTStorage and GDTUploadCoordinator singletons) will deserialize themselves from and to
* disk before and after every operation, respectively.
* library (GDTCORStorage and GDTCORUploadCoordinator singletons) will deserialize themselves from
* and to disk before and after every operation, respectively.
*/
@interface GDTLifecycle : NSObject <GDTApplicationDelegate>
@interface GDTCORLifecycle : NSObject <GDTCORApplicationDelegate>
@end
@@ -26,61 +26,61 @@
NS_ASSUME_NONNULL_BEGIN
/** A notification sent out if the app is backgrounding. */
FOUNDATION_EXPORT NSString *const kGDTApplicationDidEnterBackgroundNotification;
FOUNDATION_EXPORT NSString *const kGDTCORApplicationDidEnterBackgroundNotification;
/** A notification sent out if the app is foregrounding. */
FOUNDATION_EXPORT NSString *const kGDTApplicationWillEnterForegroundNotification;
FOUNDATION_EXPORT NSString *const kGDTCORApplicationWillEnterForegroundNotification;
/** A notification sent out if the app is terminating. */
FOUNDATION_EXPORT NSString *const kGDTApplicationWillTerminateNotification;
FOUNDATION_EXPORT NSString *const kGDTCORApplicationWillTerminateNotification;
/** Compares flags with the WWAN reachability flag, if available, and returns YES if present.
*
* @param flags The set of reachability flags.
* @return YES if the WWAN flag is set, NO otherwise.
*/
BOOL GDTReachabilityFlagsContainWWAN(SCNetworkReachabilityFlags flags);
BOOL GDTCORReachabilityFlagsContainWWAN(SCNetworkReachabilityFlags flags);
/** A typedef identify background identifiers. */
typedef NSUInteger GDTBackgroundIdentifier;
typedef volatile NSUInteger GDTCORBackgroundIdentifier;
/** A background task's invalid sentinel value. */
FOUNDATION_EXPORT const GDTBackgroundIdentifier GDTBackgroundIdentifierInvalid;
FOUNDATION_EXPORT const GDTCORBackgroundIdentifier GDTCORBackgroundIdentifierInvalid;
#if TARGET_OS_IOS || TARGET_OS_TV
/** A protocol that wraps UIApplicationDelegate or NSObject protocol, depending on the platform. */
@protocol GDTApplicationDelegate <UIApplicationDelegate>
@protocol GDTCORApplicationDelegate <UIApplicationDelegate>
#elif TARGET_OS_OSX
@protocol GDTApplicationDelegate <NSApplicationDelegate>
@protocol GDTCORApplicationDelegate <NSApplicationDelegate>
#else
@protocol GDTApplicationDelegate <NSObject>
@protocol GDTCORApplicationDelegate <NSObject>
#endif // TARGET_OS_IOS || TARGET_OS_TV
@end
/** A cross-platform application class. */
@interface GDTApplication : NSObject <GDTApplicationDelegate>
@interface GDTCORApplication : NSObject <GDTCORApplicationDelegate>
/** Creates and/or returns the shared application instance.
*
* @return The shared application instance.
*/
+ (nullable GDTApplication *)sharedApplication;
+ (nullable GDTCORApplication *)sharedApplication;
/** Creates a background task with the returned identifier if on a suitable platform.
*
* @param handler The handler block that is called if the background task expires.
* @return An identifier for the background task, or GDTBackgroundIdentifierInvalid if one couldn't
* be created.
* @return An identifier for the background task, or GDTCORBackgroundIdentifierInvalid if one
* couldn't be created.
*/
- (GDTBackgroundIdentifier)beginBackgroundTaskWithExpirationHandler:
- (GDTCORBackgroundIdentifier)beginBackgroundTaskWithExpirationHandler:
(void (^__nullable)(void))handler;
/** Ends the background task if the identifier is valid.
*
* @param bgID The background task to end.
*/
- (void)endBackgroundTask:(GDTBackgroundIdentifier)bgID;
- (void)endBackgroundTask:(GDTCORBackgroundIdentifier)bgID;
@end
@@ -16,39 +16,39 @@
#import <Foundation/Foundation.h>
#import <GoogleDataTransport/GDTLifecycle.h>
#import <GoogleDataTransport/GDTUploadPackage.h>
#import <GoogleDataTransport/GDTCORLifecycle.h>
#import <GoogleDataTransport/GDTCORUploadPackage.h>
@class GDTStoredEvent;
@class GDTCORStoredEvent;
NS_ASSUME_NONNULL_BEGIN
/** Options that define a set of upload conditions. This is used to help minimize end user data
* consumption impact.
*/
typedef NS_OPTIONS(NSInteger, GDTUploadConditions) {
typedef NS_OPTIONS(NSInteger, GDTCORUploadConditions) {
/** An upload shouldn't be attempted, because there's no network. */
GDTUploadConditionNoNetwork = 1 << 0,
GDTCORUploadConditionNoNetwork = 1 << 0,
/** An upload would likely use mobile data. */
GDTUploadConditionMobileData = 1 << 1,
GDTCORUploadConditionMobileData = 1 << 1,
/** An upload would likely use wifi data. */
GDTUploadConditionWifiData = 1 << 2,
GDTCORUploadConditionWifiData = 1 << 2,
/** An upload uses some sort of network connection, but it's unclear which. */
GDTUploadConditionUnclearConnection = 1 << 3,
GDTCORUploadConditionUnclearConnection = 1 << 3,
/** A high priority event has occurred. */
GDTUploadConditionHighPriority = 1 << 4,
GDTCORUploadConditionHighPriority = 1 << 4,
};
/** This protocol defines the common interface of event prioritization. Prioritizers are
* stateful objects that prioritize events upon insertion into storage and remain prepared to return
* a set of filenames to the storage system.
*/
@protocol GDTPrioritizer <NSObject, GDTLifecycleProtocol, GDTUploadPackageProtocol>
@protocol GDTCORPrioritizer <NSObject, GDTCORLifecycleProtocol, GDTCORUploadPackageProtocol>
@required
@@ -58,7 +58,7 @@ typedef NS_OPTIONS(NSInteger, GDTUploadConditions) {
*
* @param event The event to prioritize.
*/
- (void)prioritizeEvent:(GDTStoredEvent *)event;
- (void)prioritizeEvent:(GDTCORStoredEvent *)event;
/** Returns a set of events to upload given a set of conditions.
*
@@ -66,7 +66,7 @@ typedef NS_OPTIONS(NSInteger, GDTUploadConditions) {
* @return An object to be used by the uploader to determine file URLs to upload with respect to the
* current conditions.
*/
- (GDTUploadPackage *)uploadPackageWithConditions:(GDTUploadConditions)conditions;
- (GDTCORUploadPackage *)uploadPackageWithConditions:(GDTCORUploadConditions)conditions;
@end
@@ -16,14 +16,14 @@
#import <Foundation/Foundation.h>
#import <GoogleDataTransport/GDTPrioritizer.h>
#import <GoogleDataTransport/GDTTargets.h>
#import <GoogleDataTransport/GDTUploader.h>
#import <GoogleDataTransport/GDTCORPrioritizer.h>
#import <GoogleDataTransport/GDTCORTargets.h>
#import <GoogleDataTransport/GDTCORUploader.h>
NS_ASSUME_NONNULL_BEGIN
/** Manages the registration of targets with the transport SDK. */
@interface GDTRegistrar : NSObject <GDTLifecycleProtocol>
@interface GDTCORRegistrar : NSObject <GDTCORLifecycleProtocol>
/** Creates and/or returns the singleton instance.
*
@@ -36,14 +36,14 @@ NS_ASSUME_NONNULL_BEGIN
* @param backend The backend object to register.
* @param target The target this backend object will be responsible for.
*/
- (void)registerUploader:(id<GDTUploader>)backend target:(GDTTarget)target;
- (void)registerUploader:(id<GDTCORUploader>)backend target:(GDTCORTarget)target;
/** Registers a event prioritizer implementation with the GoogleDataTransport infrastructure.
*
* @param prioritizer The prioritizer object to register.
* @param target The target this prioritizer object will be responsible for.
*/
- (void)registerPrioritizer:(id<GDTPrioritizer>)prioritizer target:(GDTTarget)target;
- (void)registerPrioritizer:(id<GDTCORPrioritizer>)prioritizer target:(GDTCORTarget)target;
@end
@@ -15,17 +15,17 @@
*/
#import <Foundation/Foundation.h>
#import <GoogleDataTransport/GDTDataFuture.h>
#import <GoogleDataTransport/GDTEvent.h>
#import <GoogleDataTransport/GDTCORDataFuture.h>
#import <GoogleDataTransport/GDTCOREvent.h>
@class GDTEvent;
@class GDTCOREvent;
NS_ASSUME_NONNULL_BEGIN
@interface GDTStoredEvent : NSObject <NSSecureCoding>
@interface GDTCORStoredEvent : NSObject <NSSecureCoding>
/** The data future representing the original event's transport bytes. */
@property(readonly, nonatomic) GDTDataFuture *dataFuture;
@property(readonly, nonatomic) GDTCORDataFuture *dataFuture;
/** The mapping identifier, to allow backends to map the transport bytes to a proto. */
@property(readonly, nonatomic) NSString *mappingID;
@@ -34,10 +34,10 @@ NS_ASSUME_NONNULL_BEGIN
@property(readonly, nonatomic) NSNumber *target;
/** The quality of service tier this event belongs to. */
@property(readonly, nonatomic) GDTEventQoS qosTier;
@property(readonly, nonatomic) GDTCOREventQoS qosTier;
/** The clock snapshot at the time of the event. */
@property(readonly, nonatomic) GDTClock *clockSnapshot;
@property(readonly, nonatomic) GDTCORClock *clockSnapshot;
/** A dictionary provided to aid prioritizers by allowing the passing of arbitrary data.
*
@@ -51,7 +51,7 @@ NS_ASSUME_NONNULL_BEGIN
* @param dataFuture The dataFuture this event represents.
* @return An instance of this class.
*/
- (instancetype)initWithEvent:(GDTEvent *)event dataFuture:(GDTDataFuture *)dataFuture;
- (instancetype)initWithEvent:(GDTCOREvent *)event dataFuture:(GDTCORDataFuture *)dataFuture;
@end
@@ -19,11 +19,11 @@
/** The list of targets supported by the shared transport infrastructure. If adding a new target,
* please use the previous value +1.
*/
typedef NS_ENUM(NSInteger, GDTTarget) {
typedef NS_ENUM(NSInteger, GDTCORTarget) {
/** A target only used in testing. */
kGDTTargetTest = 999,
kGDTCORTargetTest = 999,
/** The CCT target. */
kGDTTargetCCT = 1000,
kGDTCORTargetCCT = 1000,
};
@@ -16,13 +16,13 @@
#import <Foundation/Foundation.h>
#import <GoogleDataTransport/GDTEventTransformer.h>
#import <GoogleDataTransport/GDTCOREventTransformer.h>
@class GDTEvent;
@class GDTCOREvent;
NS_ASSUME_NONNULL_BEGIN
@interface GDTTransport : NSObject
@interface GDTCORTransport : NSObject
// Please use the designated initializer.
- (instancetype)init NS_UNAVAILABLE;
@@ -36,7 +36,7 @@ NS_ASSUME_NONNULL_BEGIN
* @return A transport that will send events.
*/
- (instancetype)initWithMappingID:(NSString *)mappingID
transformers:(nullable NSArray<id<GDTEventTransformer>> *)transformers
transformers:(nullable NSArray<id<GDTCOREventTransformer>> *)transformers
target:(NSInteger)target NS_DESIGNATED_INITIALIZER;
/** Copies and sends an internal telemetry event. Events sent using this API are lower in priority,
@@ -46,7 +46,7 @@ NS_ASSUME_NONNULL_BEGIN
*
* @param event The event to send.
*/
- (void)sendTelemetryEvent:(GDTEvent *)event;
- (void)sendTelemetryEvent:(GDTCOREvent *)event;
/** Copies and sends an SDK service data event. Events send using this API are higher in priority,
* and will cause a network request at some point in the relative near future.
@@ -55,13 +55,13 @@ NS_ASSUME_NONNULL_BEGIN
*
* @param event The event to send.
*/
- (void)sendDataEvent:(GDTEvent *)event;
- (void)sendDataEvent:(GDTCOREvent *)event;
/** Creates an event for use by this transport.
*
* @return An event that is suited for use by this transport.
*/
- (GDTEvent *)eventForTransport;
- (GDTCOREvent *)eventForTransport;
@end
@@ -16,14 +16,14 @@
#import <Foundation/Foundation.h>
#import <GoogleDataTransport/GDTTargets.h>
#import <GoogleDataTransport/GDTCORTargets.h>
@class GDTClock;
@class GDTStoredEvent;
@class GDTUploadPackage;
@class GDTCORClock;
@class GDTCORStoredEvent;
@class GDTCORUploadPackage;
/** A protocol that allows a handler to respond to package lifecycle events. */
@protocol GDTUploadPackageProtocol <NSObject>
@protocol GDTCORUploadPackageProtocol <NSObject>
@optional
@@ -33,37 +33,37 @@
*
* @param package The package that has expired.
*/
- (void)packageExpired:(GDTUploadPackage *)package;
- (void)packageExpired:(GDTCORUploadPackage *)package;
/** Indicates that the package was successfully delivered.
*
* @param package The package that was delivered.
*/
- (void)packageDelivered:(GDTUploadPackage *)package successful:(BOOL)successful;
- (void)packageDelivered:(GDTCORUploadPackage *)package successful:(BOOL)successful;
@end
/** This class is a container that's handed off to uploaders. */
@interface GDTUploadPackage : NSObject <NSSecureCoding>
@interface GDTCORUploadPackage : NSObject <NSSecureCoding>
/** The set of stored events in this upload package. */
@property(nonatomic) NSSet<GDTStoredEvent *> *events;
@property(nonatomic) NSSet<GDTCORStoredEvent *> *events;
/** The expiration time. If [[GDTClock snapshot] isAfter:deliverByTime] this package has expired.
/** The expiration time. If [[GDTCORClock snapshot] isAfter:deliverByTime] this package has expired.
*
* @note By default, the expiration time will be 3 minutes from creation.
*/
@property(nonatomic) GDTClock *deliverByTime;
@property(nonatomic) GDTCORClock *deliverByTime;
/** The target of this package. */
@property(nonatomic, readonly) GDTTarget target;
@property(nonatomic, readonly) GDTCORTarget target;
/** Initializes a package instance.
*
* @param target The target/destination of this package.
* @return An instance of this class.
*/
- (instancetype)initWithTarget:(GDTTarget)target NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithTarget:(GDTCORTarget)target NS_DESIGNATED_INITIALIZER;
// Please use the designated initializer.
- (instancetype)init NS_UNAVAILABLE;
@@ -16,16 +16,16 @@
#import <Foundation/Foundation.h>
#import <GoogleDataTransport/GDTClock.h>
#import <GoogleDataTransport/GDTLifecycle.h>
#import <GoogleDataTransport/GDTPrioritizer.h>
#import <GoogleDataTransport/GDTTargets.h>
#import <GoogleDataTransport/GDTUploadPackage.h>
#import <GoogleDataTransport/GDTCORClock.h>
#import <GoogleDataTransport/GDTCORLifecycle.h>
#import <GoogleDataTransport/GDTCORPrioritizer.h>
#import <GoogleDataTransport/GDTCORTargets.h>
#import <GoogleDataTransport/GDTCORUploadPackage.h>
NS_ASSUME_NONNULL_BEGIN
/** This protocol defines the common interface for uploader implementations. */
@protocol GDTUploader <NSObject, GDTLifecycleProtocol, GDTUploadPackageProtocol>
@protocol GDTCORUploader <NSObject, GDTCORLifecycleProtocol, GDTCORUploadPackageProtocol>
@required
@@ -34,13 +34,13 @@ NS_ASSUME_NONNULL_BEGIN
* @param conditions The conditions that the upload attempt is likely to occur under.
* @return YES if the uploader can make an upload attempt, NO otherwise.
*/
- (BOOL)readyToUploadWithConditions:(GDTUploadConditions)conditions;
- (BOOL)readyToUploadWithConditions:(GDTCORUploadConditions)conditions;
/** Uploads events to the backend using this specific backend's chosen format.
*
* @param package The event package to upload. Make sure to call -completeDelivery.
*/
- (void)uploadPackage:(GDTUploadPackage *)package;
- (void)uploadPackage:(GDTCORUploadPackage *)package;
@end
@@ -14,17 +14,17 @@
* limitations under the License.
*/
#import "GDTClock.h"
#import "GDTConsoleLogger.h"
#import "GDTDataFuture.h"
#import "GDTEvent.h"
#import "GDTEventDataObject.h"
#import "GDTEventTransformer.h"
#import "GDTLifecycle.h"
#import "GDTPrioritizer.h"
#import "GDTRegistrar.h"
#import "GDTStoredEvent.h"
#import "GDTTargets.h"
#import "GDTTransport.h"
#import "GDTUploadPackage.h"
#import "GDTUploader.h"
#import "GDTCORClock.h"
#import "GDTCORConsoleLogger.h"
#import "GDTCORDataFuture.h"
#import "GDTCOREvent.h"
#import "GDTCOREventDataObject.h"
#import "GDTCOREventTransformer.h"
#import "GDTCORLifecycle.h"
#import "GDTCORPrioritizer.h"
#import "GDTCORRegistrar.h"
#import "GDTCORStoredEvent.h"
#import "GDTCORTargets.h"
#import "GDTCORTransport.h"
#import "GDTCORUploadPackage.h"
#import "GDTCORUploader.h"
@@ -1,119 +0,0 @@
/*
* Copyright 2019 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "GDTLibrary/Public/GDTLifecycle.h"
#import <GoogleDataTransport/GDTEvent.h>
#import "GDTLibrary/Private/GDTRegistrar_Private.h"
#import "GDTLibrary/Private/GDTStorage_Private.h"
#import "GDTLibrary/Private/GDTTransformer_Private.h"
#import "GDTLibrary/Private/GDTUploadCoordinator.h"
@implementation GDTLifecycle
+ (void)load {
[self sharedInstance];
}
/** Creates/returns the singleton instance of this class.
*
* @return The singleton instance of this class.
*/
+ (instancetype)sharedInstance {
static GDTLifecycle *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[GDTLifecycle alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
selector:@selector(applicationDidEnterBackground:)
name:kGDTApplicationDidEnterBackgroundNotification
object:nil];
[notificationCenter addObserver:self
selector:@selector(applicationWillEnterForeground:)
name:kGDTApplicationWillEnterForegroundNotification
object:nil];
NSString *name = kGDTApplicationWillTerminateNotification;
[notificationCenter addObserver:self
selector:@selector(applicationWillTerminate:)
name:name
object:nil];
}
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)applicationDidEnterBackground:(NSNotification *)notification {
GDTApplication *application = [GDTApplication sharedApplication];
if ([[GDTTransformer sharedInstance] respondsToSelector:@selector(appWillBackground:)]) {
[[GDTTransformer sharedInstance] appWillBackground:application];
}
if ([[GDTStorage sharedInstance] respondsToSelector:@selector(appWillBackground:)]) {
[[GDTStorage sharedInstance] appWillBackground:application];
}
if ([[GDTUploadCoordinator sharedInstance] respondsToSelector:@selector(appWillBackground:)]) {
[[GDTUploadCoordinator sharedInstance] appWillBackground:application];
}
if ([[GDTRegistrar sharedInstance] respondsToSelector:@selector(appWillBackground:)]) {
[[GDTRegistrar sharedInstance] appWillBackground:application];
}
}
- (void)applicationWillEnterForeground:(NSNotification *)notification {
GDTApplication *application = [GDTApplication sharedApplication];
if ([[GDTTransformer sharedInstance] respondsToSelector:@selector(appWillForeground:)]) {
[[GDTTransformer sharedInstance] appWillForeground:application];
}
if ([[GDTStorage sharedInstance] respondsToSelector:@selector(appWillForeground:)]) {
[[GDTStorage sharedInstance] appWillForeground:application];
}
if ([[GDTUploadCoordinator sharedInstance] respondsToSelector:@selector(appWillForeground:)]) {
[[GDTUploadCoordinator sharedInstance] appWillForeground:application];
}
if ([[GDTRegistrar sharedInstance] respondsToSelector:@selector(appWillForeground:)]) {
[[GDTRegistrar sharedInstance] appWillForeground:application];
}
}
- (void)applicationWillTerminate:(NSNotification *)notification {
GDTApplication *application = [GDTApplication sharedApplication];
if ([[GDTTransformer sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) {
[[GDTTransformer sharedInstance] appWillTerminate:application];
}
if ([[GDTStorage sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) {
[[GDTStorage sharedInstance] appWillTerminate:application];
}
if ([[GDTUploadCoordinator sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) {
[[GDTUploadCoordinator sharedInstance] appWillTerminate:application];
}
if ([[GDTRegistrar sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) {
[[GDTRegistrar sharedInstance] appWillTerminate:application];
}
}
@end
@@ -1,256 +0,0 @@
/*
* Copyright 2018 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "GDTLibrary/Private/GDTStorage.h"
#import "GDTLibrary/Private/GDTStorage_Private.h"
#import <GoogleDataTransport/GDTConsoleLogger.h>
#import <GoogleDataTransport/GDTLifecycle.h>
#import <GoogleDataTransport/GDTPrioritizer.h>
#import <GoogleDataTransport/GDTStoredEvent.h>
#import "GDTLibrary/Private/GDTAssert.h"
#import "GDTLibrary/Private/GDTEvent_Private.h"
#import "GDTLibrary/Private/GDTRegistrar_Private.h"
#import "GDTLibrary/Private/GDTUploadCoordinator.h"
/** Creates and/or returns a singleton NSString that is the shared storage path.
*
* @return The SDK event storage path.
*/
static NSString *GDTStoragePath() {
static NSString *storagePath;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *cachePath =
NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
storagePath = [NSString stringWithFormat:@"%@/google-sdks-events", cachePath];
});
return storagePath;
}
@implementation GDTStorage
+ (NSString *)archivePath {
static NSString *archivePath;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
archivePath = [GDTStoragePath() stringByAppendingPathComponent:@"GDTStorageArchive"];
});
return archivePath;
}
+ (instancetype)sharedInstance {
static GDTStorage *sharedStorage;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedStorage = [[GDTStorage alloc] init];
});
return sharedStorage;
}
- (instancetype)init {
self = [super init];
if (self) {
_storageQueue = dispatch_queue_create("com.google.GDTStorage", DISPATCH_QUEUE_SERIAL);
_targetToEventSet = [[NSMutableDictionary alloc] init];
_storedEvents = [[NSMutableOrderedSet alloc] init];
_uploadCoordinator = [GDTUploadCoordinator sharedInstance];
}
return self;
}
- (void)storeEvent:(GDTEvent *)event {
[self createEventDirectoryIfNotExists];
__block GDTBackgroundIdentifier bgID = GDTBackgroundIdentifierInvalid;
if (_runningInBackground) {
bgID = [[GDTApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[GDTApplication sharedApplication] endBackgroundTask:bgID];
}];
}
dispatch_async(_storageQueue, ^{
// Check that a backend implementation is available for this target.
NSInteger target = event.target;
// Check that a prioritizer is available for this target.
id<GDTPrioritizer> prioritizer = [GDTRegistrar sharedInstance].targetToPrioritizer[@(target)];
GDTAssert(prioritizer, @"There's no prioritizer registered for the given target.");
// Write the transport bytes to disk, get a filename.
GDTAssert(event.dataObjectTransportBytes, @"The event should have been serialized to bytes");
NSURL *eventFile = [self saveEventBytesToDisk:event.dataObjectTransportBytes
eventHash:event.hash];
GDTDataFuture *dataFuture = [[GDTDataFuture alloc] initWithFileURL:eventFile];
GDTStoredEvent *storedEvent = [event storedEventWithDataFuture:dataFuture];
// Add event to tracking collections.
[self addEventToTrackingCollections:storedEvent];
// Have the prioritizer prioritize the event.
[prioritizer prioritizeEvent:storedEvent];
// Check the QoS, if it's high priority, notify the target that it has a high priority event.
if (event.qosTier == GDTEventQoSFast) {
[self.uploadCoordinator forceUploadForTarget:target];
}
// If running in the background, save state to disk and end the associated background task.
if (bgID != GDTBackgroundIdentifierInvalid) {
[NSKeyedArchiver archiveRootObject:self toFile:[GDTStorage archivePath]];
[[GDTApplication sharedApplication] endBackgroundTask:bgID];
}
});
}
- (void)removeEvents:(NSSet<GDTStoredEvent *> *)events {
NSSet<GDTStoredEvent *> *eventsToRemove = [events copy];
dispatch_async(_storageQueue, ^{
for (GDTStoredEvent *event in eventsToRemove) {
// Remove from disk, first and foremost.
NSError *error;
if (event.dataFuture.fileURL) {
NSURL *fileURL = event.dataFuture.fileURL;
[[NSFileManager defaultManager] removeItemAtURL:fileURL error:&error];
GDTAssert(error == nil, @"There was an error removing an event file: %@", error);
}
// Remove from the tracking collections.
[self.storedEvents removeObject:event];
[self.targetToEventSet[event.target] removeObject:event];
}
});
}
#pragma mark - Private helper methods
/** Creates the storage directory if it does not exist. */
- (void)createEventDirectoryIfNotExists {
NSError *error;
BOOL result = [[NSFileManager defaultManager] createDirectoryAtPath:GDTStoragePath()
withIntermediateDirectories:YES
attributes:0
error:&error];
if (!result || error) {
GDTLogError(GDTMCEDirectoryCreationError, @"Error creating the directory: %@", error);
}
}
/** Saves the event's dataObjectTransportBytes to a file using NSData mechanisms.
*
* @note This method should only be called from a method within a block on _storageQueue to maintain
* thread safety.
*
* @param transportBytes The transport bytes of the event.
* @param eventHash The hash value of the event.
* @return The filename
*/
- (NSURL *)saveEventBytesToDisk:(NSData *)transportBytes eventHash:(NSUInteger)eventHash {
NSString *storagePath = GDTStoragePath();
NSString *event = [NSString stringWithFormat:@"event-%lu", (unsigned long)eventHash];
NSURL *eventFilePath = [NSURL fileURLWithPath:[storagePath stringByAppendingPathComponent:event]];
GDTAssert(![[NSFileManager defaultManager] fileExistsAtPath:eventFilePath.path],
@"An event shouldn't already exist at this path: %@", eventFilePath.path);
BOOL writingSuccess = [transportBytes writeToURL:eventFilePath atomically:YES];
if (!writingSuccess) {
GDTLogError(GDTMCEFileWriteError, @"An event file could not be written: %@", eventFilePath);
}
return eventFilePath;
}
/** Adds the event to internal tracking collections.
*
* @note This method should only be called from a method within a block on _storageQueue to maintain
* thread safety.
*
* @param event The event to track.
*/
- (void)addEventToTrackingCollections:(GDTStoredEvent *)event {
[_storedEvents addObject:event];
NSMutableSet<GDTStoredEvent *> *events = self.targetToEventSet[event.target];
events = events ? events : [[NSMutableSet alloc] init];
[events addObject:event];
_targetToEventSet[event.target] = events;
}
#pragma mark - GDTLifecycleProtocol
- (void)appWillForeground:(GDTApplication *)app {
[NSKeyedUnarchiver unarchiveObjectWithFile:[GDTStorage archivePath]];
self->_runningInBackground = NO;
}
- (void)appWillBackground:(GDTApplication *)app {
self->_runningInBackground = YES;
[NSKeyedArchiver archiveRootObject:self toFile:[GDTStorage archivePath]];
// Create an immediate background task to run until the end of the current queue of work.
__block GDTBackgroundIdentifier bgID = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgID];
}];
dispatch_async(_storageQueue, ^{
[app endBackgroundTask:bgID];
});
}
- (void)appWillTerminate:(GDTApplication *)application {
[NSKeyedArchiver archiveRootObject:self toFile:[GDTStorage archivePath]];
}
#pragma mark - NSSecureCoding
/** The NSKeyedCoder key for the storedEvents property. */
static NSString *const kGDTStorageStoredEventsKey = @"GDTStorageStoredEventsKey";
/** The NSKeyedCoder key for the targetToEventSet property. */
static NSString *const kGDTStorageTargetToEventSetKey = @"GDTStorageTargetToEventSetKey";
/** The NSKeyedCoder key for the uploadCoordinator property. */
static NSString *const kGDTStorageUploadCoordinatorKey = @"GDTStorageUploadCoordinatorKey";
+ (BOOL)supportsSecureCoding {
return YES;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
// Create the singleton and populate its ivars.
GDTStorage *sharedInstance = [self.class sharedInstance];
dispatch_sync(sharedInstance.storageQueue, ^{
sharedInstance->_storedEvents = [aDecoder decodeObjectOfClass:[NSMutableOrderedSet class]
forKey:kGDTStorageStoredEventsKey];
sharedInstance->_targetToEventSet =
[aDecoder decodeObjectOfClass:[NSMutableDictionary class]
forKey:kGDTStorageTargetToEventSetKey];
sharedInstance->_uploadCoordinator =
[aDecoder decodeObjectOfClass:[GDTUploadCoordinator class]
forKey:kGDTStorageUploadCoordinatorKey];
});
return sharedInstance;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
GDTStorage *sharedInstance = [self.class sharedInstance];
dispatch_sync(sharedInstance.storageQueue, ^{
[aCoder encodeObject:sharedInstance->_storedEvents forKey:kGDTStorageStoredEventsKey];
[aCoder encodeObject:sharedInstance->_targetToEventSet forKey:kGDTStorageTargetToEventSetKey];
[aCoder encodeObject:sharedInstance->_uploadCoordinator forKey:kGDTStorageUploadCoordinatorKey];
});
}
@end
@@ -1,102 +0,0 @@
/*
* Copyright 2018 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "GDTLibrary/Private/GDTTransformer.h"
#import "GDTLibrary/Private/GDTTransformer_Private.h"
#import <GoogleDataTransport/GDTConsoleLogger.h>
#import <GoogleDataTransport/GDTEventTransformer.h>
#import <GoogleDataTransport/GDTLifecycle.h>
#import "GDTLibrary/Private/GDTAssert.h"
#import "GDTLibrary/Private/GDTStorage.h"
@implementation GDTTransformer
+ (instancetype)sharedInstance {
static GDTTransformer *eventTransformer;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
eventTransformer = [[self alloc] init];
});
return eventTransformer;
}
- (instancetype)init {
self = [super init];
if (self) {
_eventWritingQueue = dispatch_queue_create("com.google.GDTTransformer", DISPATCH_QUEUE_SERIAL);
_storageInstance = [GDTStorage sharedInstance];
}
return self;
}
- (void)transformEvent:(GDTEvent *)event
withTransformers:(NSArray<id<GDTEventTransformer>> *)transformers {
GDTAssert(event, @"You can't write a nil event");
__block GDTBackgroundIdentifier bgID = GDTBackgroundIdentifierInvalid;
if (_runningInBackground) {
bgID = [[GDTApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[GDTApplication sharedApplication] endBackgroundTask:bgID];
}];
}
dispatch_async(_eventWritingQueue, ^{
GDTEvent *transformedEvent = event;
for (id<GDTEventTransformer> transformer in transformers) {
if ([transformer respondsToSelector:@selector(transform:)]) {
transformedEvent = [transformer transform:transformedEvent];
if (!transformedEvent) {
return;
}
} else {
GDTLogError(GDTMCETransformerDoesntImplementTransform,
@"Transformer doesn't implement transform: %@", transformer);
return;
}
}
[self.storageInstance storeEvent:transformedEvent];
if (self->_runningInBackground) {
[[GDTApplication sharedApplication] endBackgroundTask:bgID];
}
});
}
#pragma mark - GDTLifecycleProtocol
- (void)appWillForeground:(GDTApplication *)app {
dispatch_async(_eventWritingQueue, ^{
self->_runningInBackground = NO;
});
}
- (void)appWillBackground:(GDTApplication *)app {
// Create an immediate background task to run until the end of the current queue of work.
__block GDTBackgroundIdentifier bgID = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgID];
}];
dispatch_async(_eventWritingQueue, ^{
[app endBackgroundTask:bgID];
});
}
- (void)appWillTerminate:(GDTApplication *)application {
// Flush the queue immediately.
dispatch_sync(_eventWritingQueue, ^{
});
}
@end
@@ -1,65 +0,0 @@
/*
* Copyright 2018 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <GoogleDataTransport/GDTTransport.h>
#import "GDTLibrary/Private/GDTTransport_Private.h"
#import <GoogleDataTransport/GDTClock.h>
#import <GoogleDataTransport/GDTEvent.h>
#import "GDTLibrary/Private/GDTAssert.h"
#import "GDTLibrary/Private/GDTTransformer.h"
@implementation GDTTransport
- (instancetype)initWithMappingID:(NSString *)mappingID
transformers:(nullable NSArray<id<GDTEventTransformer>> *)transformers
target:(NSInteger)target {
self = [super init];
if (self) {
GDTAssert(mappingID.length > 0, @"A mapping ID cannot be nil or empty");
GDTAssert(target > 0, @"A target cannot be negative or 0");
_mappingID = mappingID;
_transformers = transformers;
_target = target;
_transformerInstance = [GDTTransformer sharedInstance];
}
return self;
}
- (void)sendTelemetryEvent:(GDTEvent *)event {
// TODO: Determine if sending an event before registration is allowed.
GDTAssert(event, @"You can't send a nil event");
GDTEvent *copiedEvent = [event copy];
copiedEvent.qosTier = GDTEventQoSTelemetry;
copiedEvent.clockSnapshot = [GDTClock snapshot];
[self.transformerInstance transformEvent:copiedEvent withTransformers:_transformers];
}
- (void)sendDataEvent:(GDTEvent *)event {
// TODO: Determine if sending an event before registration is allowed.
GDTAssert(event, @"You can't send a nil event");
GDTAssert(event.qosTier != GDTEventQoSTelemetry, @"Use -sendTelemetryEvent, please.");
GDTEvent *copiedEvent = [event copy];
copiedEvent.clockSnapshot = [GDTClock snapshot];
[self.transformerInstance transformEvent:copiedEvent withTransformers:_transformers];
}
- (GDTEvent *)eventForTransport {
return [[GDTEvent alloc] initWithMappingID:_mappingID target:_target];
}
@end
@@ -1,54 +0,0 @@
/*
* Copyright 2019 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <Foundation/Foundation.h>
/** A block type that could be run instead of NSAssert. No return type, no params. */
typedef void (^GDTAssertionBlock)(void);
/** Returns the result of executing a soft-linked method present in unit tests that allows a block
* to be run in lieu of a call to NSAssert. This helps ameliorate issues with catching exceptions
* that occur on a dispatch_queue.
*
* @return A block that can be run instead of calling NSAssert, or nil.
*/
FOUNDATION_EXPORT GDTAssertionBlock _Nullable GDTAssertionBlockToRunInsteadOfNSAssert(void);
#if !defined(NS_BLOCK_ASSERTIONS)
/** Asserts using NSAssert, unless a block was specified to be run instead.
*
* @param condition The condition you'd expect to be YES.
*/
#define GDTAssert(condition, ...) \
do { \
if (__builtin_expect(!(condition), 0)) { \
GDTAssertionBlock assertionBlock = GDTAssertionBlockToRunInsteadOfNSAssert(); \
if (assertionBlock) { \
assertionBlock(); \
} else { \
NSAssert(condition, __VA_ARGS__); \
} \
} \
} while (0);
#else
#define GDTAssert(condition, ...) \
do { \
} while (0);
#endif // !defined(NS_BLOCK_ASSERTIONS)
+17 -10
View File
@@ -1,9 +1,10 @@
# Firebase iOS Open Source Development [![Build Status](https://travis-ci.org/firebase/firebase-ios-sdk.svg?branch=master)](https://travis-ci.org/firebase/firebase-ios-sdk)
This repository contains a subset of the Firebase iOS SDK source. It currently
includes FirebaseCore, FirebaseAuth, FirebaseDatabase, FirebaseFirestore,
FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
FirebaseInAppMessagingDisplay, FirebaseMessaging and FirebaseStorage.
includes FirebaseCore, FirebaseABTesting, FirebaseAuth, FirebaseDatabase,
FirebaseFirestore, FirebaseFunctions, FirebaseInstanceID, FirebaseInAppMessaging,
FirebaseInAppMessagingDisplay, FirebaseMessaging, FirebaseRemoteConfig, and
FirebaseStorage.
The repository also includes GoogleUtilities source. The
[GoogleUtilities](GoogleUtilities/README.md) pod is
@@ -80,9 +81,8 @@ For the pod that you want to develop:
`pod gen Firebase{name here}.podspec --local-sources=./ --auto-open`
Firestore and Functions have self contained Xcode projects. See
[Firestore/README.md](Firestore/README.md) and
[Functions/README.md](Functions/README.md).
Firestore has a self contained Xcode project. See
[Firestore/README.md](Firestore/README.md).
### Adding a New Firebase Pod
@@ -99,13 +99,17 @@ Travis will verify that any code changes are done in a style compliant way. Inst
These commands will get the right versions:
```
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/773cb75d360b58f32048f5964038d09825a507c8/Formula/clang-format.rb
brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/3dfea1004e0736754bbf49673cca8aaed8a94089/Formula/swiftformat.rb
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/e3496d9/Formula/clang-format.rb
brew upgrade https://raw.githubusercontent.com/Homebrew/homebrew-core/7963c3d/Formula/swiftformat.rb
```
Note: if you already have a newer version of these installed you may need to
`brew switch` to this version.
To update this section, find the versions of clang-format and swiftformat.rb to
match the versions in the CI failure logs
[here](https://github.com/Homebrew/homebrew-core/tree/master/Formula).
### Running Unit Tests
Select a scheme and press Command-u to build a component and run its unit tests.
@@ -179,8 +183,9 @@ very grateful! We'd like to empower as many developers as we can to be able to
participate in the Firebase community.
### macOS and tvOS
Thanks to contributions from the community, FirebaseAuth, FirebaseCore, FirebaseDatabase, FirebaseMessaging,
FirebaseFirestore, FirebaseFunctions and FirebaseStorage now compile, run unit tests, and work on
Thanks to contributions from the community, FirebaseABTesting, FirebaseAuth, FirebaseCore,
FirebaseDatabase, FirebaseMessaging, FirebaseFirestore,
FirebaseFunctions, FirebaseRemoteConfig, and FirebaseStorage now compile, run unit tests, and work on
macOS and tvOS.
For tvOS, checkout the [Sample](Example/tvOSSample).
@@ -195,12 +200,14 @@ Note that the Firebase pod is not available for macOS and tvOS.
To install, add a subset of the following to the Podfile:
```
pod 'FirebaseABTesting'
pod 'FirebaseAuth'
pod 'FirebaseCore'
pod 'FirebaseDatabase'
pod 'FirebaseFirestore'
pod 'FirebaseFunctions'
pod 'FirebaseMessaging'
pod 'FirebaseRemoteConfig'
pod 'FirebaseStorage'
```