Collect context information needed for packaging telemetry items

This commit is contained in:
Christoph Wendt
2015-09-03 23:20:23 -07:00
parent fede13a6d6
commit ca405da200
3 changed files with 693 additions and 0 deletions

View File

@@ -0,0 +1,213 @@
#import <Foundation/Foundation.h>
#import "HockeySDK.h"
#if HOCKEYSDK_FEATURE_TELEMETRY
#import "HockeySDKPrivate.h"
#import "BITApplication.h"
#import "BITDevice.h"
#import "BITOperation.h"
#import "BITInternal.h"
#import "BITUser.h"
#import "BITSession.h"
#import "BITLocation.h"
@class BITPersistence;
NS_ASSUME_NONNULL_BEGIN
FOUNDATION_EXPORT NSString *const kBITApplicationWasLaunched;
/**
* Context object which contains information about the device, user, session etc.
*/
@interface BITTelemetryContext : NSObject
/**
* A Dictionary which holds content of property list in memory.
*/
@property (nonatomic, strong) NSMutableDictionary *metaData;
/**
* The instrumentation key of the app.
*/
@property(nonatomic, strong) BITPersistence *persistence;
/**
* The instrumentation key of the app.
*/
@property(nonatomic, copy) NSString *instrumentationKey;
///-----------------------------------------------------------------------------
/// @name Initialisation
///-----------------------------------------------------------------------------
/**
* A queue which makes array operations thread safe.
*/
@property (nonatomic, strong) dispatch_queue_t operationsQueue;
/**
* The application context.
*/
@property(nonatomic, strong, readonly) BITApplication *application;
/**
* The device context.
*/
@property (nonatomic, strong, readonly)BITDevice *device;
/**
* The location context.
*/
@property (nonatomic, strong, readonly)BITLocation *location;
/**
* The session context.
*/
@property (nonatomic, strong, readonly)BITSession *session;
/**
* The user context.
*/
@property (nonatomic, strong, readonly)BITUser *user;
/**
* The internal context.
*/
@property (nonatomic, strong, readonly)BITInternal *internal;
/**
* The operation context.
*/
@property (nonatomic, strong, readonly)BITOperation *operation;
/**
* Initializes a telemetry context.
*
* @param instrumentationKey the instrumentation key of the app.
* @param persistence the persistence used to save and load metadata
*
* @return the telemetry context
*/
- (instancetype)initWithInstrumentationKey:(NSString *)instrumentationKey persistence:(BITPersistence *)persistence;
///-----------------------------------------------------------------------------
/// @name Users
///-----------------------------------------------------------------------------
/**
* Use this method to configure the current context.
*
* @param telemetryContextConfigurationBlock block gets the current context as an input.
* Within the block you can update the context object's values to up-to-date.
*/
- (void)setTelemetryContextWithConfigurationBlock:(void (^)(BITTelemetryContext *telemetryContext))telemetryContextConfigurationBlock;
/**
* Use this method to configure the current user's context.
*
* @param userConfigurationBlock This block gets the current user as an input.
* Within the block you can update the user object's values to up-to-date.
*/
- (void)setUserWithConfigurationBlock:(void (^)(BITUser *user))userConfigurationBlock;
///-----------------------------------------------------------------------------
/// @name Network status
///-----------------------------------------------------------------------------
/**
* Get current network type and register for updates.
*/
- (void)configureNetworkStatusTracking;
///-----------------------------------------------------------------------------
/// @name Helper
///-----------------------------------------------------------------------------
/**
* Returns context objects as dictionary.
*
* @return a dictionary containing all context fields
*/
- (BITOrderedDictionary *)contextDictionary;
///-----------------------------------------------------------------------------
/// @name Getter/Setter
///-----------------------------------------------------------------------------
- (NSString *)screenResolution;
- (void)setScreenResolution:(NSString *)screenResolution;
- (NSString *)appVersion;
- (void)setAppVersion:(NSString *)appVersion;
- (NSString *)userId;
- (void)setUserId:(NSString *)userId;
- (NSString *)userAcquisitionDate;
- (void)setUserAcquisitionDate:(NSString *)userAcqusitionDate;
- (NSString *)accountId;
- (void)setAccountId:(NSString *)accountId;
- (NSString *)authenticatedUserId;
- (void)setAuthenticatedUserId:(NSString *)authenticatedUserId;
- (NSString *)authenticatedUserAcquisitionDate;
- (void)setAuthenticatedUserAcquisitionDate:(NSString *)authenticatedUserAcquisitionDate;
- (NSString *)anonymousUserAquisitionDate;
- (void)setAnonymousUserAquisitionDate:(NSString *)anonymousUserAquisitionDate;
- (NSString *)sdkVersion;
- (void)setSdkVersion:(NSString *)sdkVersion;
- (NSString *)sessionId;
- (void)setSessionId:(NSString *)sessionId;
- (NSString *)osVersion;
- (void)setOsVersion:(NSString *)osVersion;
- (NSString *)osName;
- (void)setOsName:(NSString *)osName;
- (NSString *)deviceModel;
- (void)setDeviceModel:(NSString *)deviceModel;
- (NSString *)deviceOemName;
- (void)setDeviceOemName:(NSString *)oemName;
- (NSString *)osLocale;
- (void)setOsLocale:(NSString *)osLocale;
- (NSString *)deviceId;
- (void)setDeviceId:(NSString *)deviceId;
- (NSString *)deviceType;
- (void)setDeviceType:(NSString *)deviceType;
- (NSString *)networkType;
- (void)setNetworkType:(NSString *)networkType;
@end
NS_ASSUME_NONNULL_END
#endif /* HOCKEYSDK_FEATURE_TELEMETRY */

