diff --git a/OptimizelySDKCore/OptimizelySDKCore/OPTLYBuilder.h b/OptimizelySDKCore/OptimizelySDKCore/OPTLYBuilder.h index 84c31f9a3..c26952f8f 100644 --- a/OptimizelySDKCore/OptimizelySDKCore/OPTLYBuilder.h +++ b/OptimizelySDKCore/OptimizelySDKCore/OPTLYBuilder.h @@ -48,6 +48,11 @@ typedef void (^OPTLYBuilderBlock)(OPTLYBuilder * _Nullable builder); @property (nonatomic, readwrite, strong, nullable) id userProfile; /// The datafile manager that will download the datafile for the manager @property (nonatomic, readwrite, strong, nullable) id datafileManager; +/// The client version +@property (nonatomic, strong, nonnull) NSString *clientVersion; +/// The client engine +@property (nonatomic, strong, nonnull) NSString *clientEngine; + /// Create an Optimizely Builder object. + (nullable instancetype)builderWithBlock:(nonnull OPTLYBuilderBlock)block; diff --git a/OptimizelySDKCore/OptimizelySDKCore/OPTLYBuilder.m b/OptimizelySDKCore/OptimizelySDKCore/OPTLYBuilder.m index 9e856450f..389cb0c96 100644 --- a/OptimizelySDKCore/OptimizelySDKCore/OPTLYBuilder.m +++ b/OptimizelySDKCore/OptimizelySDKCore/OPTLYBuilder.m @@ -52,6 +52,8 @@ - (id)initWithBlock:(OPTLYBuilderBlock)block { builder.datafile = self.datafile; builder.logger = self.logger; builder.errorHandler = self.errorHandler; + builder.clientEngine = self.clientEngine; + builder.clientVersion = self.clientVersion; }]; if (_config == nil) { diff --git a/OptimizelySDKCore/OptimizelySDKCore/OPTLYProjectConfig.h b/OptimizelySDKCore/OptimizelySDKCore/OPTLYProjectConfig.h index 2c17eb755..fdd540234 100644 --- a/OptimizelySDKCore/OptimizelySDKCore/OPTLYProjectConfig.h +++ b/OptimizelySDKCore/OptimizelySDKCore/OPTLYProjectConfig.h @@ -61,6 +61,11 @@ NS_ASSUME_NONNULL_END @property (nonatomic, strong, nullable) id logger; @property (nonatomic, strong, nullable) id errorHandler; +/// Returns the client type (e.g., objective-c-sdk-core, objective-c-sdk-iOS, objective-c-sdk-tvOS) +@property (nonatomic, strong, readonly, nonnull) NSString *clientEngine; +/// Returns the client version number +@property (nonatomic, strong, readonly, nonnull) NSString *clientVersion; + /** * Initialize the Project Config from a builder block. */ @@ -124,14 +129,4 @@ NS_ASSUME_NONNULL_END attributes:(nullable NSDictionary *)attributes bucketer:(nullable id)bucketer; -/* - * Returns the client type (e.g., objective-c-sdk-core, objective-c-sdk-iOS, objective-c-sdk-tvOS) - */ -- (nonnull NSString *)clientEngine; - -/* - * Returns the client version number - */ -- (nonnull NSString *)clientVersion; - @end diff --git a/OptimizelySDKCore/OptimizelySDKCore/OPTLYProjectConfig.m b/OptimizelySDKCore/OptimizelySDKCore/OPTLYProjectConfig.m index 41b34d8a3..55dad49a0 100644 --- a/OptimizelySDKCore/OptimizelySDKCore/OPTLYProjectConfig.m +++ b/OptimizelySDKCore/OptimizelySDKCore/OPTLYProjectConfig.m @@ -30,7 +30,6 @@ #import "OPTLYVariable.h" #import "OPTLYVariable.h" -NSString * const kClientEngine = @"objective-c-sdk-core"; NSString * const kExpectedDatafileVersion = @"3"; @interface OPTLYProjectConfig() @@ -125,6 +124,9 @@ - (instancetype)initWithBuilder:(OPTLYProjectConfigBuilder *)builder { [builder.errorHandler handleException:datafileException]; } + _clientEngine = builder.clientEngine; + _clientVersion = builder.clientVersion; + _errorHandler = (id)builder.errorHandler; _logger = (id)builder.logger; return self; @@ -415,14 +417,4 @@ - (OPTLYVariation *)getVariationForExperiment:(NSString *)experimentKey return variation; } -- (NSString *)clientEngine -{ - return kClientEngine; -} - -- (NSString *)clientVersion -{ - return OPTIMIZELY_SDK_CORE_VERSION; -} - @end diff --git a/OptimizelySDKCore/OptimizelySDKCore/OPTLYProjectConfigBuilder.h b/OptimizelySDKCore/OptimizelySDKCore/OPTLYProjectConfigBuilder.h index 551d08e40..269b4cf88 100644 --- a/OptimizelySDKCore/OptimizelySDKCore/OPTLYProjectConfigBuilder.h +++ b/OptimizelySDKCore/OptimizelySDKCore/OPTLYProjectConfigBuilder.h @@ -42,5 +42,10 @@ typedef void (^OPTLYProjectConfigBuilderBlock)(OPTLYProjectConfigBuilder * _Null @property (nonatomic, strong, nullable) id logger; /// the non optional datafile contents @property (nonatomic, strong, nonnull) NSData *datafile; +/// The client version +@property (nonatomic, strong, nonnull) NSString *clientVersion; +/// The client engine +@property (nonatomic, strong, nonnull) NSString *clientEngine; + @end diff --git a/OptimizelySDKCore/OptimizelySDKCore/OPTLYProjectConfigBuilder.m b/OptimizelySDKCore/OptimizelySDKCore/OPTLYProjectConfigBuilder.m index 69513ca56..6757a193d 100644 --- a/OptimizelySDKCore/OptimizelySDKCore/OPTLYProjectConfigBuilder.m +++ b/OptimizelySDKCore/OptimizelySDKCore/OPTLYProjectConfigBuilder.m @@ -16,6 +16,8 @@ #import "OPTLYProjectConfigBuilder.h" +NSString * const kClientEngine = @"objective-c-sdk-core"; + @implementation OPTLYProjectConfigBuilder + (nullable instancetype)builderWithBlock:(nonnull OPTLYProjectConfigBuilderBlock)block { @@ -30,6 +32,12 @@ - (id)initWithBlock:(OPTLYProjectConfigBuilderBlock)block { self = [super init]; if (self != nil) { block(self); + if (!_clientEngine) { + _clientEngine = kClientEngine; + } + if (!_clientVersion) { + _clientVersion = OPTIMIZELY_SDK_CORE_VERSION; + } if (!_datafile) { return nil; } diff --git a/OptimizelySDKCore/OptimizelySDKCoreTests/OPTLYBuilderTest.m b/OptimizelySDKCore/OptimizelySDKCoreTests/OPTLYBuilderTest.m index 7c6f9e980..373669505 100644 --- a/OptimizelySDKCore/OptimizelySDKCoreTests/OPTLYBuilderTest.m +++ b/OptimizelySDKCore/OptimizelySDKCoreTests/OPTLYBuilderTest.m @@ -19,10 +19,12 @@ #import "OPTLYErrorHandler.h" #import "OPTLYEventDispatcher.h" #import "OPTLYLogger.h" +#import "OPTLYProjectConfig.h" #import "OPTLYTestHelper.h" // static data from datafile static NSString * const kDataModelDatafileName = @"datafile_6372300739"; +static NSData *datafile; @interface OPTLYBuilderTest : XCTestCase @@ -30,6 +32,10 @@ @interface OPTLYBuilderTest : XCTestCase @implementation OPTLYBuilderTest ++ (void)setUp { + datafile = [OPTLYTestHelper loadJSONDatafileIntoDataObject:kDataModelDatafileName]; +} + - (void)testBuilderRequiresDatafile { Optimizely *optimizely = [Optimizely initWithBuilderBlock:^(OPTLYBuilder *builder) { @@ -48,10 +54,13 @@ - (void)testBuilderBuildsDefaults { XCTAssertNotNil(optimizely.eventBuilder); XCTAssertNotNil(optimizely.eventDispatcher); XCTAssertNotNil(optimizely.logger); + XCTAssertNotNil(optimizely.config.clientEngine); + XCTAssertNotNil(optimizely.config.clientVersion); + XCTAssertEqualObjects(optimizely.config.clientEngine, @"objective-c-sdk-core"); + XCTAssertEqualObjects(optimizely.config.clientVersion, OPTIMIZELY_SDK_CORE_VERSION); } - (void)testBuilderCanAssignErrorHandler { - NSData *datafile = [OPTLYTestHelper loadJSONDatafileIntoDataObject:kDataModelDatafileName]; OPTLYErrorHandlerDefault *errorHandler = [[OPTLYErrorHandlerDefault alloc] init]; Optimizely *defaultOptimizely = [Optimizely initWithBuilderBlock:^(OPTLYBuilder *builder) { @@ -70,7 +79,6 @@ - (void)testBuilderCanAssignErrorHandler { } - (void)testBuilderCanAssignEventDispatcher { - NSData *datafile = [OPTLYTestHelper loadJSONDatafileIntoDataObject:kDataModelDatafileName]; id eventDispatcher = [[NSObject alloc] init]; Optimizely *defaultOptimizely = [Optimizely initWithBuilderBlock:^(OPTLYBuilder *builder) { @@ -89,7 +97,6 @@ - (void)testBuilderCanAssignEventDispatcher { } - (void)testBuilderCanAssignLogger { - NSData *datafile = [OPTLYTestHelper loadJSONDatafileIntoDataObject:kDataModelDatafileName]; OPTLYLoggerDefault *logger = [[OPTLYLoggerDefault alloc] init]; Optimizely *defaultOptimizely = [Optimizely initWithBuilderBlock:^(OPTLYBuilder *builder) { @@ -119,4 +126,23 @@ - (void)testBuilderReturnsNilWithBadDatafile { XCTAssertNil(optimizely); } +/** + * Make sure the OPTLYBuilder can pass the client engine and version properly to the OPTLYProjectConfig initialization. + */ +- (void)testBuilderCanPassClientEngineAndVersionToProjectConfig { + NSString *clientEngine = @"clientEngine"; + NSString *clientVersion = @"clientVersion"; + + Optimizely *optimizely = [Optimizely initWithBuilderBlock:^(OPTLYBuilder * _Nullable builder) { + builder.datafile = datafile; + builder.clientEngine = clientEngine; + builder.clientVersion = clientVersion; + }]; + + XCTAssertNotNil(optimizely); + XCTAssertNotNil(optimizely.config); + XCTAssertEqualObjects(optimizely.config.clientEngine, clientEngine); + XCTAssertEqualObjects(optimizely.config.clientVersion, clientVersion); +} + @end diff --git a/OptimizelySDKCore/OptimizelySDKCoreTests/OPTLYProjectConfigTest.m b/OptimizelySDKCore/OptimizelySDKCoreTests/OPTLYProjectConfigTest.m index 682f51f58..5f81026db 100644 --- a/OptimizelySDKCore/OptimizelySDKCoreTests/OPTLYProjectConfigTest.m +++ b/OptimizelySDKCore/OptimizelySDKCoreTests/OPTLYProjectConfigTest.m @@ -64,6 +64,26 @@ - (void)testInitWithBuilderBlock XCTAssertNotNil(projectConfig, @"project config should not be nil."); XCTAssertNotNil(projectConfig.logger, @"logger should not be nil."); XCTAssertNotNil(projectConfig.errorHandler, @"error handler should not be nil."); + XCTAssertEqualObjects(projectConfig.clientEngine, @"objective-c-sdk-core"); + XCTAssertEqualObjects(projectConfig.clientVersion, OPTIMIZELY_SDK_CORE_VERSION); +} + +/** + * Make sure we can pass in different values for client engine and client version to override the defaults. + */ +- (void)testClientEngineAndClientVersionAreConfigurable { + NSData *datafile = [OPTLYTestHelper loadJSONDatafileIntoDataObject:kDataModelDatafileName]; + NSString *clientEngine = @"clientEngine"; + NSString *clientVersion = @"clientVersion"; + + OPTLYProjectConfig *projectConfig = [OPTLYProjectConfig initWithBuilderBlock:^(OPTLYProjectConfigBuilder * _Nullable builder) { + builder.datafile = datafile; + builder.clientEngine = clientEngine; + builder.clientVersion = clientVersion; + }]; + XCTAssertNotNil(projectConfig); + XCTAssertEqualObjects(projectConfig.clientEngine, clientEngine); + XCTAssertEqualObjects(projectConfig.clientVersion, clientVersion); } - (void)testInitWithBuilderBlockNoDatafile diff --git a/OptimizelySDKShared/OptimizelySDKShared/OPTLYClientBuilder.h b/OptimizelySDKShared/OptimizelySDKShared/OPTLYClientBuilder.h index 129e73651..3dd4426fa 100644 --- a/OptimizelySDKShared/OptimizelySDKShared/OPTLYClientBuilder.h +++ b/OptimizelySDKShared/OptimizelySDKShared/OPTLYClientBuilder.h @@ -41,6 +41,10 @@ typedef void (^OPTLYClientBuilderBlock)(OPTLYClientBuilder * _Nonnull builder); @property (nonatomic, readwrite, strong, nullable) id logger; /// User profile to be used by the Optimizely instance to store user-specific data. @property (nonatomic, readwrite, strong, nullable) id userProfile; +/// The client version +@property (nonatomic, strong, nonnull) NSString *clientVersion; +/// The client engine +@property (nonatomic, strong, nonnull) NSString *clientEngine; /// Create an Optimizely Client object. + (nonnull instancetype)builderWithBlock:(nonnull OPTLYClientBuilderBlock)block; diff --git a/OptimizelySDKShared/OptimizelySDKShared/OPTLYClientBuilder.m b/OptimizelySDKShared/OptimizelySDKShared/OPTLYClientBuilder.m index a117dfd70..2dab2357d 100644 --- a/OptimizelySDKShared/OptimizelySDKShared/OPTLYClientBuilder.m +++ b/OptimizelySDKShared/OptimizelySDKShared/OPTLYClientBuilder.m @@ -38,6 +38,8 @@ - (id)initWithBlock:(OPTLYClientBuilderBlock)block { builder.eventDispatcher = _eventDispatcher; builder.logger = _logger; builder.userProfile = _userProfile; + builder.clientEngine = _clientEngine; + builder.clientVersion = _clientVersion; }]; _logger = _optimizely.logger; if (!_logger) { diff --git a/OptimizelySDKShared/OptimizelySDKShared/OPTLYManager.h b/OptimizelySDKShared/OptimizelySDKShared/OPTLYManager.h index 2683a5a96..d1789964a 100644 --- a/OptimizelySDKShared/OptimizelySDKShared/OPTLYManager.h +++ b/OptimizelySDKShared/OptimizelySDKShared/OPTLYManager.h @@ -35,6 +35,10 @@ @property (nonatomic, readonly, strong, nullable) id logger; /// User profile to be used by the client to store user-specific data. @property (nonatomic, readonly, strong, nullable) id userProfile; +/// The client engine +@property (nonatomic, readonly, strong, nonnull) NSString *clientEngine; +/// The client version +@property (nonatomic, readonly, strong, nonnull) NSString *clientVersion; /** * Init with builder block @@ -43,6 +47,12 @@ */ + (nullable instancetype)initWithBuilderBlock:(nonnull OPTLYManagerBuilderBlock)block; +/** + * Init with a builder + * @param builder The Optimizely Manager Builder where datafile manager, event dispatcher, and other configurations will be set. + * @return OPTLYManager instance + */ ++ (instancetype)initWithBuilder:(OPTLYManagerBuilder *)builder; /* * Synchronous call that would retrieve the datafile from local cache. If it fails to load from local cache it will return a dummy instance */ diff --git a/OptimizelySDKShared/OptimizelySDKShared/OPTLYManager.m b/OptimizelySDKShared/OptimizelySDKShared/OPTLYManager.m index bfebc9c0b..4a17bb0b9 100644 --- a/OptimizelySDKShared/OptimizelySDKShared/OPTLYManager.m +++ b/OptimizelySDKShared/OptimizelySDKShared/OPTLYManager.m @@ -31,7 +31,11 @@ @interface OPTLYManager() @implementation OPTLYManager + (instancetype)initWithBuilderBlock:(OPTLYManagerBuilderBlock)block { - return [[self alloc] initWithBuilder:[OPTLYManagerBuilder builderWithBlock:block]]; + return [OPTLYManager initWithBuilder:[OPTLYManagerBuilder builderWithBlock:block]]; +} + ++ (instancetype)initWithBuilder:(OPTLYManagerBuilder *)builder { + return [[self alloc] initWithBuilder:builder]; } - (instancetype)init { @@ -54,6 +58,8 @@ - (instancetype)initWithBuilder:(OPTLYManagerBuilder *)builder { _logger = builder.logger; _projectId = builder.projectId; _userProfile = builder.userProfile; + _clientEngine = builder.clientEngine; + _clientVersion = builder.clientVersion; } return self; } @@ -127,6 +133,8 @@ - (OPTLYClient *)initializeClientWithManagerSettingsAndDatafile:(NSData *)datafi builder.eventDispatcher = self.eventDispatcher; builder.logger = self.logger; builder.userProfile = self.userProfile; + builder.clientEngine = self.clientEngine; + builder.clientVersion = self.clientVersion; }]; return client; } diff --git a/OptimizelySDKShared/OptimizelySDKShared/OPTLYManagerBuilder.h b/OptimizelySDKShared/OptimizelySDKShared/OPTLYManagerBuilder.h index 8cb56d622..dbabbd12c 100644 --- a/OptimizelySDKShared/OptimizelySDKShared/OPTLYManagerBuilder.h +++ b/OptimizelySDKShared/OptimizelySDKShared/OPTLYManagerBuilder.h @@ -39,6 +39,10 @@ typedef void (^OPTLYManagerBuilderBlock)(OPTLYManagerBuilder * _Nullable builder @property (nonatomic, readwrite, strong, nullable) id logger; /// User profile to be used by the client to store user-specific data. @property (nonatomic, readwrite, strong, nullable) id userProfile; +/// The client engine +@property (nonatomic, readwrite, strong, nonnull) NSString *clientEngine; +/// The client version +@property (nonatomic, readwrite, strong, nonnull) NSString *clientVersion; /// Create the Optimizely Manager object. + (nullable instancetype)builderWithBlock:(nonnull OPTLYManagerBuilderBlock)block; diff --git a/OptimizelySDKShared/OptimizelySDKShared/OPTLYManagerBuilder.m b/OptimizelySDKShared/OptimizelySDKShared/OPTLYManagerBuilder.m index f6641a281..f529deeba 100644 --- a/OptimizelySDKShared/OptimizelySDKShared/OPTLYManagerBuilder.m +++ b/OptimizelySDKShared/OptimizelySDKShared/OPTLYManagerBuilder.m @@ -35,39 +35,23 @@ - (id)initWithBlock:(OPTLYManagerBuilderBlock)block { self = [super init]; if (self != nil) { block(self); - if (![OPTLYDatafileManagerUtility conformsToOPTLYDatafileManagerProtocol:[self.datafileManager class]]) { + if (!self.datafileManager) { + self.datafileManager = [[OPTLYDatafileManagerBasic alloc] init]; + } + else if (![OPTLYDatafileManagerUtility conformsToOPTLYDatafileManagerProtocol:[self.datafileManager class]]) { return nil; } - } - return self; -} - -- (id)datafileManager { - if (!_datafileManager) { - _datafileManager = [[OPTLYDatafileManagerBasic alloc] init]; - } - return _datafileManager; -} - -- (id)errorHandler { - if (!_errorHandler) { - _errorHandler = [[OPTLYErrorHandlerNoOp alloc] init]; - } - return _errorHandler; -} - -- (id)eventDispatcher { - if (!_eventDispatcher) { - _eventDispatcher = [[OPTLYEventDispatcherBasic alloc] init]; - } - return _eventDispatcher; -} - -- (id)logger { - if (!_logger) { - _logger = [[OPTLYLoggerDefault alloc] init]; + if (!self.errorHandler) { + self.errorHandler = [[OPTLYErrorHandlerNoOp alloc] init]; + } + if (!self.eventDispatcher) { + self.eventDispatcher = [[OPTLYEventDispatcherBasic alloc] init]; + } + if (!self.logger) { + self.logger = [[OPTLYLoggerDefault alloc] init]; + } } - return _logger; + return self; } @end diff --git a/OptimizelySDKShared/OptimizelySDKSharedTests/OPTLYClientTest.m b/OptimizelySDKShared/OptimizelySDKSharedTests/OPTLYClientTest.m index 9f44bf07e..29c3b1646 100644 --- a/OptimizelySDKShared/OptimizelySDKSharedTests/OPTLYClientTest.m +++ b/OptimizelySDKShared/OptimizelySDKSharedTests/OPTLYClientTest.m @@ -19,6 +19,7 @@ #import "OPTLYClient.h" #import +#import // static datafile name static NSString *const kDatamodelDatafileName = @"datafile_6372300739"; @@ -48,4 +49,24 @@ - (void)testClientBuildsOptimizelyDefaults { XCTAssertNotNil(client.logger); } +/** + * Make sure the OPTLYClient Builder can pass the client engine and client version through to optimizely core and then to optimizely project config + */ +- (void)testClientPassesThroughClientEngineAndVersion { + NSString *clientEngine = @"clientEngine"; + NSString *clientVersion = @"clientVersion"; + OPTLYClient *client = [OPTLYClient initWithBuilderBlock:^(OPTLYClientBuilder * _Nonnull builder) { + builder.datafile = [OPTLYTestHelper loadJSONDatafileIntoDataObject:kDatamodelDatafileName]; + builder.clientEngine = clientEngine; + builder.clientVersion = clientVersion; + }]; + XCTAssertNotNil(client); + XCTAssertNotNil(client.optimizely); + XCTAssertNotNil(client.optimizely.config); + XCTAssertNotNil(client.optimizely.config.clientEngine); + XCTAssertNotNil(client.optimizely.config.clientVersion); + XCTAssertEqualObjects(client.optimizely.config.clientEngine, clientEngine); + XCTAssertEqualObjects(client.optimizely.config.clientVersion, clientVersion); +} + @end diff --git a/OptimizelySDKShared/OptimizelySDKSharedTests/OPTLYManagerBuilderTest.m b/OptimizelySDKShared/OptimizelySDKSharedTests/OPTLYManagerBuilderTest.m index 2c6a3adc8..34787c6e9 100644 --- a/OptimizelySDKShared/OptimizelySDKSharedTests/OPTLYManagerBuilderTest.m +++ b/OptimizelySDKShared/OptimizelySDKSharedTests/OPTLYManagerBuilderTest.m @@ -60,6 +60,8 @@ - (void)testManagerBuilderBuildsSuccessfulWithProjectId { XCTAssertNotNil(manager.eventDispatcher); XCTAssertNotNil(manager.logger); XCTAssertNotNil(manager.datafileManager); + XCTAssertNil(manager.clientEngine); + XCTAssertNil(manager.clientVersion); } - (void)testBuilderCanAssignErrorHandler { @@ -145,4 +147,24 @@ - (void)testBuilderCannotAssignDatafileManagerThatDoesNotConformToProtocol { XCTAssertNil(managerWithObject); } +/** + * Test the manager builder can properly assign the manager's client engine and client version + */ +- (void)testManagerBuilderCanAssignClientEngineAndClientVersion { + NSString *clientEngine = @"clientEngine"; + NSString *clientVersion = @"clientVersion"; + + OPTLYManager *manager = [OPTLYManager initWithBuilderBlock:^(OPTLYManagerBuilder * _Nullable builder) { + builder.projectId = kProjectId; + builder.clientEngine = clientEngine; + builder.clientVersion = clientVersion; + }]; + + XCTAssertNotNil(manager); + XCTAssertNotNil(manager.clientEngine); + XCTAssertNotNil(manager.clientVersion); + XCTAssertEqualObjects(manager.clientEngine, clientEngine); + XCTAssertEqualObjects(manager.clientVersion, clientVersion); +} + @end diff --git a/OptimizelySDKShared/OptimizelySDKSharedTests/OPTLYManagerTest.m b/OptimizelySDKShared/OptimizelySDKSharedTests/OPTLYManagerTest.m index 634e1ade9..b560552d2 100644 --- a/OptimizelySDKShared/OptimizelySDKSharedTests/OPTLYManagerTest.m +++ b/OptimizelySDKShared/OptimizelySDKSharedTests/OPTLYManagerTest.m @@ -58,6 +58,8 @@ - (void)testInitializationSettingsGetPropogatedToClientAndCore { id eventDispatcher = [[OPTLYEventDispatcherBasic alloc] init]; id logger = [[OPTLYLoggerDefault alloc] initWithLogLevel:OptimizelyLogLevelOff]; id userProfile = [[OPTLYUserProfileNoOp alloc] init]; + NSString *clientEngine = @"clientEngine"; + NSString *clientVersion = @"clientVersion"; // initialize Manager OPTLYManager *manager = [OPTLYManager initWithBuilderBlock:^(OPTLYManagerBuilder * _Nullable builder) { @@ -68,6 +70,8 @@ - (void)testInitializationSettingsGetPropogatedToClientAndCore { builder.logger = logger; builder.projectId = kProjectId; builder.userProfile = userProfile; + builder.clientEngine = clientEngine; + builder.clientVersion = clientVersion; }]; XCTAssertEqual(manager.datafileManager, datafileManager); @@ -82,6 +86,11 @@ - (void)testInitializationSettingsGetPropogatedToClientAndCore { XCTAssertEqual(optimizely.eventDispatcher, eventDispatcher); XCTAssertEqual(optimizely.logger, logger); XCTAssertEqual(optimizely.userProfile, userProfile); + XCTAssertNotNil(optimizely.config); + XCTAssertNotNil(optimizely.config.clientEngine); + XCTAssertNotNil(optimizely.config.clientVersion); + XCTAssertEqualObjects(optimizely.config.clientEngine, clientEngine); + XCTAssertEqualObjects(optimizely.config.clientVersion, clientVersion); } - (void)testInitializeClientWithoutDatafileReturnsDummy { diff --git a/OptimizelySDKTVOS/OptimizelySDKTVOS.xcodeproj/project.pbxproj b/OptimizelySDKTVOS/OptimizelySDKTVOS.xcodeproj/project.pbxproj index 80b816d52..9f5f636f2 100644 --- a/OptimizelySDKTVOS/OptimizelySDKTVOS.xcodeproj/project.pbxproj +++ b/OptimizelySDKTVOS/OptimizelySDKTVOS.xcodeproj/project.pbxproj @@ -7,8 +7,8 @@ objects = { /* Begin PBXBuildFile section */ - 2D3503A11DFA533800B0A822 /* OPTLYProjectConfig+tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D3503A01DFA533800B0A822 /* OPTLYProjectConfig+tvOS.h */; }; - 2D3503AC1DFA535F00B0A822 /* OPTLYProjectConfig+tvOS.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D3503AB1DFA535F00B0A822 /* OPTLYProjectConfig+tvOS.m */; }; + 2D14BCB31E0B0D2900D2FE5B /* OPTLYtvOSManagerBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D14BCB21E0B0D2900D2FE5B /* OPTLYtvOSManagerBuilder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2D14BCB51E0B0DDA00D2FE5B /* OPTLYtvOSManagerBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D14BCB41E0B0DDA00D2FE5B /* OPTLYtvOSManagerBuilder.m */; }; 2D3504161DFA78D600B0A822 /* OPTLYTestHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D35040E1DFA78D600B0A822 /* OPTLYTestHelper.m */; }; 2D3504171DFA78D600B0A822 /* BucketerTestsDatafile.json in Resources */ = {isa = PBXBuildFile; fileRef = 2D3504101DFA78D600B0A822 /* BucketerTestsDatafile.json */; }; 2D3504181DFA78D600B0A822 /* datafile_6372300739.json in Resources */ = {isa = PBXBuildFile; fileRef = 2D3504111DFA78D600B0A822 /* datafile_6372300739.json */; }; @@ -143,8 +143,8 @@ /* Begin PBXFileReference section */ 1273AF90BC689BE6B17EFDC5 /* Pods_OptimizelySDKTVOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OptimizelySDKTVOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 28DE410B256E509B248B59A2 /* Pods-OptimizelySDKTVOS.beta.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OptimizelySDKTVOS.beta.xcconfig"; path = "../Pods/Target Support Files/Pods-OptimizelySDKTVOS/Pods-OptimizelySDKTVOS.beta.xcconfig"; sourceTree = ""; }; - 2D3503A01DFA533800B0A822 /* OPTLYProjectConfig+tvOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OPTLYProjectConfig+tvOS.h"; sourceTree = ""; }; - 2D3503AB1DFA535F00B0A822 /* OPTLYProjectConfig+tvOS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "OPTLYProjectConfig+tvOS.m"; sourceTree = ""; }; + 2D14BCB21E0B0D2900D2FE5B /* OPTLYtvOSManagerBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OPTLYtvOSManagerBuilder.h; sourceTree = ""; }; + 2D14BCB41E0B0DDA00D2FE5B /* OPTLYtvOSManagerBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OPTLYtvOSManagerBuilder.m; sourceTree = ""; }; 2D35040D1DFA78D600B0A822 /* OPTLYTestHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OPTLYTestHelper.h; sourceTree = ""; }; 2D35040E1DFA78D600B0A822 /* OPTLYTestHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OPTLYTestHelper.m; sourceTree = ""; }; 2D3504101DFA78D600B0A822 /* BucketerTestsDatafile.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = BucketerTestsDatafile.json; sourceTree = ""; }; @@ -260,8 +260,8 @@ children = ( EA52495D1DC736DF00AF6685 /* OptimizelySDKTVOS.modulemap */, EA2FA7271DC1FA9F00B1D81B /* OptimizelySDKTVOS.h */, - 2D3503A01DFA533800B0A822 /* OPTLYProjectConfig+tvOS.h */, - 2D3503AB1DFA535F00B0A822 /* OPTLYProjectConfig+tvOS.m */, + 2D14BCB21E0B0D2900D2FE5B /* OPTLYtvOSManagerBuilder.h */, + 2D14BCB41E0B0DDA00D2FE5B /* OPTLYtvOSManagerBuilder.m */, EA2FA7281DC1FA9F00B1D81B /* OptimizelySDKTVOS-Info.plist */, ); path = OptimizelySDKTVOS; @@ -321,7 +321,7 @@ buildActionMask = 2147483647; files = ( EA2FA7351DC1FAA000B1D81B /* OptimizelySDKTVOS.h in Headers */, - 2D3503A11DFA533800B0A822 /* OPTLYProjectConfig+tvOS.h in Headers */, + 2D14BCB31E0B0D2900D2FE5B /* OPTLYtvOSManagerBuilder.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -616,7 +616,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2D3503AC1DFA535F00B0A822 /* OPTLYProjectConfig+tvOS.m in Sources */, + 2D14BCB51E0B0DDA00D2FE5B /* OPTLYtvOSManagerBuilder.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/OptimizelySDKTVOS/OptimizelySDKTVOS/OPTLYProjectConfig+tvOS.m b/OptimizelySDKTVOS/OptimizelySDKTVOS/OPTLYProjectConfig+tvOS.m deleted file mode 100644 index a8c7c20eb..000000000 --- a/OptimizelySDKTVOS/OptimizelySDKTVOS/OPTLYProjectConfig+tvOS.m +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************** - * Copyright 2016, Optimizely, Inc. and contributors * - * * - * 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 -#import "OPTLYProjectConfig+tvOS.h" - -NSString * const kClientEngine = @"objective-c-sdk-tvOS"; - -@implementation OPTLYProjectConfig (OptimizelySDKTVOS) - -+ (void)load { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - SEL clientEngineSelector = @selector(clientEngine); - SEL clientVersionSelector = @selector(clientVersion); - SEL iOSClientEngineSelector = @selector(iOSclientEngine); - SEL iOSClientVersionSelector = @selector(iOSclientVersion); - Method clientEngineMethod = class_getInstanceMethod(self, clientEngineSelector); - Method clientVersionMethod = class_getInstanceMethod(self, clientVersionSelector); - Method iOSClientEngineMethod = class_getInstanceMethod(self, iOSClientEngineSelector); - Method iOSClientVersionMethod = class_getInstanceMethod(self, iOSClientVersionSelector); - - BOOL methodAdded; - - // replace client engine - methodAdded = class_addMethod([self class], - clientEngineSelector, - method_getImplementation(iOSClientEngineMethod), - method_getTypeEncoding(iOSClientEngineMethod)); - if (methodAdded) { - class_replaceMethod([self class], - iOSClientEngineSelector, - method_getImplementation(clientEngineMethod), - method_getTypeEncoding(clientEngineMethod)); - } - else { - method_exchangeImplementations(clientEngineMethod, iOSClientEngineMethod); - } - - // replace client version - methodAdded = class_addMethod([self class], - clientVersionSelector, - method_getImplementation(iOSClientVersionMethod), - method_getTypeEncoding(iOSClientVersionMethod)); - if (methodAdded) { - class_replaceMethod([self class], - iOSClientVersionSelector, - method_getImplementation(clientVersionMethod), - method_getTypeEncoding(clientVersionMethod)); - } - else { - method_exchangeImplementations(clientVersionMethod, iOSClientVersionMethod); - } - }); -} - -- (NSString *)iOSclientEngine { - return kClientEngine; -} - -- (NSString *)iOSclientVersion { - return OPTIMIZELY_SDK_TVOS_VERSION; -} - -@end diff --git a/OptimizelySDKiOS/OptimizelySDKiOS/OPTLYProjectConfig+iOS.h b/OptimizelySDKTVOS/OptimizelySDKTVOS/OPTLYtvOSManagerBuilder.h similarity index 71% rename from OptimizelySDKiOS/OptimizelySDKiOS/OPTLYProjectConfig+iOS.h rename to OptimizelySDKTVOS/OptimizelySDKTVOS/OPTLYtvOSManagerBuilder.h index d03caea0d..7a5ee9a82 100644 --- a/OptimizelySDKiOS/OptimizelySDKiOS/OPTLYProjectConfig+iOS.h +++ b/OptimizelySDKTVOS/OptimizelySDKTVOS/OPTLYtvOSManagerBuilder.h @@ -13,9 +13,18 @@ * See the License for the specific language governing permissions and * * limitations under the License. * ***************************************************************************/ + #import -#import +#import + +@protocol OPTLYDatafileManager, OPTLYErrorHandler, OPTLYEventDispatcher, OPTLYLogger, OPTLYUserProfile; +@class OPTLYtvOSManagerBuilder; + +typedef void (^OPTLYtvOSManagerBuilderBlock)(OPTLYtvOSManagerBuilder * _Nullable builder); + +@interface OPTLYtvOSManagerBuilder : OPTLYManagerBuilder -@interface OPTLYProjectConfig (OptimizelySDKiOS) +/// Create the Optimizely tvOS Manager Builder object. ++ (nullable instancetype)builderWithBlock:(nonnull OPTLYtvOSManagerBuilderBlock)block; @end diff --git a/OptimizelySDKTVOS/OptimizelySDKTVOS/OPTLYtvOSManagerBuilder.m b/OptimizelySDKTVOS/OptimizelySDKTVOS/OPTLYtvOSManagerBuilder.m new file mode 100644 index 000000000..2f8833d03 --- /dev/null +++ b/OptimizelySDKTVOS/OptimizelySDKTVOS/OPTLYtvOSManagerBuilder.m @@ -0,0 +1,94 @@ +/**************************************************************************** + * Copyright 2016, Optimizely, Inc. and contributors * + * * + * 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 +#import +#import +#import +#import +#import +#import "OPTLYtvOSManagerBuilder.h" + +static NSString * const kClientEngine = @"objective-c-sdk-tvOS"; + +@implementation OPTLYtvOSManagerBuilder + ++ (nullable instancetype)builderWithBlock:(OPTLYtvOSManagerBuilderBlock)block { + return [[self alloc] initWithBlock:block]; +} + +- (id)init { + return [self initWithBlock:nil]; +} + +- (id)initWithBlock:(OPTLYtvOSManagerBuilderBlock)block { + NSParameterAssert(block); + if (self != nil) { + block(self); + if (!self.logger) { + self.logger = [[OPTLYLoggerDefault alloc] init]; + } + if (!self.errorHandler) { + self.errorHandler = [[OPTLYErrorHandlerNoOp alloc] init]; + } + + // set datafile manager + if (!self.datafileManager) { + self.datafileManager = [OPTLYDatafileManagerDefault initWithBuilderBlock:^(OPTLYDatafileManagerBuilder * _Nullable builder) { + builder.datafileFetchInterval = 120; + builder.projectId = self.projectId; + builder.errorHandler = self.errorHandler; + builder.logger = self.logger; + }]; + } + else if (![OPTLYDatafileManagerUtility conformsToOPTLYDatafileManagerProtocol:[self.datafileManager class]]) { + return nil; + } + + // set event dispatcher + if (!self.eventDispatcher) { + self.eventDispatcher = [OPTLYEventDispatcherDefault initWithBuilderBlock:^(OPTLYEventDispatcherBuilder * _Nullable builder) { + builder.eventDispatcherDispatchInterval = 0; + builder.eventDispatcherDispatchTimeout = 2; + builder.logger = self.logger; + }]; + } + else if (![OPTLYEventDispatcherUtility conformsToOPTLYEventDispatcherProtocol:[self.eventDispatcher class]]) { + return nil; + } + + // set user profile + if (!self.userProfile) { + self.userProfile = [OPTLYUserProfileDefault initWithBuilderBlock:^(OPTLYUserProfileBuilder * _Nullable builder) { + builder.logger = self.logger; + }]; + } + else if (![OPTLYUserProfileUtility conformsToOPTLYUserProfileProtocol:[self.userProfile class]]) { + return nil; + } + + // set client engine and client version + if (!self.clientEngine) { + self.clientEngine = kClientEngine; + } + if (!self.clientVersion) { + self.clientVersion = OPTIMIZELY_SDK_TVOS_VERSION; + } + } + return self; +} + +@end diff --git a/OptimizelySDKTVOS/OptimizelySDKTVOS/OptimizelySDKTVOS.h b/OptimizelySDKTVOS/OptimizelySDKTVOS/OptimizelySDKTVOS.h index d2eef7ac1..97f5b0774 100644 --- a/OptimizelySDKTVOS/OptimizelySDKTVOS/OptimizelySDKTVOS.h +++ b/OptimizelySDKTVOS/OptimizelySDKTVOS/OptimizelySDKTVOS.h @@ -17,6 +17,7 @@ #import #import #import +#import "OPTLYtvOSManagerBuilder.h" //! Project version number for OptimizelySDKTVOS. FOUNDATION_EXPORT double OptimizelySDKTVOSVersionNumber; diff --git a/OptimizelySDKTVOS/OptimizelySDKTVOSTests/OptimizelySDKTVOSTests.m b/OptimizelySDKTVOS/OptimizelySDKTVOSTests/OptimizelySDKTVOSTests.m index 271e7105e..f930c7048 100644 --- a/OptimizelySDKTVOS/OptimizelySDKTVOSTests/OptimizelySDKTVOSTests.m +++ b/OptimizelySDKTVOS/OptimizelySDKTVOSTests/OptimizelySDKTVOSTests.m @@ -59,10 +59,10 @@ + (void)tearDown { } - (void)testTVOSSDKInitializedWithOverrides { - OPTLYManager *manager = [OPTLYManager initWithBuilderBlock:^(OPTLYManagerBuilder * _Nullable builder) { + OPTLYManager *manager = [OPTLYManager initWithBuilder:[OPTLYtvOSManagerBuilder builderWithBlock:^(OPTLYtvOSManagerBuilder * _Nullable builder) { builder.datafile = kDefaultDatafile; builder.projectId = kProjectId; - }]; + }]]; XCTAssertNotNil(manager); XCTAssertNotNil(manager.datafileManager); XCTAssertNotNil(manager.errorHandler); diff --git a/OptimizelySDKiOS/OptimizelySDKiOS.xcodeproj/project.pbxproj b/OptimizelySDKiOS/OptimizelySDKiOS.xcodeproj/project.pbxproj index b4c613c81..06972c95e 100644 --- a/OptimizelySDKiOS/OptimizelySDKiOS.xcodeproj/project.pbxproj +++ b/OptimizelySDKiOS/OptimizelySDKiOS.xcodeproj/project.pbxproj @@ -8,8 +8,8 @@ /* Begin PBXBuildFile section */ 0A40C71D7B825E4BFD61A110 /* Pods_OptimizelySDKiOSTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D9B2266C94E7767CEB55292 /* Pods_OptimizelySDKiOSTests.framework */; }; - 2D3503941DFA52D100B0A822 /* OPTLYProjectConfig+iOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D3503931DFA52D100B0A822 /* OPTLYProjectConfig+iOS.h */; }; - 2D35039F1DFA530A00B0A822 /* OPTLYProjectConfig+iOS.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D35039E1DFA530A00B0A822 /* OPTLYProjectConfig+iOS.m */; }; + 2D14BCA61E09DC2A00D2FE5B /* OPTLYiOSManagerBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D14BCA51E09DC2A00D2FE5B /* OPTLYiOSManagerBuilder.h */; }; + 2D14BCA81E09DC7000D2FE5B /* OPTLYiOSManagerBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D14BCA71E09DC7000D2FE5B /* OPTLYiOSManagerBuilder.m */; }; 2D3503FD1DFA78CB00B0A822 /* OPTLYTestHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D3503F51DFA78CB00B0A822 /* OPTLYTestHelper.m */; }; 2D3503FE1DFA78CB00B0A822 /* BucketerTestsDatafile.json in Resources */ = {isa = PBXBuildFile; fileRef = 2D3503F71DFA78CB00B0A822 /* BucketerTestsDatafile.json */; }; 2D3503FF1DFA78CB00B0A822 /* datafile_6372300739.json in Resources */ = {isa = PBXBuildFile; fileRef = 2D3503F81DFA78CB00B0A822 /* datafile_6372300739.json */; }; @@ -142,8 +142,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 2D3503931DFA52D100B0A822 /* OPTLYProjectConfig+iOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OPTLYProjectConfig+iOS.h"; sourceTree = ""; }; - 2D35039E1DFA530A00B0A822 /* OPTLYProjectConfig+iOS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "OPTLYProjectConfig+iOS.m"; sourceTree = ""; }; + 2D14BCA51E09DC2A00D2FE5B /* OPTLYiOSManagerBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OPTLYiOSManagerBuilder.h; sourceTree = ""; }; + 2D14BCA71E09DC7000D2FE5B /* OPTLYiOSManagerBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OPTLYiOSManagerBuilder.m; sourceTree = ""; }; 2D3503F41DFA78CB00B0A822 /* OPTLYTestHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OPTLYTestHelper.h; sourceTree = ""; }; 2D3503F51DFA78CB00B0A822 /* OPTLYTestHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OPTLYTestHelper.m; sourceTree = ""; }; 2D3503F71DFA78CB00B0A822 /* BucketerTestsDatafile.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = BucketerTestsDatafile.json; sourceTree = ""; }; @@ -273,8 +273,8 @@ children = ( EA52495C1DC736B100AF6685 /* OptimizelySDKiOS.modulemap */, EA3C68501DC1E6B600C578CA /* OptimizelySDKiOS.h */, - 2D3503931DFA52D100B0A822 /* OPTLYProjectConfig+iOS.h */, - 2D35039E1DFA530A00B0A822 /* OPTLYProjectConfig+iOS.m */, + 2D14BCA51E09DC2A00D2FE5B /* OPTLYiOSManagerBuilder.h */, + 2D14BCA71E09DC7000D2FE5B /* OPTLYiOSManagerBuilder.m */, EA3C68521DC1E6B600C578CA /* OptimizelySDKiOS-Info.plist */, ); path = OptimizelySDKiOS; @@ -323,7 +323,7 @@ buildActionMask = 2147483647; files = ( EA3C68511DC1E6B600C578CA /* OptimizelySDKiOS.h in Headers */, - 2D3503941DFA52D100B0A822 /* OPTLYProjectConfig+iOS.h in Headers */, + 2D14BCA61E09DC2A00D2FE5B /* OPTLYiOSManagerBuilder.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -616,7 +616,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2D35039F1DFA530A00B0A822 /* OPTLYProjectConfig+iOS.m in Sources */, + 2D14BCA81E09DC7000D2FE5B /* OPTLYiOSManagerBuilder.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/OptimizelySDKiOS/OptimizelySDKiOS/OPTLYProjectConfig+iOS.m b/OptimizelySDKiOS/OptimizelySDKiOS/OPTLYProjectConfig+iOS.m deleted file mode 100644 index d185ee6be..000000000 --- a/OptimizelySDKiOS/OptimizelySDKiOS/OPTLYProjectConfig+iOS.m +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************** - * Copyright 2016, Optimizely, Inc. and contributors * - * * - * 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 -#import "OPTLYProjectConfig+iOS.h" - -NSString * const kClientEngine = @"objective-c-sdk-iOS"; - -@implementation OPTLYProjectConfig (OptimizelySDKiOS) - -+ (void)load { - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - SEL clientEngineSelector = @selector(clientEngine); - SEL clientVersionSelector = @selector(clientVersion); - SEL iOSClientEngineSelector = @selector(iOSclientEngine); - SEL iOSClientVersionSelector = @selector(iOSclientVersion); - Method clientEngineMethod = class_getInstanceMethod(self, clientEngineSelector); - Method clientVersionMethod = class_getInstanceMethod(self, clientVersionSelector); - Method iOSClientEngineMethod = class_getInstanceMethod(self, iOSClientEngineSelector); - Method iOSClientVersionMethod = class_getInstanceMethod(self, iOSClientVersionSelector); - - BOOL methodAdded; - - // replace client engine - methodAdded = class_addMethod([self class], - clientEngineSelector, - method_getImplementation(iOSClientEngineMethod), - method_getTypeEncoding(iOSClientEngineMethod)); - if (methodAdded) { - class_replaceMethod([self class], - iOSClientEngineSelector, - method_getImplementation(clientEngineMethod), - method_getTypeEncoding(clientEngineMethod)); - } - else { - method_exchangeImplementations(clientEngineMethod, iOSClientEngineMethod); - } - - // replace client version - methodAdded = class_addMethod([self class], - clientVersionSelector, - method_getImplementation(iOSClientVersionMethod), - method_getTypeEncoding(iOSClientVersionMethod)); - if (methodAdded) { - class_replaceMethod([self class], - iOSClientVersionSelector, - method_getImplementation(clientVersionMethod), - method_getTypeEncoding(clientVersionMethod)); - } - else { - method_exchangeImplementations(clientVersionMethod, iOSClientVersionMethod); - } - }); -} - -- (NSString *)iOSclientEngine { - return kClientEngine; -} - -- (NSString *)iOSclientVersion { - return OPTIMIZELY_SDK_iOS_VERSION; -} - -@end diff --git a/OptimizelySDKTVOS/OptimizelySDKTVOS/OPTLYProjectConfig+tvOS.h b/OptimizelySDKiOS/OptimizelySDKiOS/OPTLYiOSManagerBuilder.h similarity index 71% rename from OptimizelySDKTVOS/OptimizelySDKTVOS/OPTLYProjectConfig+tvOS.h rename to OptimizelySDKiOS/OptimizelySDKiOS/OPTLYiOSManagerBuilder.h index b83e17265..719a9366f 100644 --- a/OptimizelySDKTVOS/OptimizelySDKTVOS/OPTLYProjectConfig+tvOS.h +++ b/OptimizelySDKiOS/OptimizelySDKiOS/OPTLYiOSManagerBuilder.h @@ -15,10 +15,16 @@ ***************************************************************************/ #import -#import +#import -@class OPTLYProjectConfig; +@protocol OPTLYDatafileManager, OPTLYErrorHandler, OPTLYEventDispatcher, OPTLYLogger, OPTLYUserProfile; +@class OPTLYiOSManagerBuilder; -@interface OPTLYTVOSProjectConfig : OPTLYProjectConfig +typedef void (^OPTLYiOSManagerBuilderBlock)(OPTLYiOSManagerBuilder * _Nullable builder); + +@interface OPTLYiOSManagerBuilder : OPTLYManagerBuilder + +/// Create the Optimizely iOS Manager Builder object. ++ (nullable instancetype)builderWithBlock:(nonnull OPTLYiOSManagerBuilderBlock)block; @end diff --git a/OptimizelySDKiOS/OptimizelySDKiOS/OPTLYiOSManagerBuilder.m b/OptimizelySDKiOS/OptimizelySDKiOS/OPTLYiOSManagerBuilder.m new file mode 100644 index 000000000..b46d7ec13 --- /dev/null +++ b/OptimizelySDKiOS/OptimizelySDKiOS/OPTLYiOSManagerBuilder.m @@ -0,0 +1,94 @@ +/**************************************************************************** + * Copyright 2016, Optimizely, Inc. and contributors * + * * + * 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 +#import +#import +#import +#import +#import +#import "OPTLYiOSManagerBuilder.h" + +static NSString * const kClientEngine = @"objective-c-sdk-iOS"; + +@implementation OPTLYiOSManagerBuilder + ++ (nullable instancetype)builderWithBlock:(OPTLYiOSManagerBuilderBlock)block { + return [[self alloc] initWithBlock:block]; +} + +- (id)init { + return [self initWithBlock:nil]; +} + +- (id)initWithBlock:(OPTLYiOSManagerBuilderBlock)block { + NSParameterAssert(block); + if (self != nil) { + block(self); + if (!self.logger) { + self.logger = [[OPTLYLoggerDefault alloc] init]; + } + if (!self.errorHandler) { + self.errorHandler = [[OPTLYErrorHandlerNoOp alloc] init]; + } + + // set datafile manager + if (!self.datafileManager) { + self.datafileManager = [OPTLYDatafileManagerDefault initWithBuilderBlock:^(OPTLYDatafileManagerBuilder * _Nullable builder) { + builder.datafileFetchInterval = 120; + builder.projectId = self.projectId; + builder.errorHandler = self.errorHandler; + builder.logger = self.logger; + }]; + } + else if (![OPTLYDatafileManagerUtility conformsToOPTLYDatafileManagerProtocol:[self.datafileManager class]]) { + return nil; + } + + // set event dispatcher + if (!self.eventDispatcher) { + self.eventDispatcher = [OPTLYEventDispatcherDefault initWithBuilderBlock:^(OPTLYEventDispatcherBuilder * _Nullable builder) { + builder.eventDispatcherDispatchInterval = 0; + builder.eventDispatcherDispatchTimeout = 2; + builder.logger = self.logger; + }]; + } + else if (![OPTLYEventDispatcherUtility conformsToOPTLYEventDispatcherProtocol:[self.eventDispatcher class]]) { + return nil; + } + + // set user profile + if (!self.userProfile) { + self.userProfile = [OPTLYUserProfileDefault initWithBuilderBlock:^(OPTLYUserProfileBuilder * _Nullable builder) { + builder.logger = self.logger; + }]; + } + else if (![OPTLYUserProfileUtility conformsToOPTLYUserProfileProtocol:[self.userProfile class]]) { + return nil; + } + + // set client engine and client version + if (!self.clientEngine) { + self.clientEngine = kClientEngine; + } + if (!self.clientVersion) { + self.clientVersion = OPTIMIZELY_SDK_iOS_VERSION; + } + } + return self; +} + +@end diff --git a/OptimizelySDKiOS/OptimizelySDKiOS/OptimizelySDKiOS.h b/OptimizelySDKiOS/OptimizelySDKiOS/OptimizelySDKiOS.h index 56a96d6f5..287cdb014 100644 --- a/OptimizelySDKiOS/OptimizelySDKiOS/OptimizelySDKiOS.h +++ b/OptimizelySDKiOS/OptimizelySDKiOS/OptimizelySDKiOS.h @@ -17,6 +17,7 @@ #import #import #import +#import "OPTLYiOSManagerBuilder.h" //! Project version number for OptimizelySDKiOS. FOUNDATION_EXPORT double OptimizelySDKiOSVersionNumber; diff --git a/OptimizelySDKiOS/OptimizelySDKiOSTests/OptimizelySDKiOSTests.m b/OptimizelySDKiOS/OptimizelySDKiOSTests/OptimizelySDKiOSTests.m index 32aff4606..a8e84b6ec 100644 --- a/OptimizelySDKiOS/OptimizelySDKiOSTests/OptimizelySDKiOSTests.m +++ b/OptimizelySDKiOS/OptimizelySDKiOSTests/OptimizelySDKiOSTests.m @@ -59,10 +59,10 @@ + (void)tearDown { } - (void)testiOSSDKInitializedWithOverrides { - OPTLYManager *manager = [OPTLYManager initWithBuilderBlock:^(OPTLYManagerBuilder * _Nullable builder) { + OPTLYManager *manager = [OPTLYManager initWithBuilder:[OPTLYiOSManagerBuilder builderWithBlock:^(OPTLYiOSManagerBuilder * _Nullable builder) { builder.datafile = kDefaultDatafile; builder.projectId = kProjectId; - }]; + }]]; XCTAssertNotNil(manager); XCTAssertNotNil(manager.datafileManager); XCTAssertNotNil(manager.errorHandler);