Skip to content

Commit

Permalink
Merge pull request #878 from Microsoft/develop
Browse files Browse the repository at this point in the history
Release 1.1.0
  • Loading branch information
jaeklim authored Dec 8, 2017
2 parents 90f43f7 + a9bd527 commit e270aa9
Show file tree
Hide file tree
Showing 107 changed files with 2,326 additions and 681 deletions.
4 changes: 2 additions & 2 deletions AppCenter.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'AppCenter'
s.version = '1.0.1'
s.version = '1.1.0'

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

s.ios.preserve_path = 'AppCenter-SDK-Apple/iOS/README.md'
s.osx.preserve_path = 'AppCenter-SDK-Apple/macOS/README.md'

s.default_subspecs = 'Analytics', 'Crashes'

s.subspec 'Core' do |ss|
Expand Down
16 changes: 15 additions & 1 deletion AppCenter/AppCenter.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,9 @@
04FD126F1E415697007ABFE7 /* MSLogManagerDefaultPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 04FD126E1E415697007ABFE7 /* MSLogManagerDefaultPrivate.h */; };
3592ABA71DC90E3600EF4592 /* MSLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 3592ABA51DC90E3600EF4592 /* MSLogger.h */; };
3592ABA81DC90E3600EF4592 /* MSLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 3592ABA61DC90E3600EF4592 /* MSLogger.m */; };
35C0E3CB1FD6146A004E841E /* MSMockSecondService.m in Sources */ = {isa = PBXBuildFile; fileRef = 35C0E3C91FD6146A004E841E /* MSMockSecondService.m */; };
35C0E3CC1FD6146A004E841E /* MSMockSecondService.m in Sources */ = {isa = PBXBuildFile; fileRef = 35C0E3C91FD6146A004E841E /* MSMockSecondService.m */; };
35C0E3CD1FD6146A004E841E /* MSMockSecondService.m in Sources */ = {isa = PBXBuildFile; fileRef = 35C0E3C91FD6146A004E841E /* MSMockSecondService.m */; };
35D0B7531DDFABFD003EACCD /* MSWrapperLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 35D0B7511DDFABFD003EACCD /* MSWrapperLogger.h */; };
35D0B7541DDFABFD003EACCD /* MSWrapperLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 35D0B7521DDFABFD003EACCD /* MSWrapperLogger.m */; };
380A4DCB1DD6908A00E99219 /* MSUtilityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 380A4DCA1DD6908A00E99219 /* MSUtilityTests.m */; };
Expand All @@ -327,6 +330,7 @@
385AD9221D95898D008B354A /* MSServiceAbstractProtected.h in Headers */ = {isa = PBXBuildFile; fileRef = 385AD9211D95898D008B354A /* MSServiceAbstractProtected.h */; };
385FC0551D37EBD700A1799F /* MSDeviceTrackerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 385FC0541D37EBD700A1799F /* MSDeviceTrackerTests.m */; };
38641B051EB0F40800B2CE73 /* MSAppDelegateForwarderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 38641B041EB0F40800B2CE73 /* MSAppDelegateForwarderTests.m */; };
386A69ED1FD8843D0057B316 /* MSKeychainUtilPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 386A69EC1FD8843D0057B316 /* MSKeychainUtilPrivate.h */; };
386E8D931E25932100EECF0F /* MSHttpTestUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 386E8D911E25932100EECF0F /* MSHttpTestUtil.m */; };
387C75811D6270A300D68CC1 /* MSServiceAbstractInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 387C757F1D6270A300D68CC1 /* MSServiceAbstractInternal.h */; };
387C758F1D64E50800D68CC1 /* MSServiceCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 387C758D1D64DF2500D68CC1 /* MSServiceCommon.h */; };
Expand Down Expand Up @@ -587,6 +591,8 @@
04FD126E1E415697007ABFE7 /* MSLogManagerDefaultPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSLogManagerDefaultPrivate.h; sourceTree = "<group>"; };
3592ABA51DC90E3600EF4592 /* MSLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSLogger.h; sourceTree = "<group>"; };
3592ABA61DC90E3600EF4592 /* MSLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSLogger.m; sourceTree = "<group>"; };
35C0E3C91FD6146A004E841E /* MSMockSecondService.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MSMockSecondService.m; sourceTree = "<group>"; };
35C0E3CA1FD6146A004E841E /* MSMockSecondService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MSMockSecondService.h; sourceTree = "<group>"; };
35D0B7511DDFABFD003EACCD /* MSWrapperLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSWrapperLogger.h; sourceTree = "<group>"; };
35D0B7521DDFABFD003EACCD /* MSWrapperLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSWrapperLogger.m; sourceTree = "<group>"; };
380A4DCA1DD6908A00E99219 /* MSUtilityTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSUtilityTests.m; sourceTree = "<group>"; };
Expand All @@ -608,6 +614,7 @@
385AD9211D95898D008B354A /* MSServiceAbstractProtected.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSServiceAbstractProtected.h; sourceTree = "<group>"; };
385FC0541D37EBD700A1799F /* MSDeviceTrackerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSDeviceTrackerTests.m; sourceTree = "<group>"; };
38641B041EB0F40800B2CE73 /* MSAppDelegateForwarderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSAppDelegateForwarderTests.m; sourceTree = "<group>"; };
386A69EC1FD8843D0057B316 /* MSKeychainUtilPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSKeychainUtilPrivate.h; sourceTree = "<group>"; };
386E8D911E25932100EECF0F /* MSHttpTestUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MSHttpTestUtil.m; sourceTree = "<group>"; };
386E8D921E25932100EECF0F /* MSHttpTestUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MSHttpTestUtil.h; sourceTree = "<group>"; };
387C757F1D6270A300D68CC1 /* MSServiceAbstractInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = MSServiceAbstractInternal.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
Expand Down Expand Up @@ -997,8 +1004,9 @@
B2CD749A1F22BE270070E7DF /* MSUtility+File.m */,
B2CD749B1F22BE270070E7DF /* MSUtility+StringFormatting.h */,
B2CD749C1F22BE270070E7DF /* MSUtility+StringFormatting.m */,
045BC3161E3FD88600B6C960 /* MSKeychainUtil.m */,
045BC3181E3FD8AC00B6C960 /* MSKeychainUtil.h */,
045BC3161E3FD88600B6C960 /* MSKeychainUtil.m */,
386A69EC1FD8843D0057B316 /* MSKeychainUtilPrivate.h */,
);
path = Util;
sourceTree = "<group>";
Expand Down Expand Up @@ -1115,6 +1123,8 @@
D377A30C1E83A05900B2C97A /* MSMockUserDefaults.m */,
805F3F691F209C8A00B489E4 /* MSMockService.h */,
805F3F6A1F209C9D00B489E4 /* MSMockService.m */,
35C0E3CA1FD6146A004E841E /* MSMockSecondService.h */,
35C0E3C91FD6146A004E841E /* MSMockSecondService.m */,
04311FEE1EE083C2007054C5 /* MSTestFrameworks.h */,
);
path = Util;
Expand Down Expand Up @@ -1401,6 +1411,7 @@
B2CD745E1F22BBBB0070E7DF /* MSWrapperSdkInternal.h in Headers */,
04754F431EA980FD002CBA46 /* MSDeviceTrackerPrivate.h in Headers */,
E8AEE9821D5970A400C0FF6C /* MSLogManagerDelegate.h in Headers */,
386A69ED1FD8843D0057B316 /* MSKeychainUtilPrivate.h in Headers */,
3844FF211E8C2716003E9194 /* MSDevice.h in Headers */,
6E04016C1D1C9E1F0051BCFA /* AppCenter.h in Headers */,
E84B8E351D235226006FD231 /* MSHttpSender.h in Headers */,
Expand Down Expand Up @@ -1748,6 +1759,7 @@
0446DF171F3B864600C8E338 /* MSServiceAbstractTests.m in Sources */,
0446DF181F3B864600C8E338 /* MSChannelConfigurationTests.m in Sources */,
0446DF191F3B864600C8E338 /* MSLoggerTests.m in Sources */,
35C0E3CB1FD6146A004E841E /* MSMockSecondService.m in Sources */,
0446DF1B1F3B864600C8E338 /* MSSenderUtilTests.m in Sources */,
0446DF1C1F3B864600C8E338 /* MSMockLog.m in Sources */,
0446DF1D1F3B864600C8E338 /* MSLogManagerDefaultTests.m in Sources */,
Expand All @@ -1772,6 +1784,7 @@
04A140891ECE63C3001CEE94 /* MSLoggerTests.m in Sources */,
046AEAE31ECA562A00CBE511 /* MSKeychainUtilTests.m in Sources */,
04A1408B1ECE63CB001CEE94 /* MSIngestionSenderTests.m in Sources */,
35C0E3CC1FD6146A004E841E /* MSMockSecondService.m in Sources */,
046AEAE41ECA562A00CBE511 /* MSStartServiceLogTests.m in Sources */,
0446DF331F3B870A00C8E338 /* MSLogDBStorageTests.m in Sources */,
046AEAE61ECA562A00CBE511 /* MSChannelConfigurationTests.m in Sources */,
Expand Down Expand Up @@ -1887,6 +1900,7 @@
B2FD53651E567BCF0050F909 /* MSDeviceHistoryInfoTests.m in Sources */,
380A4DCB1DD6908A00E99219 /* MSUtilityTests.m in Sources */,
3849BA7E1EF3489D0072E3E0 /* MSDBStorageTests.m in Sources */,
35C0E3CD1FD6146A004E841E /* MSMockSecondService.m in Sources */,
E829E4231D25C8BA00F19DA1 /* MSIngestionSenderTests.m in Sources */,
805F3F6B1F209C9D00B489E4 /* MSMockService.m in Sources */,
E88EBBFB1D2C8CC7007E7785 /* MSLogContainerTests.m in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion AppCenter/AppCenter/Internals/Channel/MSChannelDefault.m
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ - (void)flushQueue {

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

// Notify delegates.
Expand Down
25 changes: 24 additions & 1 deletion AppCenter/AppCenter/Internals/Device/MSDeviceTracker.m
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,30 @@ - (NSString *)osBuild {
}

- (NSString *)locale:(NSLocale *)currentLocale {
return [currentLocale objectForKey:NSLocaleIdentifier];

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

- (NSNumber *)timeZoneOffset:(NSTimeZone *)timeZone {
Expand Down
6 changes: 6 additions & 0 deletions AppCenter/AppCenter/Internals/MSAppCenterInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
static NSString *const kMSInstallIdKey = @"MSInstallId";
static NSString *const kMSAppCenterIsEnabledKey = @"MSAppCenterIsEnabled";

// Name of the environment variable to check for which services should be disabled.
static NSString *const kMSDisableVariable = @"APP_CENTER_DISABLE";

// Value that would cause all services to be disabled.
static NSString *const kMSDisableAll = @"All";

@interface MSAppCenter ()

@property(nonatomic) id<MSLogManager> logManager;
Expand Down
9 changes: 8 additions & 1 deletion AppCenter/AppCenter/Internals/Sender/MSHttpSender.m
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ - (void)sendCallAsync:(MSSenderCall *)call {
}
}
}
MSLogDebug([MSAppCenter logTag], @"HTTP response received with status code=%lu and payload=%@",
MSLogVerbose([MSAppCenter logTag], @"HTTP response received with status code=%lu and payload=%@",
(unsigned long)statusCode, payload);

// Call handles the completion.
Expand Down Expand Up @@ -351,6 +351,13 @@ - (NSURLSession *)session {
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfiguration.timeoutIntervalForRequest = kRequestTimeout;
_session = [NSURLSession sessionWithConfiguration:sessionConfiguration];

/*
* Limit callbacks execution concurrency to avoid race condition. This queue is used only for
* delegate method calls and completion handlers.
* See https://developer.apple.com/documentation/foundation/nsurlsession/1411571-delegatequeue
*/
_session.delegateQueue.maxConcurrentOperationCount = 1;
}
return _session;
}
Expand Down
8 changes: 4 additions & 4 deletions AppCenter/AppCenter/Internals/Sender/MSSenderCall.m
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ - (uint32_t)delayForRetryCount:(NSUInteger)retryCount {
return delay;
}

