Skip to content

Commit e270aa9

Browse files
authored
Merge pull request #878 from Microsoft/develop
Release 1.1.0
2 parents 90f43f7 + a9bd527 commit e270aa9

File tree

107 files changed

+2326
-681
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+2326
-681
lines changed

AppCenter.podspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = 'AppCenter'
3-
s.version = '1.0.1'
3+
s.version = '1.1.0'
44

55
s.summary = 'Visual Studio App Center is your continuous integration, delivery and learning solution for iOS and macOS apps.'
66
s.description = <<-DESC
@@ -35,7 +35,7 @@ Pod::Spec.new do |s|
3535

3636
s.ios.preserve_path = 'AppCenter-SDK-Apple/iOS/README.md'
3737
s.osx.preserve_path = 'AppCenter-SDK-Apple/macOS/README.md'
38-
38+
3939
s.default_subspecs = 'Analytics', 'Crashes'
4040

4141
s.subspec 'Core' do |ss|

AppCenter/AppCenter.xcodeproj/project.pbxproj

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,9 @@
306306
04FD126F1E415697007ABFE7 /* MSLogManagerDefaultPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 04FD126E1E415697007ABFE7 /* MSLogManagerDefaultPrivate.h */; };
307307
3592ABA71DC90E3600EF4592 /* MSLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 3592ABA51DC90E3600EF4592 /* MSLogger.h */; };
308308
3592ABA81DC90E3600EF4592 /* MSLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 3592ABA61DC90E3600EF4592 /* MSLogger.m */; };
309+
35C0E3CB1FD6146A004E841E /* MSMockSecondService.m in Sources */ = {isa = PBXBuildFile; fileRef = 35C0E3C91FD6146A004E841E /* MSMockSecondService.m */; };
310+
35C0E3CC1FD6146A004E841E /* MSMockSecondService.m in Sources */ = {isa = PBXBuildFile; fileRef = 35C0E3C91FD6146A004E841E /* MSMockSecondService.m */; };
311+
35C0E3CD1FD6146A004E841E /* MSMockSecondService.m in Sources */ = {isa = PBXBuildFile; fileRef = 35C0E3C91FD6146A004E841E /* MSMockSecondService.m */; };
309312
35D0B7531DDFABFD003EACCD /* MSWrapperLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 35D0B7511DDFABFD003EACCD /* MSWrapperLogger.h */; };
310313
35D0B7541DDFABFD003EACCD /* MSWrapperLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 35D0B7521DDFABFD003EACCD /* MSWrapperLogger.m */; };
311314
380A4DCB1DD6908A00E99219 /* MSUtilityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 380A4DCA1DD6908A00E99219 /* MSUtilityTests.m */; };
@@ -327,6 +330,7 @@
327330
385AD9221D95898D008B354A /* MSServiceAbstractProtected.h in Headers */ = {isa = PBXBuildFile; fileRef = 385AD9211D95898D008B354A /* MSServiceAbstractProtected.h */; };
328331
385FC0551D37EBD700A1799F /* MSDeviceTrackerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 385FC0541D37EBD700A1799F /* MSDeviceTrackerTests.m */; };
329332
38641B051EB0F40800B2CE73 /* MSAppDelegateForwarderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 38641B041EB0F40800B2CE73 /* MSAppDelegateForwarderTests.m */; };
333+
386A69ED1FD8843D0057B316 /* MSKeychainUtilPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 386A69EC1FD8843D0057B316 /* MSKeychainUtilPrivate.h */; };
330334
386E8D931E25932100EECF0F /* MSHttpTestUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 386E8D911E25932100EECF0F /* MSHttpTestUtil.m */; };
331335
387C75811D6270A300D68CC1 /* MSServiceAbstractInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 387C757F1D6270A300D68CC1 /* MSServiceAbstractInternal.h */; };
332336
387C758F1D64E50800D68CC1 /* MSServiceCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 387C758D1D64DF2500D68CC1 /* MSServiceCommon.h */; };
@@ -587,6 +591,8 @@
587591
04FD126E1E415697007ABFE7 /* MSLogManagerDefaultPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSLogManagerDefaultPrivate.h; sourceTree = "<group>"; };
588592
3592ABA51DC90E3600EF4592 /* MSLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSLogger.h; sourceTree = "<group>"; };
589593
3592ABA61DC90E3600EF4592 /* MSLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSLogger.m; sourceTree = "<group>"; };
594+
35C0E3C91FD6146A004E841E /* MSMockSecondService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSMockSecondService.m; sourceTree = "<group>"; };
595+
35C0E3CA1FD6146A004E841E /* MSMockSecondService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSMockSecondService.h; sourceTree = "<group>"; };
590596
35D0B7511DDFABFD003EACCD /* MSWrapperLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSWrapperLogger.h; sourceTree = "<group>"; };
591597
35D0B7521DDFABFD003EACCD /* MSWrapperLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSWrapperLogger.m; sourceTree = "<group>"; };
592598
380A4DCA1DD6908A00E99219 /* MSUtilityTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSUtilityTests.m; sourceTree = "<group>"; };
@@ -608,6 +614,7 @@
608614
385AD9211D95898D008B354A /* MSServiceAbstractProtected.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSServiceAbstractProtected.h; sourceTree = "<group>"; };
609615
385FC0541D37EBD700A1799F /* MSDeviceTrackerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSDeviceTrackerTests.m; sourceTree = "<group>"; };
610616
38641B041EB0F40800B2CE73 /* MSAppDelegateForwarderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSAppDelegateForwarderTests.m; sourceTree = "<group>"; };
617+
386A69EC1FD8843D0057B316 /* MSKeychainUtilPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSKeychainUtilPrivate.h; sourceTree = "<group>"; };
611618
386E8D911E25932100EECF0F /* MSHttpTestUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSHttpTestUtil.m; sourceTree = "<group>"; };
612619
386E8D921E25932100EECF0F /* MSHttpTestUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSHttpTestUtil.h; sourceTree = "<group>"; };
613620
387C757F1D6270A300D68CC1 /* MSServiceAbstractInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = MSServiceAbstractInternal.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
@@ -997,8 +1004,9 @@
9971004
B2CD749A1F22BE270070E7DF /* MSUtility+File.m */,
9981005
B2CD749B1F22BE270070E7DF /* MSUtility+StringFormatting.h */,
9991006
B2CD749C1F22BE270070E7DF /* MSUtility+StringFormatting.m */,
1000-
045BC3161E3FD88600B6C960 /* MSKeychainUtil.m */,
10011007
045BC3181E3FD8AC00B6C960 /* MSKeychainUtil.h */,
1008+
045BC3161E3FD88600B6C960 /* MSKeychainUtil.m */,
1009+
386A69EC1FD8843D0057B316 /* MSKeychainUtilPrivate.h */,
10021010
);
10031011
path = Util;
10041012
sourceTree = "<group>";
@@ -1115,6 +1123,8 @@
11151123
D377A30C1E83A05900B2C97A /* MSMockUserDefaults.m */,
11161124
805F3F691F209C8A00B489E4 /* MSMockService.h */,
11171125
805F3F6A1F209C9D00B489E4 /* MSMockService.m */,
1126+
35C0E3CA1FD6146A004E841E /* MSMockSecondService.h */,
1127+
35C0E3C91FD6146A004E841E /* MSMockSecondService.m */,
11181128
04311FEE1EE083C2007054C5 /* MSTestFrameworks.h */,
11191129
);
11201130
path = Util;
@@ -1401,6 +1411,7 @@
14011411
B2CD745E1F22BBBB0070E7DF /* MSWrapperSdkInternal.h in Headers */,
14021412
04754F431EA980FD002CBA46 /* MSDeviceTrackerPrivate.h in Headers */,
14031413
E8AEE9821D5970A400C0FF6C /* MSLogManagerDelegate.h in Headers */,
1414+
386A69ED1FD8843D0057B316 /* MSKeychainUtilPrivate.h in Headers */,
14041415
3844FF211E8C2716003E9194 /* MSDevice.h in Headers */,
14051416
6E04016C1D1C9E1F0051BCFA /* AppCenter.h in Headers */,
14061417
E84B8E351D235226006FD231 /* MSHttpSender.h in Headers */,
@@ -1748,6 +1759,7 @@
17481759
0446DF171F3B864600C8E338 /* MSServiceAbstractTests.m in Sources */,
17491760
0446DF181F3B864600C8E338 /* MSChannelConfigurationTests.m in Sources */,
17501761
0446DF191F3B864600C8E338 /* MSLoggerTests.m in Sources */,
1762+
35C0E3CB1FD6146A004E841E /* MSMockSecondService.m in Sources */,
17511763
0446DF1B1F3B864600C8E338 /* MSSenderUtilTests.m in Sources */,
17521764
0446DF1C1F3B864600C8E338 /* MSMockLog.m in Sources */,
17531765
0446DF1D1F3B864600C8E338 /* MSLogManagerDefaultTests.m in Sources */,
@@ -1772,6 +1784,7 @@
17721784
04A140891ECE63C3001CEE94 /* MSLoggerTests.m in Sources */,
17731785
046AEAE31ECA562A00CBE511 /* MSKeychainUtilTests.m in Sources */,
17741786
04A1408B1ECE63CB001CEE94 /* MSIngestionSenderTests.m in Sources */,
1787+
35C0E3CC1FD6146A004E841E /* MSMockSecondService.m in Sources */,
17751788
046AEAE41ECA562A00CBE511 /* MSStartServiceLogTests.m in Sources */,
17761789
0446DF331F3B870A00C8E338 /* MSLogDBStorageTests.m in Sources */,
17771790
046AEAE61ECA562A00CBE511 /* MSChannelConfigurationTests.m in Sources */,
@@ -1887,6 +1900,7 @@
18871900
B2FD53651E567BCF0050F909 /* MSDeviceHistoryInfoTests.m in Sources */,
18881901
380A4DCB1DD6908A00E99219 /* MSUtilityTests.m in Sources */,
18891902
3849BA7E1EF3489D0072E3E0 /* MSDBStorageTests.m in Sources */,
1903+
35C0E3CD1FD6146A004E841E /* MSMockSecondService.m in Sources */,
18901904
E829E4231D25C8BA00F19DA1 /* MSIngestionSenderTests.m in Sources */,
18911905
805F3F6B1F209C9D00B489E4 /* MSMockService.m in Sources */,
18921906
E88EBBFB1D2C8CC7007E7785 /* MSLogContainerTests.m in Sources */,