View File

@@ -0,0 +1,466 @@
#import <Foundation/Foundation.h>
#import "BITTelemetryContext.h"
#if HOCKEYSDK_FEATURE_TELEMETRY
#import "BITTelemetryManagerPrivate.h"
#import "BITHockeyHelper.h"
#import "BITReachability.h"
#import "BITOrderedDictionary.h"
#import "BITPersistence.h"
NSString *const kBITTelemetrySessionId = @"BITTelemetrySessionId";
NSString *const kBITSessionAcquisitionTime = @"BITSessionAcquisitionTime";
static char *const BITContextOperationsQueue = "net.hockeyapp.telemetryContextQueue";
@implementation BITTelemetryContext
@synthesize instrumentationKey = _instrumentationKey;
@synthesize persistence = _persistence;
#pragma mark - Initialisation
-(instancetype)init {
if(self = [super init]) {
_operationsQueue = dispatch_queue_create(BITContextOperationsQueue, DISPATCH_QUEUE_CONCURRENT);
}
return self;
}
- (instancetype)initWithInstrumentationKey:(NSString *)instrumentationKey persistence:(BITPersistence *)persistence {
if ((self = [self init])) {
_persistence = persistence;
_instrumentationKey = instrumentationKey;
BITDevice *deviceContext = [BITDevice new];
deviceContext.model = bit_devicePlatform();
deviceContext.type = bit_deviceType();
deviceContext.osVersion = bit_osVersionBuild();
deviceContext.os = bit_osName();
deviceContext.deviceId = bit_appAnonID(NO);
deviceContext.locale = bit_deviceLocale();
deviceContext.language = bit_deviceLanguage();
deviceContext.screenResolution = bit_screenSize();
deviceContext.oemName = @"Apple";
BITInternal *internalContext = [BITInternal new];
internalContext.sdkVersion = bit_sdkVersion();
BITApplication *applicationContext = [BITApplication new];
applicationContext.version = bit_appVersion();
BITOperation *operationContext = [BITOperation new];
NSMutableDictionary *restoredMetaData = [[_persistence metaData] mutableCopy];
_metaData = restoredMetaData ?: @{}.mutableCopy;
_metaData[@"users"] = restoredMetaData[@"users"] ?: @{}.mutableCopy;
BITUser *userContext = [self userForDate:[NSDate date]];
if (!userContext) {
userContext = [self newUser];
[self addUser:userContext forDate:[NSDate date]];
}
BITLocation *locationContext = [BITLocation new];
BITSession *sessionContext = [BITSession new];
_application = applicationContext;
_device = deviceContext;
_location = locationContext;
_user = userContext;
_internal = internalContext;
_operation = operationContext;
_session = sessionContext;
[self configureNetworkStatusTracking];
}
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark - User
- (BITUser *)newUser {
return ({
BITUser *user = [BITUser new];
user.userId = bit_appAnonID(NO);
user;
});
}
- (void)addUser:(BITUser *)user forDate:(NSDate *)date {
NSString *timestamp = [self unixTimestampFromDate:date ?: [NSDate date]];
__weak typeof(self) weakSelf = self;
dispatch_sync(self.operationsQueue, ^{
typeof(self) strongSelf = weakSelf;
NSMutableDictionary *users = strongSelf.metaData[@"users"];
users[timestamp] = user;
[self.persistence persistMetaData:strongSelf.metaData];
});
}
- (BITUser *)userForDate:(NSDate *)date {
NSString *timestamp = [self unixTimestampFromDate:date];
NSMutableDictionary *users = self.metaData[@"users"];
__block BITUser *user = nil;
__weak typeof(self) weakSelf = self;
dispatch_sync(self.operationsQueue, ^{
typeof(self) strongSelf = weakSelf;
NSString *userKey = [strongSelf keyForTimestamp:timestamp inDictionary:users];
user = users[userKey];
});
return user;
}
- (NSString *)unixTimestampFromDate:(NSDate *)date {
return [NSString stringWithFormat:@"%ld", (time_t) [date timeIntervalSince1970]];
}
- (NSString *)keyForTimestamp:(NSString *)timestamp inDictionary:(NSDictionary *)dict {
for(NSString *key in [self sortedKeysOfDictionay:dict]) {
if([timestamp doubleValue] >= [key doubleValue]) {
return key;
}
}
return nil;
}
- (NSArray *)sortedKeysOfDictionay:(NSDictionary *)dict {
NSMutableArray *keys = [[dict allKeys] mutableCopy];
NSArray *sortedArray = [keys sortedArrayUsingComparator:^(id a, id b) {
return [b compare:a options:NSNumericSearch];
}];
return sortedArray;
}
#pragma mark - Network
- (void)configureNetworkStatusTracking {
[[BITReachability sharedInstance] startNetworkStatusTracking];
_device.network = [[BITReachability sharedInstance] descriptionForActiveReachabilityType];
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(updateNetworkType:) name:kBITReachabilityTypeChangedNotification object:nil];
}
- (void)updateNetworkType:(NSNotification *)notification {
[self setNetworkType:[notification userInfo][kBITReachabilityUserInfoName]];
}
#pragma mark - Getter/Setter properties
- (NSString *)instrumentationKey {
__block NSString *tmp;
dispatch_sync(_operationsQueue, ^{
tmp = _instrumentationKey;
});
return tmp;
}
- (void)setInstrumentationKey:(NSString *)instrumentationKey {
NSString* tmp = [instrumentationKey copy];
dispatch_barrier_async(_operationsQueue, ^{
_instrumentationKey = tmp;
});
}
- (NSString *)screenResolution {
__block NSString *tmp;
dispatch_sync(_operationsQueue, ^{
tmp = _device.screenResolution;
});
return tmp;
}
- (void)setScreenResolution:(NSString *)screenResolution {
NSString* tmp = [screenResolution copy];
dispatch_barrier_async(_operationsQueue, ^{
_device.screenResolution = tmp;
});
}
- (NSString *)appVersion {
__block NSString *tmp;
dispatch_sync(_operationsQueue, ^{
tmp = _application.version;
});
return tmp;
}
- (void)setAppVersion:(NSString *)appVersion {
NSString* tmp = [appVersion copy];
dispatch_barrier_async(_operationsQueue, ^{
_application.version = tmp;
});
}
- (NSString *)userId {
__block NSString *tmp;
dispatch_sync(_operationsQueue, ^{
tmp = _user.userId;
});
return tmp;
}
- (void)setUserId:(NSString *)userId {
NSString* tmp = [userId copy];
dispatch_barrier_async(_operationsQueue, ^{
_user.userId = tmp;
});
}
- (NSString *)userAcquisitionDate {
__block NSString *tmp;
dispatch_sync(_operationsQueue, ^{
tmp = _user.accountAcquisitionDate;
});
return tmp;
}
- (void)setUserAcquisitionDate:(NSString *)userAcqusitionDate {
NSString* tmp = [userAcqusitionDate copy];
dispatch_barrier_async(_operationsQueue, ^{
_user.accountAcquisitionDate = tmp;
});
}
- (NSString *)accountId {
__block NSString *tmp;
dispatch_sync(_operationsQueue, ^{
tmp = _user.accountId;
});
return tmp;
}
- (void)setAccountId:(NSString *)accountId {
NSString* tmp = [accountId copy];
dispatch_barrier_async(_operationsQueue, ^{
_user.accountId = tmp;
});
}
- (NSString *)authenticatedUserId {
__block NSString *tmp;
dispatch_sync(_operationsQueue, ^{
tmp = _user.authUserId;
});
return tmp;
}
- (void)setAuthenticatedUserId:(NSString *)authenticatedUserId {
NSString* tmp = [authenticatedUserId copy];
dispatch_barrier_async(_operationsQueue, ^{
_user.authUserId = tmp;
});
}
- (NSString *)authenticatedUserAcquisitionDate {
__block NSString *tmp;
dispatch_sync(_operationsQueue, ^{
tmp = _user.authUserAcquisitionDate;
});
return tmp;
}
- (void)setAuthenticatedUserAcquisitionDate:(NSString *)authenticatedUserAcquisitionDate {
NSString* tmp = [authenticatedUserAcquisitionDate copy];
dispatch_barrier_async(_operationsQueue, ^{
_user.authUserAcquisitionDate = tmp;
});
}
- (NSString *)anonymousUserAquisitionDate {
__block NSString *tmp;
dispatch_sync(_operationsQueue, ^{
tmp = _user.anonUserAcquisitionDate;
});
return tmp;
}
- (void)setAnonymousUserAquisitionDate:(NSString *)anonymousUserAquisitionDate {
NSString* tmp = [anonymousUserAquisitionDate copy];
dispatch_barrier_async(_operationsQueue, ^{
_user.anonUserAcquisitionDate = tmp;
});
}
- (NSString *)sdkVersion {
__block NSString *tmp;
dispatch_sync(_operationsQueue, ^{
tmp = _internal.sdkVersion;
});
return tmp;
}
- (void)setSdkVersion:(NSString *)sdkVersion {
NSString* tmp = [sdkVersion copy];
dispatch_barrier_async(_operationsQueue, ^{
_internal.sdkVersion = tmp;
});
}
- (NSString *)sessionId {
__block NSString *tmp;
dispatch_sync(_operationsQueue, ^{
tmp = _session.sessionId;
});
return tmp;
}
- (void)setSessionId:(NSString *)sessionId {
NSString* tmp = [sessionId copy];
dispatch_barrier_async(_operationsQueue, ^{
_session.sessionId = tmp;
});
}
- (NSString *)osVersion {
__block NSString *tmp;
dispatch_sync(_operationsQueue, ^{
tmp = _device.osVersion;
});
return tmp;
}
- (void)setOsVersion:(NSString *)osVersion {
NSString* tmp = [osVersion copy];
dispatch_barrier_async(_operationsQueue, ^{
_device.osVersion = tmp;
});
}
- (NSString *)osName {
__block NSString *tmp;
dispatch_sync(_operationsQueue, ^{
tmp = _device.os;
});
return tmp;
}
- (void)setOsName:(NSString *)osName {
NSString* tmp = [osName copy];
dispatch_barrier_async(_operationsQueue, ^{
_device.os = tmp;
});
}
- (NSString *)deviceModel {
__block NSString *tmp;
dispatch_sync(_operationsQueue, ^{
tmp = _device.model;
});
return tmp;
}
- (void)setDeviceModel:(NSString *)deviceModel {
NSString* tmp = [deviceModel copy];
dispatch_barrier_async(_operationsQueue, ^{
_device.model = tmp;
});
}
- (NSString *)deviceOemName {
__block NSString *tmp;
dispatch_sync(_operationsQueue, ^{
tmp = _device.oemName;
});
return tmp;
}
- (void)setDeviceOemName:(NSString *)oemName {
NSString* tmp = [oemName copy];
dispatch_barrier_async(_operationsQueue, ^{
_device.oemName = tmp;
});
}
- (NSString *)osLocale {
__block NSString *tmp;
dispatch_sync(_operationsQueue, ^{
tmp = _device.locale;
});
return tmp;
}
- (void)setOsLocale:(NSString *)osLocale {
NSString* tmp = [osLocale copy];
dispatch_barrier_async(_operationsQueue, ^{
_device.locale = tmp;
});
}
- (NSString *)deviceId {
__block NSString *tmp;
dispatch_sync(_operationsQueue, ^{
tmp = _device.deviceId;
});
return tmp;
}
- (void)setDeviceId:(NSString *)deviceId {
NSString* tmp = [deviceId copy];
dispatch_barrier_async(_operationsQueue, ^{
_device.deviceId = tmp;
});
}
- (NSString *)deviceType {
__block NSString *tmp;
dispatch_sync(_operationsQueue, ^{
tmp = _device.type;
});
return tmp;
}
- (void)setDeviceType:(NSString *)deviceType {
NSString* tmp = [deviceType copy];
dispatch_barrier_async(_operationsQueue, ^{
_device.type = tmp;
});
}
- (NSString *)networkType {
__block NSString *tmp;
dispatch_sync(_operationsQueue, ^{
tmp = _device.network;
});
return tmp;
}
- (void)setNetworkType:(NSString *)networkType {
NSString* tmp = [networkType copy];
dispatch_barrier_async(_operationsQueue, ^{
_device.network = tmp;
});
}
#pragma mark - Custom getter
#pragma mark - Helper
// TODO: Cache context
- (BITOrderedDictionary *)contextDictionary {
__block BITOrderedDictionary *contextDictionary = [BITOrderedDictionary new];
dispatch_sync(_operationsQueue, ^{
[contextDictionary addEntriesFromDictionary:[self.session serializeToDictionary]];
[contextDictionary addEntriesFromDictionary:[self.user serializeToDictionary]];
[contextDictionary addEntriesFromDictionary:[self.device serializeToDictionary]];
[contextDictionary addEntriesFromDictionary:[self.application serializeToDictionary]];
[contextDictionary addEntriesFromDictionary:[self.location serializeToDictionary]];
[contextDictionary addEntriesFromDictionary:[self.internal serializeToDictionary]];
[contextDictionary addEntriesFromDictionary:[self.operation serializeToDictionary]];
});
return contextDictionary;
}
@end
#endif /* HOCKEYSDK_FEATURE_TELEMETRY */