- (void)startTimer {
- (void)startRetryTimerWithStatusCode:(NSUInteger)statusCode {
[self resetTimer];

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

// Retry.
else if ([MSSenderUtil isRecoverableError:statusCode] && ![self hasReachedMaxRetries]) {
[self startTimer];
[self startRetryTimerWithStatusCode:statusCode];
}

// Callback to Channel.
Expand Down
2 changes: 1 addition & 1 deletion AppCenter/AppCenter/Internals/Util/MSKeychainUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ NS_ASSUME_NONNULL_BEGIN
*
* @return A string data that was deleted.
*/
+ (NSString *)deleteStringForKey:(NSString *)key;
+ (NSString *_Nullable)deleteStringForKey:(NSString *)key;

/**
* Get a string from Keychain with the given key.
Expand Down
41 changes: 24 additions & 17 deletions AppCenter/AppCenter/Internals/Util/MSKeychainUtil.m
Original file line number Diff line number Diff line change
@@ -1,32 +1,34 @@
#import <Foundation/Foundation.h>

#import "MSKeychainUtil.h"
#import "MSKeychainUtilPrivate.h"
#import "MSUtility.h"

@implementation MSKeychainUtil

static NSString *AppCenterKeychainServiceName(void) {
static NSString *AppCenterKeychainServiceName(NSString *suffix) {
static NSString *serviceName = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
serviceName = [NSString stringWithFormat:@"%@.AppCenter", [MS_APP_MAIN_BUNDLE bundleIdentifier]];
serviceName = [NSString stringWithFormat:@"%@.%@", [MS_APP_MAIN_BUNDLE bundleIdentifier], suffix];
});
return serviceName;
}

+ (BOOL)storeString:(NSString *)string forKey:(NSString *)key {
NSMutableDictionary *item = [MSKeychainUtil generateItem:key];
+ (BOOL)storeString:(NSString *)string forKey:(NSString *)key withServiceName:(NSString *)serviceName {
NSMutableDictionary *item = [MSKeychainUtil generateItem:key withServiceName:serviceName];
item[(__bridge id)kSecValueData] = [string dataUsingEncoding:NSUTF8StringEncoding];

OSStatus status = SecItemAdd((__bridge CFDictionaryRef)item, nil);
return status == noErr;
}

+ (NSString *)deleteStringForKey:(NSString *)key {
+ (BOOL)storeString:(NSString *)string forKey:(NSString *)key {
return [MSKeychainUtil storeString:string forKey:key withServiceName:AppCenterKeychainServiceName(kMSServiceSuffix)];
}

+ (NSString *)deleteStringForKey:(NSString *)key withServiceName:(NSString *)serviceName {
NSString *string = [MSKeychainUtil stringForKey:key];
if (string) {
NSMutableDictionary *item = [MSKeychainUtil generateItem:key];

NSMutableDictionary *item = [MSKeychainUtil generateItem:key withServiceName:serviceName];
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)item);
if (status == noErr) {
return string;
Expand All @@ -35,33 +37,38 @@ + (NSString *)deleteStringForKey:(NSString *)key {
return nil;
}

+ (NSString *)stringForKey:(NSString *)key {
NSMutableDictionary *item = [MSKeychainUtil generateItem:key];
+ (NSString *)deleteStringForKey:(NSString *)key {
return [MSKeychainUtil deleteStringForKey:key withServiceName:AppCenterKeychainServiceName(kMSServiceSuffix)];
}

+ (NSString *)stringForKey:(NSString *)key withServiceName:(NSString *)serviceName {
NSMutableDictionary *item = [MSKeychainUtil generateItem:key withServiceName:serviceName];
item[(__bridge id)kSecReturnData] = (__bridge id)kCFBooleanTrue;
item[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;

CFTypeRef data = nil;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)item, &data);

if (status == noErr) {
return [[NSString alloc] initWithData:(__bridge_transfer NSData *)data encoding:NSUTF8StringEncoding];
}
return nil;
}

+ (NSString *)stringForKey:(NSString *)key {
return [MSKeychainUtil stringForKey:key withServiceName:AppCenterKeychainServiceName(kMSServiceSuffix)];
}

+ (BOOL)clear {
NSMutableDictionary *item = [NSMutableDictionary new];
item[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
item[(__bridge id)kSecAttrService] = AppCenterKeychainServiceName();

item[(__bridge id)kSecAttrService] = AppCenterKeychainServiceName(kMSServiceSuffix);
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)item);
return status == noErr;
}

+ (NSMutableDictionary *)generateItem:(NSString *)key {
+ (NSMutableDictionary *)generateItem:(NSString *)key withServiceName:(NSString *)serviceName {
NSMutableDictionary *item = [NSMutableDictionary new];
item[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
item[(__bridge id)kSecAttrService] = AppCenterKeychainServiceName();
item[(__bridge id)kSecAttrService] = serviceName;
item[(__bridge id)kSecAttrAccount] = key;
return item;
}
Expand Down
50 changes: 50 additions & 0 deletions AppCenter/AppCenter/Internals/Util/MSKeychainUtilPrivate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@


#import "MSKeychainUtil.h"

NS_ASSUME_NONNULL_BEGIN

/**
* Keychain service name suffix.
*/
static NSString *const kMSServiceSuffix = @"AppCenter";

/**
* Utility class for Keychain.
*/
@interface MSKeychainUtil ()

/**
* Store a string to Keychain with the given key.
*
* @param string A string data to be placed in Keychain.
* @param key A unique key for the data.
* @param serviceName Keychain service name.
*
* @return YES if stored successfully, NO otherwise.
*/
+ (BOOL)storeString:(NSString *)string forKey:(NSString *)key withServiceName:(NSString *)serviceName;

/**
* Delete a string from Keychain with the given key.
*
* @param key A unique key for the data.
* @param serviceName Keychain service name.
*
* @return A string data that was deleted.
*/
+ (NSString *_Nullable)deleteStringForKey:(NSString *)key withServiceName:(NSString *)serviceName;

/**
* Get a string from Keychain with the given key.
*
* @param key A unique key for the data.
* @param serviceName Keychain service name.
*
* @return A string data if exists.
*/
+ (NSString *_Nullable)stringForKey:(NSString *)key withServiceName:(NSString *)serviceName;

@end

NS_ASSUME_NONNULL_END
Loading

0 comments on commit e270aa9

Please sign in to comment.