Skip to content

Commit 114e501

Browse files
authored
Set AppId and Dev or Prod keys from a plist (#383)
* Set AppId and Dev or Prod keys from a plist * Moved setting the keys to Leanplum load method. Introduced environment setting to control prod/dev mode * Fix Leanplum throwError to rethrow exceptions in unit tests.
1 parent 239b3f0 commit 114e501

File tree

8 files changed

+293
-0
lines changed

8 files changed

+293
-0
lines changed

Example/Leanplum-SDK.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117
A8F4479E2449769000F6978A /* LPNetworkOperationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = A8F4479D2449769000F6978A /* LPNetworkOperationTest.m */; };
118118
B449EB2A21F27AB2005C93B6 /* TiedPrioritiesDifferentDelay.json in Resources */ = {isa = PBXBuildFile; fileRef = B449EB2921F27AB2005C93B6 /* TiedPrioritiesDifferentDelay.json */; };
119119
B449EB2B21F27B0B005C93B6 /* TiedPrioritiesDifferentDelay.json in Resources */ = {isa = PBXBuildFile; fileRef = B449EB2921F27AB2005C93B6 /* TiedPrioritiesDifferentDelay.json */; };
120+
E773031E24AB871E00EDF983 /* Leanplum-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = E773031D24AB871E00EDF983 /* Leanplum-Info.plist */; };
120121
/* End PBXBuildFile section */
121122