View File

@@ -45,6 +45,10 @@
1B330A621B98E13C007844AB /* BITDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B330A5F1B98E13C007844AB /* BITDevice.h */; };
1B330A631B98E13C007844AB /* BITDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B330A601B98E13C007844AB /* BITDevice.m */; };
1B330A641B98E13C007844AB /* BITDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B330A601B98E13C007844AB /* BITDevice.m */; };
1B330A711B98E267007844AB /* BITTelemetryContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B330A6E1B98E267007844AB /* BITTelemetryContext.h */; };
1B330A721B98E267007844AB /* BITTelemetryContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B330A6E1B98E267007844AB /* BITTelemetryContext.h */; };
1B330A731B98E267007844AB /* BITTelemetryContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B330A6F1B98E267007844AB /* BITTelemetryContext.m */; };
1B330A741B98E267007844AB /* BITTelemetryContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B330A6F1B98E267007844AB /* BITTelemetryContext.m */; };
1B330A791B98E64A007844AB /* BITApplication.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B330A771B98E64A007844AB /* BITApplication.h */; };
1B330A7A1B98E64A007844AB /* BITApplication.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B330A771B98E64A007844AB /* BITApplication.h */; };
1B330A7B1B98E64A007844AB /* BITApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B330A781B98E64A007844AB /* BITApplication.m */; };
@@ -463,6 +467,8 @@
1B330A5A1B98DFC7007844AB /* BITData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITData.m; sourceTree = "<group>"; };
1B330A5F1B98E13C007844AB /* BITDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITDevice.h; sourceTree = "<group>"; };
1B330A601B98E13C007844AB /* BITDevice.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITDevice.m; sourceTree = "<group>"; };
1B330A6E1B98E267007844AB /* BITTelemetryContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITTelemetryContext.h; sourceTree = "<group>"; };
1B330A6F1B98E267007844AB /* BITTelemetryContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITTelemetryContext.m; sourceTree = "<group>"; };
1B330A771B98E64A007844AB /* BITApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITApplication.h; sourceTree = "<group>"; };
1B330A781B98E64A007844AB /* BITApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITApplication.m; sourceTree = "<group>"; };
1B330A7D1B98E6A2007844AB /* BITOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITOperation.h; sourceTree = "<group>"; };
@@ -798,6 +804,10 @@
1B87EFB31B8D0C540007C96B /* BITTelemetryManager.h */,
1B87EFB41B8D0C540007C96B /* BITTelemetryManager.m */,
1B87EFB71B8D0F800007C96B /* BITTelemetryManagerPrivate.h */,
1B98D4571B98F6CA00B8000B /* BITReachability.h */,
1B98D4581B98F6CA00B8000B /* BITReachability.m */,
1B330A6E1B98E267007844AB /* BITTelemetryContext.h */,
1B330A6F1B98E267007844AB /* BITTelemetryContext.m */,
1BD33EAD1B950DC700C3368B /* BITChannel.h */,
1BD33EAE1B950DC700C3368B /* BITChannel.m */,
B27FBEFB1B9622700082406A /* BITPersistence.h */,
@@ -1247,6 +1257,7 @@
1E5955FD15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */,
E48A3DEC17B3ED1C00924C3D /* BITAuthenticator.h in Headers */,
1E754E5C1621FBB70070AB92 /* BITCrashManager.h in Headers */,
1B330A711B98E267007844AB /* BITTelemetryContext.h in Headers */,
1B6852E01B95361D00D5C387 /* BITSessionStateData.h in Headers */,
1E754E5E1621FBB70070AB92 /* BITCrashManagerDelegate.h in Headers */,
1B6852C81B952BE900D5C387 /* BITBase.h in Headers */,
@@ -1326,6 +1337,7 @@
1EB6176D1B0A30CC0035A986 /* BITWebTableViewCell.h in Headers */,
1EB617AF1B0A31CA0035A986 /* HockeySDKFeatureConfig.h in Headers */,
1EB6177A1B0A310F0035A986 /* BITCrashDetailsPrivate.h in Headers */,
1B330A721B98E267007844AB /* BITTelemetryContext.h in Headers */,
1B6852E11B95361D00D5C387 /* BITSessionStateData.h in Headers */,
1EB6179D1B0A31760035A986 /* BITFeedbackListViewController.h in Headers */,
1B6852C91B952BE900D5C387 /* BITBase.h in Headers */,
@@ -1722,6 +1734,7 @@
1E49A4BB161222B900463151 /* BITHockeyBaseViewController.m in Sources */,
97F0FA0518B2294D00EF50AA /* BITFeedbackMessageAttachment.m in Sources */,
1E49A4C7161222B900463151 /* BITAppStoreHeader.m in Sources */,
1B330A731B98E267007844AB /* BITTelemetryContext.m in Sources */,
1B6852CA1B952BE900D5C387 /* BITBase.m in Sources */,
1E49A4CD161222B900463151 /* BITStoreButton.m in Sources */,
1E90FD7418EDB86400CF0417 /* BITCrashDetails.m in Sources */,
@@ -1814,6 +1827,7 @@
1EB6178F1B0A31510035A986 /* BITFeedbackManager.m in Sources */,
1EB6178B1B0A31510035A986 /* BITFeedbackUserDataViewController.m in Sources */,
1EB617931B0A31510035A986 /* BITUpdateViewController.m in Sources */,
1B330A741B98E267007844AB /* BITTelemetryContext.m in Sources */,
1B6852CB1B952BE900D5C387 /* BITBase.m in Sources */,
1EB617901B0A31510035A986 /* BITActivityIndicatorButton.m in Sources */,
1EB6178E1B0A31510035A986 /* BITFeedbackActivity.m in Sources */,