AppCenter/AppCenter/Internals/Channel/MSChannelDefault.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ - (void)flushQueue {
194194

195195
// Failure.
196196
else {
197-
MSLogDebug([MSAppCenter logTag], @"Log(s) sent with failure, batch Id:%@, status code:%lu",
197+
MSLogError([MSAppCenter logTag], @"Log(s) sent with failure, batch Id:%@, status code:%lu",
198198
senderBatchId, (unsigned long)statusCode);
199199

200200
// Notify delegates.

AppCenter/AppCenter/Internals/Device/MSDeviceTracker.m

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,30 @@ - (NSString *)osBuild {
298298
}
299299

300300
- (NSString *)locale:(NSLocale *)currentLocale {
301-
return [currentLocale objectForKey:NSLocaleIdentifier];
301+
302+
/*
303+
* [currentLocale objectForKey:NSLocaleIdentifier] will return an alternate language if a language set in system is
304+
* not supported by applications. If system language is set to en_US but an application doesn't support en_US, for
305+
* example, the OS will return the next application supported language in Preferred Language Order list unless there
306+
* is only one language in the list. The method will return the first language in the list to prevent from the above
307+
* scenario.
308+
*
309+
* In addition to that;
310+
* 1. preferred language returns "-" instead of "_" as a delimiter of language code and country code, the method
311+
* will concatenate language code and country code with "_" and return it.
312+
* 2. some languages can be set without country code so region code can be returned in this case.
313+
* 3. some langugaes have script code which differentiate languages. E.g. zh-Hans and zh-Hant. This is a possible
314+
* scenario in Apple platforms that a locale can be zh_CN for Traditional Chinese. The method will return zh-Hant_CN
315+
* in this case to make sure system language is Traditional Chinese even though region is set to China.
316+
*/
317+
NSLocale *preferredLanguage = [[NSLocale alloc] initWithLocaleIdentifier:[NSLocale preferredLanguages][0]];
318+
NSString *languageCode = [preferredLanguage objectForKey:NSLocaleLanguageCode];
319+
NSString *scriptCode = [preferredLanguage objectForKey:NSLocaleScriptCode];
320+
NSString *countryCode = [preferredLanguage objectForKey:NSLocaleCountryCode];
321+
NSString *locale = [NSString stringWithFormat:@"%@%@_%@", languageCode,
322+
(scriptCode ? [NSString stringWithFormat:@"-%@", scriptCode] : @""),
323+
countryCode ?: [currentLocale objectForKey:NSLocaleCountryCode]];
324+
return locale;
302325
}
303326

304327
- (NSNumber *)timeZoneOffset:(NSTimeZone *)timeZone {

AppCenter/AppCenter/Internals/MSAppCenterInternal.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
static NSString *const kMSInstallIdKey = @"MSInstallId";
1010
static NSString *const kMSAppCenterIsEnabledKey = @"MSAppCenterIsEnabled";
1111

12+
// Name of the environment variable to check for which services should be disabled.
13+
static NSString *const kMSDisableVariable = @"APP_CENTER_DISABLE";
14+
15+
// Value that would cause all services to be disabled.
16+
static NSString *const kMSDisableAll = @"All";
17+
1218
@interface MSAppCenter ()
1319

1420
@property(nonatomic) id<MSLogManager> logManager;

AppCenter/AppCenter/Internals/Sender/MSHttpSender.m

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ - (void)sendCallAsync:(MSSenderCall *)call {
237237
}
238238
}
239239
}
240-
MSLogDebug([MSAppCenter logTag], @"HTTP response received with status code=%lu and payload=%@",
240+
MSLogVerbose([MSAppCenter logTag], @"HTTP response received with status code=%lu and payload=%@",
241241
(unsigned long)statusCode, payload);
242242

243243
// Call handles the completion.
@@ -351,6 +351,13 @@ - (NSURLSession *)session {
351351
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
352352
sessionConfiguration.timeoutIntervalForRequest = kRequestTimeout;
353353
_session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
354+
355+
/*
356+
* Limit callbacks execution concurrency to avoid race condition. This queue is used only for
357+
* delegate method calls and completion handlers.
358+
* See https://developer.apple.com/documentation/foundation/nsurlsession/1411571-delegatequeue
359+
*/
360+
_session.delegateQueue.maxConcurrentOperationCount = 1;
354361
}
355362
return _session;
356363
}

AppCenter/AppCenter/Internals/Sender/MSSenderCall.m

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@ - (uint32_t)delayForRetryCount:(NSUInteger)retryCount {
3333
return delay;
3434
}
3535

36-
- (void)startTimer {
36+
- (void)startRetryTimerWithStatusCode:(NSUInteger)statusCode {
3737
[self resetTimer];
3838

3939
// Create queue.
4040
self.timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, DISPATCH_TARGET_QUEUE_DEFAULT);
4141
int64_t delta = NSEC_PER_SEC * [self delayForRetryCount:self.retryCount];
42-
MSLogDebug([MSAppCenter logTag], @"Call attempt #%lu failed, it will be retried in %.f ms.",
43-
(unsigned long)self.retryCount, round(delta / 1000000));
42+
MSLogWarning([MSAppCenter logTag], @"Call attempt #%lu failed with status code: %lu, it will be retried in %.f ms.",
43+
(unsigned long)self.retryCount, (unsigned long)statusCode, round(delta / 1000000));
4444
self.retryCount++;
4545
dispatch_source_set_timer(self.timerSource, dispatch_walltime(NULL, delta), 1ull * NSEC_PER_SEC, 1ull * NSEC_PER_SEC);
4646
__weak typeof(self) weakSelf = self;
@@ -84,7 +84,7 @@ - (void)sender:(id<MSSender>)sender
8484

8585
// Retry.
8686
else if ([MSSenderUtil isRecoverableError:statusCode] && ![self hasReachedMaxRetries]) {
87-
[self startTimer];
87+
[self startRetryTimerWithStatusCode:statusCode];
8888
}
8989

9090
// Callback to Channel.

AppCenter/AppCenter/Internals/Util/MSKeychainUtil.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
2424
*
2525
* @return A string data that was deleted.
2626
*/
27-
+ (NSString *)deleteStringForKey:(NSString *)key;
27+
+ (NSString *_Nullable)deleteStringForKey:(NSString *)key;
2828

2929
/**
3030
* Get a string from Keychain with the given key.

AppCenter/AppCenter/Internals/Util/MSKeychainUtil.m

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,34 @@
11
#import <Foundation/Foundation.h>
22

3-
#import "MSKeychainUtil.h"
3+
#import "MSKeychainUtilPrivate.h"
44
#import "MSUtility.h"
55

66
@implementation MSKeychainUtil
77

8-
static NSString *AppCenterKeychainServiceName(void) {
8+
static NSString *AppCenterKeychainServiceName(NSString *suffix) {
99
static NSString *serviceName = nil;
1010
static dispatch_once_t onceToken;
1111
dispatch_once(&onceToken, ^{
12-
serviceName = [NSString stringWithFormat:@"%@.AppCenter", [MS_APP_MAIN_BUNDLE bundleIdentifier]];
12+
serviceName = [NSString stringWithFormat:@"%@.%@", [MS_APP_MAIN_BUNDLE bundleIdentifier], suffix];
1313
});
1414
return serviceName;
1515
}
1616

17-
+ (BOOL)storeString:(NSString *)string forKey:(NSString *)key {
18-
NSMutableDictionary *item = [MSKeychainUtil generateItem:key];
17+
+ (BOOL)storeString:(NSString *)string forKey:(NSString *)key withServiceName:(NSString *)serviceName {
18+
NSMutableDictionary *item = [MSKeychainUtil generateItem:key withServiceName:serviceName];
1919
item[(__bridge id)kSecValueData] = [string dataUsingEncoding:NSUTF8StringEncoding];
20-
2120
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)item, nil);
2221
return status == noErr;
2322
}
2423

25-
+ (NSString *)deleteStringForKey:(NSString *)key {
24+
+ (BOOL)storeString:(NSString *)string forKey:(NSString *)key {
25+
return [MSKeychainUtil storeString:string forKey:key withServiceName:AppCenterKeychainServiceName(kMSServiceSuffix)];
26+
}
27+
28+
+ (NSString *)deleteStringForKey:(NSString *)key withServiceName:(NSString *)serviceName {
2629
NSString *string = [MSKeychainUtil stringForKey:key];
2730
if (string) {
28-
NSMutableDictionary *item = [MSKeychainUtil generateItem:key];
29-
31+
NSMutableDictionary *item = [MSKeychainUtil generateItem:key withServiceName:serviceName];
3032
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)item);
3133
if (status == noErr) {
3234
return string;
@@ -35,33 +37,38 @@ + (NSString *)deleteStringForKey:(NSString *)key {
3537
return nil;
3638
}
3739

38-
+ (NSString *)stringForKey:(NSString *)key {
39-
NSMutableDictionary *item = [MSKeychainUtil generateItem:key];
40+
+ (NSString *)deleteStringForKey:(NSString *)key {
41+
return [MSKeychainUtil deleteStringForKey:key withServiceName:AppCenterKeychainServiceName(kMSServiceSuffix)];
42+
}
43+
44+
+ (NSString *)stringForKey:(NSString *)key withServiceName:(NSString *)serviceName {
45+
NSMutableDictionary *item = [MSKeychainUtil generateItem:key withServiceName:serviceName];
4046
item[(__bridge id)kSecReturnData] = (__bridge id)kCFBooleanTrue;
4147
item[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
42-
4348
CFTypeRef data = nil;
4449
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)item, &data);
45-
4650
if (status == noErr) {
4751
return [[NSString alloc] initWithData:(__bridge_transfer NSData *)data encoding:NSUTF8StringEncoding];
4852
}
4953
return nil;
5054
}
5155

56+
+ (NSString *)stringForKey:(NSString *)key {
57+
return [MSKeychainUtil stringForKey:key withServiceName:AppCenterKeychainServiceName(kMSServiceSuffix)];
58+
}
59+
5260
+ (BOOL)clear {
5361
NSMutableDictionary *item = [NSMutableDictionary new];
5462
item[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
55-
item[(__bridge id)kSecAttrService] = AppCenterKeychainServiceName();
56-
63+
item[(__bridge id)kSecAttrService] = AppCenterKeychainServiceName(kMSServiceSuffix);
5764
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)item);
5865
return status == noErr;
5966
}
6067

61-
+ (NSMutableDictionary *)generateItem:(NSString *)key {
68+
+ (NSMutableDictionary *)generateItem:(NSString *)key withServiceName:(NSString *)serviceName {
6269
NSMutableDictionary *item = [NSMutableDictionary new];
6370
item[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
64-
item[(__bridge id)kSecAttrService] = AppCenterKeychainServiceName();
71+
item[(__bridge id)kSecAttrService] = serviceName;
6572
item[(__bridge id)kSecAttrAccount] = key;
6673
return item;
6774
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
2+
3+
#import "MSKeychainUtil.h"
4+
5+
NS_ASSUME_NONNULL_BEGIN
6+
7+
/**
8+
* Keychain service name suffix.
9+
*/
10+
static NSString *const kMSServiceSuffix = @"AppCenter";
11+
12+
/**
13+
* Utility class for Keychain.
14+
*/
15+
@interface MSKeychainUtil ()
16+
17+
/**
18+
* Store a string to Keychain with the given key.
19+
*
20+
* @param string A string data to be placed in Keychain.
21+
* @param key A unique key for the data.
22+
* @param serviceName Keychain service name.
23+
*
24+
* @return YES if stored successfully, NO otherwise.
25+
*/
26+
+ (BOOL)storeString:(NSString *)string forKey:(NSString *)key withServiceName:(NSString *)serviceName;
27+
28+
/**
29+
* Delete a string from Keychain with the given key.
30+
*
31+
* @param key A unique key for the data.
32+
* @param serviceName Keychain service name.
33+
*
34+
* @return A string data that was deleted.
35+
*/
36+
+ (NSString *_Nullable)deleteStringForKey:(NSString *)key withServiceName:(NSString *)serviceName;
37+
38+
/**
39+
* Get a string from Keychain with the given key.
40+
*
41+
* @param key A unique key for the data.
42+
* @param serviceName Keychain service name.
43+
*
44+
* @return A string data if exists.
45+
*/
46+
+ (NSString *_Nullable)stringForKey:(NSString *)key withServiceName:(NSString *)serviceName;
47+
48+
@end
49+
50+
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)