122123
/* Begin PBXContainerItemProxy section */
@@ -241,6 +242,7 @@
241242
B5CCCA371D74B64D005ADEE1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
242243
B5CCCA391D74B64D005ADEE1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
243244
D2BDBCD86C8BEA8BF5B15B99 /* Pods-Leanplum-SDK_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Leanplum-SDK_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Leanplum-SDK_Example/Pods-Leanplum-SDK_Example.debug.xcconfig"; sourceTree = "<group>"; };
245+
E773031D24AB871E00EDF983 /* Leanplum-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Leanplum-Info.plist"; sourceTree = "<group>"; };
244246
ED67DCDB70EA6598AF12284A /* Pods-Leanplum-SDK_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Leanplum-SDK_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-Leanplum-SDK_Example/Pods-Leanplum-SDK_Example.release.xcconfig"; sourceTree = "<group>"; };
245247
F5CF859C9DD307380E6F9A30 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; };
246248
/* End PBXFileReference section */
@@ -476,6 +478,7 @@
476478
6003F5B6195388D20070C39A /* Supporting Files */ = {
477479
isa = PBXGroup;
478480
children = (
481+
E773031D24AB871E00EDF983 /* Leanplum-Info.plist */,
479482
6003F5B7195388D20070C39A /* Tests-Info.plist */,
480483
6003F5B8195388D20070C39A /* InfoPlist.strings */,
481484
606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */,
@@ -646,6 +649,7 @@
646649
07E5C8F01F052DD000A4B092 /* DifferentPrioritiesWithMissingValues.json in Resources */,
647650
6003F5A9195388D20070C39A /* Images.xcassets in Resources */,
648651
07E5C8EB1F052DCC00A4B092 /* test.file in Resources */,
652+
E773031E24AB871E00EDF983 /* Leanplum-Info.plist in Resources */,
649653
07E5C8E81F052DC700A4B092 /* malformed_track_event_response.json in Resources */,
650654
07E5C8F31F052DD000A4B092 /* sample_action_notification.json in Resources */,
651655
07E5C8E51F052DC400A4B092 /* track_event_response.json in Resources */,

Example/Tests/Classes/LeanplumTest.m

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
#import "LPRegisterDevice.h"
4141
#import "Leanplum.h"
4242
#import "LPOperationQueue.h"
43+
#import "LPAPIConfig.h"
44+
45+
#import <OCMock/OCMArg.h>
4346

4447
/**
4548
* Tests leanplum public methods, we seed predefined response that comes from backend
@@ -75,6 +78,10 @@ + (void)setUp
7578

7679
- (void)setUp {
7780
[super setUp];
81+
82+
// Clear the set keys, required for plist testing
83+
[[LPAPIConfig sharedConfig] setAppId:nil withAccessKey:nil];
84+
[[LPConstantsState sharedState] setIsDevelopmentModeEnabled:NO];
7885
}
7986

8087
- (void)tearDown {
@@ -84,6 +91,142 @@ - (void)tearDown {
8491
[HTTPStubs removeAllStubs];
8592
}
8693

94+
/**
95+
* Tests setting the environment in the plist to production.
96+
*/
97+
- (void) test_leanplum_load_plist_env_key_prod
98+
{
99+
id mockLeanplum = OCMClassMock([Leanplum class]);
100+
NSMutableDictionary *plistDict = [[NSMutableDictionary alloc] initWithDictionary:[Leanplum getDefaultAppKeysPlist] copyItems:YES];
101+
plistDict[kEnvKey] = kEnvProduction;
102+
[[[mockLeanplum stub] andReturn:plistDict] getDefaultAppKeysPlist];
103+
// Force reload
104+
[Leanplum load];
105+
106+
XCTAssertEqualObjects([[LPAPIConfig sharedConfig] appId], APPLICATION_ID);
107+
XCTAssertEqualObjects([[LPAPIConfig sharedConfig] accessKey], PRODUCTION_KEY);
108+
XCTAssertFalse([[LPConstantsState sharedState] isDevelopmentModeEnabled]);
109+
}
110+
111+
/**
112+
* Tests setting the environment in the plist to development.
113+
*/
114+
- (void) test_leanplum_load_plist_env_key_dev
115+
{
116+
id mockLeanplum = OCMClassMock([Leanplum class]);
117+
NSMutableDictionary *plistDict = [[NSMutableDictionary alloc] initWithDictionary:[Leanplum getDefaultAppKeysPlist] copyItems:YES];
118+
plistDict[kEnvKey] = kEnvDevelopment;
119+
[[[mockLeanplum stub] andReturn:plistDict] getDefaultAppKeysPlist];
120+
// Force reload
121+
[Leanplum load];
122+
123+
XCTAssertEqualObjects([[LPAPIConfig sharedConfig] appId], APPLICATION_ID);
124+
XCTAssertEqualObjects([[LPAPIConfig sharedConfig] accessKey], DEVELOPMENT_KEY);
125+
XCTAssertTrue([[LPConstantsState sharedState] isDevelopmentModeEnabled]);
126+
}
127+
128+
/**
129+
* Tests setting explicitly the environment to development.
130+
*/
131+
- (void) test_set_app_environment_dev
132+
{
133+
[Leanplum setAppEnvironment:kEnvDevelopment];
134+
135+
XCTAssertEqualObjects([[LPAPIConfig sharedConfig] appId], APPLICATION_ID);
136+
XCTAssertEqualObjects([[LPAPIConfig sharedConfig] accessKey], DEVELOPMENT_KEY);
137+
XCTAssertTrue([[LPConstantsState sharedState] isDevelopmentModeEnabled]);
138+
}
139+
140+
/**
141+
* Tests setting explicitly the environment to production.
142+
*/
143+
- (void) test_set_app_environment_prod
144+
{
145+
[Leanplum setAppEnvironment:kEnvProduction];
146+
147+
XCTAssertEqualObjects([[LPAPIConfig sharedConfig] appId], APPLICATION_ID);
148+
XCTAssertEqualObjects([[LPAPIConfig sharedConfig] accessKey], PRODUCTION_KEY);
149+
XCTAssertFalse([[LPConstantsState sharedState] isDevelopmentModeEnabled]);
150+
}
151+
152+
/**
153+
* Tests environment cannot be set with incorrect value.
154+
*/
155+
- (void) test_set_app_environment_incorrect
156+
{
157+
[LeanplumHelper mockThrowErrorToThrow];
158+
XCTAssertThrows([Leanplum setAppEnvironment:@"staging"], @"Incorrect environment.");
159+
XCTAssertTrue([LeanplumHelper.lastErrorMessage containsString:@"Incorrect env parameter."]);
160+
}
161+
162+
/**
163+
* Tests environment cannot be set after Leanplum has started.
164+
*/
165+
- (void) test_set_app_environment_after_start
166+
{
167+
[LeanplumHelper mockThrowErrorToThrow];
168+
169+
[Leanplum load];
170+
// Set Leanplum start was executed.
171+
[[LPInternalState sharedState] setCalledStart:YES];
172+
173+
XCTAssertThrows([Leanplum setAppEnvironment:kEnvProduction], @"Already called start.");
174+
XCTAssertTrue([LeanplumHelper.lastErrorMessage containsString:@"Leanplum already started. Call this method before [Leanplum start]."]);
175+
}
176+
177+
/**
178+
* Tests app keys remain unset if plist is nil.
179+
*/
180+
- (void) test_leanplum_load_plist_with_nil
181+
{
182+
id mockLeanplum = OCMClassMock([Leanplum class]);
183+
[[[mockLeanplum stub] andReturn:nil] getDefaultAppKeysPlist];
184+
// Force reload
185+
[Leanplum load];
186+
187+
XCTAssertEqualObjects([[LPAPIConfig sharedConfig] appId], nil);
188+
XCTAssertEqualObjects([[LPAPIConfig sharedConfig] accessKey], nil);
189+
XCTAssertFalse([[LPConstantsState sharedState] isDevelopmentModeEnabled]);
190+
}
191+
192+
/**
193+
* Tests setting the app keys with Leanplum load method using plist.
194+
*/
195+
- (void) test_leanplum_load_plist
196+
{
197+
[Leanplum load];
198+
#if DEBUG
199+
XCTAssertEqualObjects([[LPAPIConfig sharedConfig] accessKey], DEVELOPMENT_KEY);
200+
XCTAssertTrue([[LPConstantsState sharedState] isDevelopmentModeEnabled]);
201+
#else
202+
XCTAssertEqualObjects([[LPAPIConfig sharedConfig] accessKey], PRODUCTION_KEY);
203+
XCTAssertFalse([[LPConstantsState sharedState] isDevelopmentModeEnabled]);
204+
#endif
205+
XCTAssertEqualObjects([[LPAPIConfig sharedConfig] appId], APPLICATION_ID);
206+
}
207+
208+
/**
209+
* Tests setting the app for development using plist.
210+
*/
211+
- (void) test_set_development_from_plist
212+
{
213+
[Leanplum setAppUsingPlist:[Leanplum getDefaultAppKeysPlist] forEnvironment:kEnvDevelopment];
214+
XCTAssertEqualObjects([[LPAPIConfig sharedConfig] appId], APPLICATION_ID);
215+
XCTAssertEqualObjects([[LPAPIConfig sharedConfig] accessKey], DEVELOPMENT_KEY);
216+
XCTAssertTrue([[LPConstantsState sharedState] isDevelopmentModeEnabled]);
217+
}
218+
219+
/**
220+
* Tests setting the app for production using plist.
221+
*/
222+
- (void) test_set_production_from_plist
223+
{
224+
[Leanplum setAppUsingPlist:[Leanplum getDefaultAppKeysPlist] forEnvironment:kEnvProduction];
225+
XCTAssertEqualObjects([[LPAPIConfig sharedConfig] appId], APPLICATION_ID);
226+
XCTAssertEqualObjects([[LPAPIConfig sharedConfig] accessKey], PRODUCTION_KEY);
227+
XCTAssertFalse([[LPConstantsState sharedState] isDevelopmentModeEnabled]);
228+
}
229+
87230
/**
88231
* Tests a simple development start.
89232
*/

Example/Tests/Classes/Utilities/LeanplumHelper.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ static BOOL recordSnapshots = NO;
4343

4444
@interface LeanplumHelper : NSObject
4545

46+
@property (class) NSString *lastErrorMessage;
47+
4648
/// called before starting any test, to swizzle methods
4749
+ (void)setup_method_swizzling;
4850

@@ -70,4 +72,6 @@ static BOOL recordSnapshots = NO;
7072

7173
+ (void)dismissPresentedViewControllers;
7274

75+
+ (void)mockThrowErrorToThrow;
76+
7377
@end

Example/Tests/Classes/Utilities/LeanplumHelper.m

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#import <XCTest/XCTest.h>
2828
#import <OHHTTPStubs/HTTPStubs.h>
2929
#import <OHHTTPStubs/HTTPStubsPathHelpers.h>
30+
#import <OCMock/OCMock.h>
3031
#import "LeanplumHelper.h"
3132
#import "LeanplumRequest+Categories.h"
3233
#import "LPVarCache+Extensions.h"
@@ -38,6 +39,7 @@
3839
#import "LPAPIConfig.h"
3940
#import "LPOperationQueue.h"
4041

42+
// Keys also used in Leanplum-Info.plist file
4143
NSString *APPLICATION_ID = @"app_nLiaLr3lXvCjXhsztS1Gw8j281cPLO6sZetTDxYnaSk";
4244
NSString *DEVELOPMENT_KEY = @"dev_2bbeWLmVJyNrqI8F21Kn9nqyUPRkVCUoLddBkHEyzmk";
4345
NSString *PRODUCTION_KEY = @"prod_XYpURdwPAaxJyYLclXNfACe9Y8hs084dBx2pB8wOnqU";
@@ -48,6 +50,17 @@
4850

4951
@implementation LeanplumHelper
5052

53+
static NSString *_lastErrorMessage = nil;
54+
55+
+ (NSString *)lastErrorMessage {
56+
return _lastErrorMessage;
57+
}
58+
59+
+ (void)setLastErrorMessage:(NSString *)lastErrorMessage {
60+
NSLog(@"Exception: %@", lastErrorMessage);
61+
_lastErrorMessage = lastErrorMessage;
62+
}
63+
5164
static BOOL swizzled = NO;
5265

5366
+ (void)setup_method_swizzling {
@@ -164,4 +177,16 @@ + (void)dismissPresentedViewControllers
164177
[[UIApplication sharedApplication].keyWindow.rootViewController dismissViewControllerAnimated:false completion:nil];
165178
}
166179

180+
+ (void) throwError:(NSString *) err
181+
{
182+
[LeanplumHelper setLastErrorMessage:err];
183+
@throw([NSException exceptionWithName:err reason:nil userInfo:nil]);
184+
}
185+
186+
+ (void) mockThrowErrorToThrow
187+
{
188+
id mockLeanplumClass = OCMClassMock([Leanplum class]);
189+
[OCMStub(ClassMethod([mockLeanplumClass throwError:[OCMArg any]])) andCall:@selector(throwError:) onObject:self];
190+
}
191+
167192
@end

Example/Tests/Leanplum-Info.plist

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>APP_ID</key>
6+
<string>app_nLiaLr3lXvCjXhsztS1Gw8j281cPLO6sZetTDxYnaSk</string>
7+
<key>DEV_KEY</key>
8+
<string>dev_2bbeWLmVJyNrqI8F21Kn9nqyUPRkVCUoLddBkHEyzmk</string>
9+
<key>PROD_KEY</key>
10+
<string>prod_XYpURdwPAaxJyYLclXNfACe9Y8hs084dBx2pB8wOnqU</string>
11+
</dict>
12+
</plist>

Leanplum-SDK/Classes/Internal/Leanplum.m

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,16 @@
5151
#import "LPOperationQueue.h"
5252
#include <sys/sysctl.h>
5353

54+
NSString *const kAppKeysFileName = @"Leanplum-Info";
55+
NSString *const kAppKeysFileType = @"plist";
56+
57+
NSString *const kAppIdKey = @"APP_ID";
58+
NSString *const kDevKey = @"DEV_KEY";
59+
NSString *const kProdKey = @"PROD_KEY";
60+
NSString *const kEnvKey = @"ENV";
61+
NSString *const kEnvDevelopment = @"development";
62+
NSString *const kEnvProduction = @"production";
63+
5464
static NSString *leanplum_deviceId = nil;
5565
static NSString *registrationEmail = nil;
5666
__weak static NSExtensionContext *_extensionContext = nil;
@@ -81,6 +91,24 @@ - (void)leanplum_cancelRequestWithError:(NSError *)error
8191

8292
@implementation Leanplum
8393

94+
+(void)load
95+
{
96+
NSDictionary *appKeysDictionary = [self getDefaultAppKeysPlist];
97+
if (appKeysDictionary == nil) {
98+
return;
99+
}
100+
NSString *env = appKeysDictionary[kEnvKey];
101+
if ([self setAppUsingPlist:appKeysDictionary forEnvironment:env]) {
102+
return;
103+
}
104+
105+
#if DEBUG
106+
[self setAppUsingPlist:appKeysDictionary forEnvironment:kEnvDevelopment];
107+
#else
108+
[self setAppUsingPlist:appKeysDictionary forEnvironment:kEnvProduction];
109+
#endif
110+
}
111+
84112
+ (void)throwError:(NSString *)reason
85113
{
86114
if ([LPConstantsState sharedState].isDevelopmentModeEnabled) {
@@ -236,6 +264,50 @@ + (void)setInAppPurchaseEventName:(NSString *)event
236264
LP_END_TRY
237265
}
238266

267+
+ (NSDictionary *) getDefaultAppKeysPlist
268+
{
269+
NSString *plistFilePath = [[NSBundle mainBundle] pathForResource:kAppKeysFileName ofType:kAppKeysFileType];
270+
NSString *ignoreMessage = @"Ignore if not using Leanplum with plist configuration.";
271+
if (plistFilePath == nil) {
272+
NSLog(@"%@", [NSString stringWithFormat:@"[Leanplum getDefaultAppKeysPlist] Could not locate configuration file: '%@.%@'. %@", kAppKeysFileName, kAppKeysFileType, ignoreMessage]);
273+
return nil;
274+
}
275+
276+
NSDictionary *appKeysDictionary = [NSDictionary dictionaryWithContentsOfFile:plistFilePath];
277+
if (appKeysDictionary == nil) {
278+
NSLog(@"%@", [NSString stringWithFormat:@"[Leanplum getDefaultAppKeysPlist] The configuration file is not a dictionary: '%@.%@'. %@", kAppKeysFileName, kAppKeysFileType, ignoreMessage]);
279+
}
280+
281+
return appKeysDictionary;
282+
}
283+
284+
+ (BOOL)setAppUsingPlist:(NSDictionary *)appKeysDictionary forEnvironment:(NSString *)env {
285+
if ([[env lowercaseString] isEqualToString:kEnvDevelopment]) {
286+
[self setAppId:appKeysDictionary[kAppIdKey] withDevelopmentKey:appKeysDictionary[kDevKey]];
287+
NSLog(@"%@", [NSString stringWithFormat:@"Leanplum configured for '%@' using configuration file: '%@.%@'.", kEnvDevelopment, kAppKeysFileName, kAppKeysFileType]);
288+
return YES;
289+
} else if ([[env lowercaseString] isEqualToString:kEnvProduction]) {
290+
[self setAppId:appKeysDictionary[kAppIdKey] withProductionKey:appKeysDictionary[kProdKey]];
291+
NSLog(@"%@", [NSString stringWithFormat:@"Leanplum configured for '%@' using configuration file: '%@.%@'.", kEnvProduction, kAppKeysFileName, kAppKeysFileType]);
292+
return YES;
293+
}
294+
return NO;
295+
}
296+
297+
+ (void)setAppEnvironment:(NSString *)env
298+
{
299+
if (![[env lowercaseString] isEqualToString:kEnvProduction] && ![[env lowercaseString] isEqualToString:kEnvDevelopment]) {
300+
[self throwError:@"[Leanplum setAppEnvironment:] Incorrect env parameter. Use \"development\" or \"production\"."];
301+
return;
302+
}
303+
if ([LPInternalState sharedState].calledStart) {
304+
[self throwError:@"[Leanplum setAppEnvironment:] Leanplum already started. Call this method before [Leanplum start]."];
305+
return;
306+
}
307+
308+
[self setAppUsingPlist:[Leanplum getDefaultAppKeysPlist] forEnvironment:env];
309+
}
310+
239311
+ (void)setAppId:(NSString *)appId withDevelopmentKey:(NSString *)accessKey
240312
{
241313
if ([LPUtils isNullOrEmpty:appId]) {

Leanplum-SDK/Classes/Internal/LeanplumInternal.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,20 @@ NS_ASSUME_NONNULL_BEGIN
3636
@class LeanplumSocket;
3737
@class LPRegisterDevice;
3838

39+
/**
40+
* Keys for the plist file name
41+
*/
42+
extern NSString *const kAppKeysFileName;
43+
extern NSString *const kAppKeysFileType;
44+
45+
/**
46+
* Keys for the strings in the plist file.
47+
*/
48+
extern NSString *const kAppIdKey;
49+
extern NSString *const kDevKey;
50+
extern NSString *const kProdKey;
51+
extern NSString *const kEnvKey;
52+
3953
@interface Leanplum ()
4054

4155
typedef void (^LeanplumStartIssuedBlock)(void);
@@ -58,6 +72,9 @@ typedef NS_ENUM(NSUInteger, LPLogType) {
5872
+ (void)pause;
5973
+ (void)resume;
6074

75+
+ (BOOL)setAppUsingPlist:(NSDictionary *)appKeysDictionary forEnvironment:(NSString *)env;
76+
+ (NSDictionary *) getDefaultAppKeysPlist;
77+
6178
+ (void)track:(nullable NSString *)event
6279
withValue:(double)value
6380
andArgs:(nullable NSDictionary<NSString *, id> *)args

0 commit comments

Comments
 (0)