diff --git a/iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj b/iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj index 268387d24..cabab70a0 100644 --- a/iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj +++ b/iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj @@ -91,6 +91,8 @@ 3C6299A92BEEA46C00649187 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 3C6299A82BEEA46C00649187 /* PrivacyInfo.xcprivacy */; }; 3C6299AB2BEEA4C000649187 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 3C6299AA2BEEA4C000649187 /* PrivacyInfo.xcprivacy */; }; 3C67F77A2BEB2B710085A0F0 /* SwitchUserIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C67F7792BEB2B710085A0F0 /* SwitchUserIntegrationTests.swift */; }; + 3C70FA672D0B68A100031066 /* OneSignalClientError.h in Headers */ = {isa = PBXBuildFile; fileRef = 3C70FA652D0B68A100031066 /* OneSignalClientError.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3C70FA682D0B68A100031066 /* OneSignalClientError.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C70FA662D0B68A100031066 /* OneSignalClientError.m */; }; 3C789DBD293C2206004CF83D /* OSFocusInfluenceParam.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A600B432453790700514A53 /* OSFocusInfluenceParam.m */; }; 3C789DBE293D8EAD004CF83D /* OSFocusInfluenceParam.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A600B41245378ED00514A53 /* OSFocusInfluenceParam.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3C7A39C12B7BED900082665E /* OneSignalCoreMocks.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CC0639A2B6D7A8C002BB07F /* OneSignalCoreMocks.framework */; }; @@ -1263,6 +1265,8 @@ 3C6299A82BEEA46C00649187 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 3C6299AA2BEEA4C000649187 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 3C67F7792BEB2B710085A0F0 /* SwitchUserIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwitchUserIntegrationTests.swift; sourceTree = ""; }; + 3C70FA652D0B68A100031066 /* OneSignalClientError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OneSignalClientError.h; sourceTree = ""; }; + 3C70FA662D0B68A100031066 /* OneSignalClientError.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OneSignalClientError.m; sourceTree = ""; }; 3C7A39D42B7C18EE0082665E /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 3C8544B62C5AEFF600F542A9 /* OneSignalOSCoreMocks.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OneSignalOSCoreMocks.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3C8544B82C5AEFF700F542A9 /* OneSignalOSCoreMocks.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OneSignalOSCoreMocks.h; sourceTree = ""; }; @@ -2646,6 +2650,8 @@ DE7D1871270375FF002D3A5D /* OSReattemptRequest.m */, DE7D186C2703751B002D3A5D /* OSRequests.h */, DE7D186D2703751B002D3A5D /* OSRequests.m */, + 3C70FA652D0B68A100031066 /* OneSignalClientError.h */, + 3C70FA662D0B68A100031066 /* OneSignalClientError.m */, DE7D1860270374EE002D3A5D /* OneSignalClient.h */, DE7D185C270374EE002D3A5D /* OneSignalClient.m */, DE7D185F270374EE002D3A5D /* OneSignalRequest.h */, @@ -3119,6 +3125,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 3C70FA672D0B68A100031066 /* OneSignalClientError.h in Headers */, DE7D1869270374EE002D3A5D /* OneSignalClient.h in Headers */, DE51DDE6294262AB0073D5C4 /* OSRemoteParamController.h in Headers */, DEF78496291479C100A1F3A5 /* SwizzlingForwarder.h in Headers */, @@ -4413,6 +4420,7 @@ files = ( DEBAAEB32A436CE800BF2C1C /* OSStubInAppMessages.m in Sources */, DEBA2A262C20E9AA00E234DB /* OSBundleUtils.m in Sources */, + 3C70FA682D0B68A100031066 /* OneSignalClientError.m in Sources */, 3C47A975292642B100312125 /* OneSignalConfigManager.m in Sources */, DE7D1874270375FF002D3A5D /* OSReattemptRequest.m in Sources */, DE7D183427027A73002D3A5D /* OneSignalLog.m in Sources */, diff --git a/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OSReattemptRequest.h b/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OSReattemptRequest.h index cb0aa1ead..de97bf2bf 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OSReattemptRequest.h +++ b/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OSReattemptRequest.h @@ -27,13 +27,14 @@ #import #import "OneSignalRequest.h" +#import "OneSignalClientError.h" @interface OSReattemptRequest : NSObject @property (strong, nonatomic) OneSignalRequest *request; @property (nonatomic) OSResultSuccessBlock successBlock; -@property (nonatomic) OSFailureBlock failureBlock; +@property (nonatomic) OSClientFailureBlock failureBlock; -+(instancetype)withRequest:(OneSignalRequest *)request successBlock:(OSResultSuccessBlock)success failureBlock:(OSFailureBlock)failure; ++(instancetype)withRequest:(OneSignalRequest *)request successBlock:(OSResultSuccessBlock)success failureBlock:(OSClientFailureBlock)failure; @end diff --git a/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OSReattemptRequest.m b/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OSReattemptRequest.m index 061cf45c9..8bca15d1b 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OSReattemptRequest.m +++ b/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OSReattemptRequest.m @@ -29,7 +29,7 @@ @implementation OSReattemptRequest -+(instancetype)withRequest:(OneSignalRequest *)request successBlock:(OSResultSuccessBlock)success failureBlock:(OSFailureBlock)failure { ++(instancetype)withRequest:(OneSignalRequest *)request successBlock:(OSResultSuccessBlock)success failureBlock:(OSClientFailureBlock)failure { OSReattemptRequest *reattempt = [OSReattemptRequest new]; reattempt.request = request; diff --git a/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OneSignalClient.h b/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OneSignalClient.h index 7982f5143..7b09c51d4 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OneSignalClient.h +++ b/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OneSignalClient.h @@ -27,12 +27,13 @@ #import #import +#import #ifndef OneSignalClient_h #define OneSignalClient_h @protocol IOneSignalClient -- (void)executeRequest:(OneSignalRequest *)request onSuccess:(OSResultSuccessBlock)successBlock onFailure:(OSFailureBlock)failureBlock; +- (void)executeRequest:(OneSignalRequest *)request onSuccess:(OSResultSuccessBlock)successBlock onFailure:(OSClientFailureBlock)failureBlock; @end @interface OneSignalClient : NSObject diff --git a/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OneSignalClient.m b/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OneSignalClient.m index f62fe3de0..1733ecc3f 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OneSignalClient.m +++ b/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OneSignalClient.m @@ -69,11 +69,11 @@ - (NSURLSessionConfiguration *)configurationWithCachingPolicy:(NSURLRequestCache return configuration; } -- (NSError *)privacyConsentErrorWithRequestType:(NSString *)type { - return [NSError errorWithDomain:@"OneSignal Error" code:0 userInfo:@{@"error" : [NSString stringWithFormat: @"Attempted to perform an HTTP request (%@) before the user provided privacy consent.", type]}]; +- (OneSignalClientError *)privacyConsentErrorWithRequestType:(NSString *)type { + return [[OneSignalClientError alloc] initWithCode:0 message:[NSString stringWithFormat: @"Attempted to perform an HTTP request (%@) before the user provided privacy consent.", type] responseHeaders:nil response:nil underlyingError:nil]; } -- (void)executeRequest:(OneSignalRequest *)request onSuccess:(OSResultSuccessBlock)successBlock onFailure:(OSFailureBlock)failureBlock { +- (void)executeRequest:(OneSignalRequest *)request onSuccess:(OSResultSuccessBlock)successBlock onFailure:(OSClientFailureBlock)failureBlock { // If privacy consent is required but not yet given, any non-GET request should be blocked. if (request.method != GET && [OSPrivacyConsentController shouldLogMissingPrivacyConsentErrorWithMethodName:nil]) { [OneSignalLog onesignalLog:ONE_S_LL_ERROR message:@"Attempted to perform an HTTP request (%@) before the user provided privacy consent."]; @@ -86,7 +86,7 @@ - (void)executeRequest:(OneSignalRequest *)request onSuccess:(OSResultSuccessBlo if (request.dataRequest) { if (failureBlock) { - failureBlock([NSError errorWithDomain:@"onesignal" code:0 userInfo:@{@"error" : [NSString stringWithFormat:@"Attempted to execute a data-only API request (%@) using OneSignalClient's executeRequest: method, which only accepts JSON-based API requests", NSStringFromClass(request.class)]}]); + failureBlock([[OneSignalClientError alloc] initWithCode:0 message:[NSString stringWithFormat:@"Attempted to execute a data-only API request (%@) using OneSignalClient's executeRequest: method, which only accepts JSON-based API requests", NSStringFromClass(request.class)] responseHeaders:nil response:nil underlyingError:nil]); } return; @@ -112,13 +112,13 @@ - (void)executeRequest:(OneSignalRequest *)request onSuccess:(OSResultSuccessBlo [task resume]; } -- (void)handleMissingAppIdError:(OSFailureBlock)failureBlock withRequest:(OneSignalRequest *)request { +- (void)handleMissingAppIdError:(OSClientFailureBlock)failureBlock withRequest:(OneSignalRequest *)request { NSString *errorDescription = [NSString stringWithFormat:@"HTTP Request (%@) must contain app_id parameter", NSStringFromClass([request class])]; [OneSignalLog onesignalLog:ONE_S_LL_ERROR message:errorDescription]; if (failureBlock) - failureBlock([NSError errorWithDomain:@"OneSignalError" code:-1 userInfo:@{@"error" : errorDescription}]); + failureBlock([[OneSignalClientError alloc] initWithCode:-1 message:errorDescription responseHeaders:nil response:nil underlyingError:nil]); } - (BOOL)validRequest:(OneSignalRequest *)request { @@ -147,7 +147,7 @@ - (void)reattemptRequest:(OSReattemptRequest *)reattempt { [self executeRequest:reattempt.request onSuccess:reattempt.successBlock onFailure:reattempt.failureBlock]; } -- (BOOL)willReattemptRequest:(int)statusCode withRequest:(OneSignalRequest *)request success:(OSResultSuccessBlock)successBlock failure:(OSFailureBlock)failureBlock asyncRequest:(BOOL)async { +- (BOOL)willReattemptRequest:(int)statusCode withRequest:(OneSignalRequest *)request success:(OSResultSuccessBlock)successBlock failure:(OSClientFailureBlock)failureBlock asyncRequest:(BOOL)async { // in the event that there is no network connection, NSURLSession will return status code 0 if ((statusCode >= 500 || statusCode == 0) && request.reattemptCount < MAX_ATTEMPT_COUNT - 1) { OSReattemptRequest *reattempt = [OSReattemptRequest withRequest:request successBlock:successBlock failureBlock:failureBlock]; @@ -193,11 +193,11 @@ - (void)prettyPrintDebugStatementWithRequest:(OneSignalRequest *)request { [OneSignalLog onesignalLog:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"HTTP Request (%@) with URL: %@, with parameters: %@ and headers: %@", NSStringFromClass([request class]), request.urlRequest.URL.absoluteString, jsonString, request.additionalHeaders]]; } -- (void)handleJSONNSURLResponse:(NSURLResponse*)response data:(NSData*)data error:(NSError*)error isAsync:(BOOL)async withRequest:(OneSignalRequest *)request onSuccess:(OSResultSuccessBlock)successBlock onFailure:(OSFailureBlock)failureBlock { +- (void)handleJSONNSURLResponse:(NSURLResponse*)response data:(NSData*)data error:(NSError*)error isAsync:(BOOL)async withRequest:(OneSignalRequest *)request onSuccess:(OSResultSuccessBlock)successBlock onFailure:(OSClientFailureBlock)failureBlock { NSHTTPURLResponse* HTTPResponse = (NSHTTPURLResponse*)response; NSInteger statusCode = [HTTPResponse statusCode]; - NSDictionary *headers = [HTTPResponse allHeaderFields] ?: @{}; + NSDictionary *headers = [HTTPResponse allHeaderFields]; // can be null NSError* jsonError = nil; NSMutableDictionary* innerJson; @@ -211,7 +211,7 @@ - (void)handleJSONNSURLResponse:(NSURLResponse*)response data:(NSData*)data erro [OneSignalLog onesignalLog:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"network response (%@) with URL %@: %@", NSStringFromClass([request class]), request.urlRequest.URL.absoluteString, innerJson]]; if (jsonError) { if (failureBlock != nil) - failureBlock([NSError errorWithDomain:@"OneSignal Error" code:statusCode userInfo:@{@"returned" : jsonError, @"headers": headers}]); // Add headers to error block + failureBlock([[OneSignalClientError alloc] initWithCode:statusCode message:@"Error parsing JSON" responseHeaders:headers response:nil underlyingError:jsonError]); return; } } @@ -228,14 +228,7 @@ - (void)handleJSONNSURLResponse:(NSURLResponse*)response data:(NSData*)data erro } } else if (failureBlock != nil) { // Make sure to send all the infomation available to the client - if (innerJson != nil && error != nil) - failureBlock([NSError errorWithDomain:@"OneSignalError" code:statusCode userInfo:@{@"returned" : innerJson, @"error": error, @"headers": headers}]); - else if (innerJson != nil) - failureBlock([NSError errorWithDomain:@"OneSignalError" code:statusCode userInfo:@{@"returned" : innerJson, @"headers": headers}]); - else if (error != nil) - failureBlock([NSError errorWithDomain:@"OneSignalError" code:statusCode userInfo:@{@"error" : error, @"headers": headers}]); - else - failureBlock([NSError errorWithDomain:@"OneSignalError" code:statusCode userInfo:@{@"headers": headers}]); + failureBlock([[OneSignalClientError alloc] initWithCode:statusCode message:@"Error encountered making request" responseHeaders:headers response:innerJson underlyingError:error]); } } diff --git a/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OneSignalClientError.h b/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OneSignalClientError.h new file mode 100644 index 000000000..cd7d9c3b9 --- /dev/null +++ b/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OneSignalClientError.h @@ -0,0 +1,39 @@ +/** + * Modified MIT License + * + * Copyright 2024 OneSignal + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * 1. The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 2. All copies of substantial portions of the Software may only be used in connection + * with services provided by OneSignal. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#import + +@interface OneSignalClientError : NSObject +@property (readonly) NSInteger code; +@property (strong, nonatomic, readonly, nonnull) NSString *message; +@property (strong, nonatomic, readonly, nonnull) NSError *underlyingError; +@property (strong, nonatomic, readonly, nullable) NSDictionary *responseHeaders; +@property (strong, nonatomic, readonly, nullable) NSDictionary *response; +- (instancetype)initWithCode:(NSInteger)code message:(NSString* _Nonnull)message responseHeaders:(NSDictionary* _Nullable)headers response:(NSDictionary* _Nullable)response underlyingError:(NSError* _Nullable)error; +@end + +typedef void (^OSClientFailureBlock)(OneSignalClientError* _Nonnull error); diff --git a/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OneSignalClientError.m b/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OneSignalClientError.m new file mode 100644 index 000000000..e096eab13 --- /dev/null +++ b/iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OneSignalClientError.m @@ -0,0 +1,49 @@ +/** + * Modified MIT License + * + * Copyright 2024 OneSignal + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * 1. The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * 2. All copies of substantial portions of the Software may only be used in connection + * with services provided by OneSignal. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#import "OneSignalClientError.h" + +@implementation OneSignalClientError + +- (instancetype)initWithCode:(NSInteger)code message:(NSString* _Nonnull)message responseHeaders:(NSDictionary* _Nullable)headers response:(NSDictionary* _Nullable)response underlyingError:(NSError* _Nullable)error { + _code = code; + _message = message; + _underlyingError = error; + _response = response; + _responseHeaders = headers; + + if (!error) { + NSMutableDictionary *json = [NSMutableDictionary new]; + json[@"message"] = message; + json[@"response"] = response; + json[@"responseHeaders"] = headers; + _underlyingError = [NSError errorWithDomain:@"OneSignalClientError" code:code userInfo:json]; + } + return self; +} + +@end diff --git a/iOS_SDK/OneSignalSDK/OneSignalCore/Source/OneSignalCore.h b/iOS_SDK/OneSignalSDK/OneSignalCore/Source/OneSignalCore.h index 72843f933..a0bd2c231 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalCore/Source/OneSignalCore.h +++ b/iOS_SDK/OneSignalSDK/OneSignalCore/Source/OneSignalCore.h @@ -57,6 +57,8 @@ #import #import #import +#import + // TODO: Testing: Should this class be defined in this file? @interface OneSignalCoreImpl : NSObject diff --git a/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/MockOneSignalClient.swift b/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/MockOneSignalClient.swift index b1b870f32..82f951094 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/MockOneSignalClient.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalCoreMocks/MockOneSignalClient.swift @@ -32,7 +32,7 @@ public class MockOneSignalClient: NSObject, IOneSignalClient { let lock = NSLock() var mockResponses: [String: [String: Any]] = [:] - var mockFailureResponses: [String: NSError] = [:] + var mockFailureResponses: [String: OneSignalClientError] = [:] public var lastHTTPRequest: OneSignalRequest? public var networkRequestCount = 0 public var executedRequests: [OneSignalRequest] = [] @@ -90,7 +90,7 @@ public class MockOneSignalClient: NSObject, IOneSignalClient { remoteParamsOutcomes = [:] } - public func execute(_ request: OneSignalRequest, onSuccess successBlock: @escaping OSResultSuccessBlock, onFailure failureBlock: @escaping OSFailureBlock) { + public func execute(_ request: OneSignalRequest, onSuccess successBlock: @escaping OSResultSuccessBlock, onFailure failureBlock: @escaping OSClientFailureBlock) { print("🧪 MockOneSignalClient execute called") if executeInstantaneously { @@ -117,7 +117,7 @@ public class MockOneSignalClient: NSObject, IOneSignalClient { return stringified } - func finishExecutingRequest(_ request: OneSignalRequest, onSuccess successBlock: OSResultSuccessBlock, onFailure failureBlock: OSFailureBlock) { + func finishExecutingRequest(_ request: OneSignalRequest, onSuccess successBlock: OSResultSuccessBlock, onFailure failureBlock: OSClientFailureBlock) { // TODO: This entire method needs to contained within the equivalent of @synchronized ❗️ print("🧪 completing HTTP request: \(request)") @@ -137,8 +137,8 @@ public class MockOneSignalClient: NSObject, IOneSignalClient { } if (mockResponses[stringifiedRequest]) != nil { successBlock(mockResponses[stringifiedRequest]) - } else if (mockFailureResponses[stringifiedRequest]) != nil { - failureBlock(mockFailureResponses[stringifiedRequest]) + } else if let response = mockFailureResponses[stringifiedRequest] { + failureBlock(response) } else if fireSuccessForAllRequests { allRequestsHandled = false successBlock([:]) @@ -166,7 +166,7 @@ public class MockOneSignalClient: NSObject, IOneSignalClient { mockResponses[request] = response } - public func setMockFailureResponseForRequest(request: String, error: NSError) { + public func setMockFailureResponseForRequest(request: String, error: OneSignalClientError) { mockFailureResponses[request] = error } } diff --git a/iOS_SDK/OneSignalSDK/OneSignalExtension/OneSignalReceiveReceiptsController.m b/iOS_SDK/OneSignalSDK/OneSignalExtension/OneSignalReceiveReceiptsController.m index e232e5954..63aa9dcab 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalExtension/OneSignalReceiveReceiptsController.m +++ b/iOS_SDK/OneSignalSDK/OneSignalExtension/OneSignalReceiveReceiptsController.m @@ -101,9 +101,9 @@ - (void)sendReceiveReceiptWithPlayerId:(nonnull NSString *)playerId if (success) { success(result); } - } onFailure:^(NSError *error) { + } onFailure:^(OneSignalClientError *error) { if (failure) { - failure(error); + failure(error.underlyingError); } }]; }); diff --git a/iOS_SDK/OneSignalSDK/OneSignalInAppMessages/Controller/OSInAppMessageController.m b/iOS_SDK/OneSignalSDK/OneSignalInAppMessages/Controller/OSInAppMessageController.m index 0c60b965d..b78b99d67 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalInAppMessages/Controller/OSInAppMessageController.m +++ b/iOS_SDK/OneSignalSDK/OneSignalInAppMessages/Controller/OSInAppMessageController.m @@ -46,13 +46,17 @@ - (void)loadMessageHTMLContentWithResult:(OSResultSuccessBlock _Nullable)success let request = [OSRequestLoadInAppMessageContent withAppId:[OneSignalConfigManager getAppId] withMessageId:self.messageId withVariantId:variantId]; - [OneSignalCoreImpl.sharedClient executeRequest:request onSuccess:successBlock onFailure:failureBlock]; + [OneSignalCoreImpl.sharedClient executeRequest:request onSuccess:successBlock onFailure:^(OneSignalClientError *error) { + failureBlock(error.underlyingError); + }]; } - (void)loadPreviewMessageHTMLContentWithUUID:(NSString * _Nonnull)previewUUID success:(OSResultSuccessBlock _Nullable)successBlock failure:(OSFailureBlock _Nullable)failureBlock { let request = [OSRequestLoadInAppMessagePreviewContent withAppId:[OneSignalConfigManager getAppId] previewUUID:previewUUID]; - [OneSignalCoreImpl.sharedClient executeRequest:request onSuccess:successBlock onFailure:failureBlock]; + [OneSignalCoreImpl.sharedClient executeRequest:request onSuccess:successBlock onFailure:^(OneSignalClientError *error) { + failureBlock(error.underlyingError); + }]; } /** diff --git a/iOS_SDK/OneSignalSDK/OneSignalInAppMessages/Controller/OSMessagingController.m b/iOS_SDK/OneSignalSDK/OneSignalInAppMessages/Controller/OSMessagingController.m index 157efafb1..2cc5d964a 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalInAppMessages/Controller/OSMessagingController.m +++ b/iOS_SDK/OneSignalSDK/OneSignalInAppMessages/Controller/OSMessagingController.m @@ -315,19 +315,12 @@ - (void)attemptFetchWithRetries:(NSString *)subscriptionId } }); } - onFailure:^(NSError *error) { - NSDictionary *errorInfo = error.userInfo[@"returned"]; - NSNumber *statusCode = errorInfo[@"httpStatusCode"]; - NSDictionary* responseHeaders = errorInfo[@"headers"]; - - if (!statusCode) { - return; - } - - [OneSignalLog onesignalLog:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"getInAppMessagesFromServer failure: %@", error.localizedDescription]]; + onFailure:^(OneSignalClientError *error) { + NSDictionary* responseHeaders = error.responseHeaders; + + [OneSignalLog onesignalLog:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"getInAppMessagesFromServer failure: %@", error.underlyingError.localizedDescription]]; - NSInteger code = [statusCode integerValue]; - if (code == 425 || code == 429) { // 425 Too Early or 429 Too Many Requests + if (error.code == 425 || error.code == 429) { // 425 Too Early or 429 Too Many Requests NSInteger retryAfter = [responseHeaders[@"Retry-After"] integerValue] ?: DEFAULT_RETRY_AFTER_SECONDS; // Dynamically set the retry limit from the header, if not already set @@ -346,7 +339,7 @@ - (void)attemptFetchWithRetries:(NSString *)subscriptionId // Final attempt without rywToken [self fetchInAppMessagesWithoutToken:subscriptionId]; } - } else if (code >= 500 && code <= 599) { + } else if (error.code >= 500 && error.code <= 599) { [OneSignalLog onesignalLog:ONE_S_LL_VERBOSE message:@"Server error, skipping retries"]; } }]; @@ -393,8 +386,8 @@ - (void)fetchInAppMessagesWithoutToken:(NSString *)subscriptionId { return; } }); - } onFailure:^(NSError *error) { - [OneSignalLog onesignalLog:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"getInAppMessagesFromServer failure: %@", error.localizedDescription]]; + } onFailure:^(OneSignalClientError *error) { + [OneSignalLog onesignalLog:ONE_S_LL_VERBOSE message:[NSString stringWithFormat:@"getInAppMessagesFromServer failure: %@", error.underlyingError.localizedDescription]]; }]; } @@ -630,8 +623,8 @@ - (void)messageViewPageImpressionRequest:(OSInAppMessageInternal *)message withP // If the post was successful, save the updated viewedPageIds set [OneSignalUserDefaults.initStandard saveSetForKey:OS_IAM_PAGE_IMPRESSIONED_SET_KEY withValue:self.viewedPageIDs]; } - onFailure:^(NSError *error) { - NSString *errorMessage = [NSString stringWithFormat:@"In App Message with message id: %@ and page id: %@, failed POST page impression update with error: %@", message.messageId, pageId, error]; + onFailure:^(OneSignalClientError *error) { + NSString *errorMessage = [NSString stringWithFormat:@"In App Message with message id: %@ and page id: %@, failed POST page impression update with error: %@", message.messageId, pageId, error.message]; [OneSignalLog onesignalLog:ONE_S_LL_ERROR message:errorMessage]; if (message) { [self.viewedPageIDs removeObject:messagePrefixedPageId]; @@ -670,8 +663,8 @@ - (void)messageViewImpressionRequest:(OSInAppMessageInternal *)message { // If the post was successful, save the updated impressionedInAppMessages set [OneSignalUserDefaults.initStandard saveSetForKey:OS_IAM_IMPRESSIONED_SET_KEY withValue:self.impressionedInAppMessages]; } - onFailure:^(NSError *error) { - NSString *errorMessage = [NSString stringWithFormat:@"In App Message with id: %@, failed POST impression update with error: %@", message.messageId, error]; + onFailure:^(OneSignalClientError *error) { + NSString *errorMessage = [NSString stringWithFormat:@"In App Message with id: %@, failed POST impression update with error: %@", message.messageId, error.message]; [OneSignalLog onesignalLog:ONE_S_LL_ERROR message:errorMessage]; // If the post failed, remove the messageId from the impressionedInAppMessages set @@ -1079,8 +1072,8 @@ - (void)sendClickRESTCall:(OSInAppMessageInternal *)message withAction:(OSInAppM // Save the updated clickedClickIds since click was tracked successfully [OneSignalUserDefaults.initStandard saveSetForKey:OS_IAM_CLICKED_SET_KEY withValue:self.clickedClickIds]; } - onFailure:^(NSError *error) { - NSString *errorMessage = [NSString stringWithFormat:@"In App Message with id: %@, failed POST click update for click id: %@, with error: %@", message.messageId, action.clickId, error]; + onFailure:^(OneSignalClientError *error) { + NSString *errorMessage = [NSString stringWithFormat:@"In App Message with id: %@, failed POST click update for click id: %@, with error: %@", message.messageId, action.clickId, error.message]; [OneSignalLog onesignalLog:ONE_S_LL_ERROR message:errorMessage]; // Remove clickId from local clickedClickIds since click was not tracked diff --git a/iOS_SDK/OneSignalSDK/OneSignalLiveActivities/Source/Executors/OSLiveActivitiesExecutor.swift b/iOS_SDK/OneSignalSDK/OneSignalLiveActivities/Source/Executors/OSLiveActivitiesExecutor.swift index ab4ece358..decfe741b 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalLiveActivities/Source/Executors/OSLiveActivitiesExecutor.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalLiveActivities/Source/Executors/OSLiveActivitiesExecutor.swift @@ -212,15 +212,13 @@ class OSLiveActivitiesExecutor: OSPushSubscriptionObserver { } onFailure: { error in // NOTE: No longer running under `requestDispatch` DispatchQueue! OneSignalLog.onesignalLog(.LL_VERBOSE, message: "OneSignal.LiveActivities request failed with error \(error.debugDescription)") - if let nsError = error as? NSError { - let responseType = OSNetworkingUtils.getResponseStatusType(nsError.code) - if responseType != .retryable { - self.requestDispatch.async { - // Failed, no retry. Remove the key from the cache entirely so we don't try again. - cache.remove(request) - } - return + let responseType = OSNetworkingUtils.getResponseStatusType(error.code) + if responseType != .retryable { + self.requestDispatch.async { + // Failed, no retry. Remove the key from the cache entirely so we don't try again. + cache.remove(request) } + return } // retryable failures will stay in the cache, and will retry the next time the app starts } diff --git a/iOS_SDK/OneSignalSDK/OneSignalLiveActivitiesTests/OSLiveActivitiesExecutorTests.swift b/iOS_SDK/OneSignalSDK/OneSignalLiveActivitiesTests/OSLiveActivitiesExecutorTests.swift index 9694d2667..b2af70b54 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalLiveActivitiesTests/OSLiveActivitiesExecutorTests.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalLiveActivitiesTests/OSLiveActivitiesExecutorTests.swift @@ -183,7 +183,7 @@ final class OSLiveActivitiesExecutorTests: XCTestCase { mockClient.reset() let request = OSRequestSetStartToken(key: "my-activity-type", token: "my-token") - mockClient.setMockFailureResponseForRequest(request: String(describing: request), error: NSError(domain: "not-important", code: 500)) + mockClient.setMockFailureResponseForRequest(request: String(describing: request), error: OneSignalClientError(code: 500, message: "not-important", responseHeaders: nil, response: nil, underlyingError: nil)) /* When */ let executor = OSLiveActivitiesExecutor(requestDispatch: mockDispatchQueue) @@ -210,7 +210,7 @@ final class OSLiveActivitiesExecutorTests: XCTestCase { mockClient.reset() let request = OSRequestSetStartToken(key: "my-activity-type", token: "my-token") - mockClient.setMockFailureResponseForRequest(request: String(describing: request), error: NSError(domain: "not-important", code: 401)) + mockClient.setMockFailureResponseForRequest(request: String(describing: request), error: OneSignalClientError(code: 401, message: "not-important", responseHeaders: nil, response: nil, underlyingError: nil)) /* When */ let executor = OSLiveActivitiesExecutor(requestDispatch: mockDispatchQueue) diff --git a/iOS_SDK/OneSignalSDK/OneSignalOutcomes/Source/OutcomeEvents/Controller/V1/OSOutcomeEventsV1Repository.m b/iOS_SDK/OneSignalSDK/OneSignalOutcomes/Source/OutcomeEvents/Controller/V1/OSOutcomeEventsV1Repository.m index 0bb0b6b08..62b8c79cc 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalOutcomes/Source/OutcomeEvents/Controller/V1/OSOutcomeEventsV1Repository.m +++ b/iOS_SDK/OneSignalSDK/OneSignalOutcomes/Source/OutcomeEvents/Controller/V1/OSOutcomeEventsV1Repository.m @@ -65,7 +65,9 @@ - (void)requestMeasureOutcomeEventWithAppId:(NSString *)appId return; } - [OneSignalCoreImpl.sharedClient executeRequest:request onSuccess:successBlock onFailure:failureBlock]; + [OneSignalCoreImpl.sharedClient executeRequest:request onSuccess:successBlock onFailure:^(OneSignalClientError *error) { + failureBlock(error.underlyingError); + }]; } @end diff --git a/iOS_SDK/OneSignalSDK/OneSignalOutcomes/Source/OutcomeEvents/Controller/V2/OSOutcomeEventsV2Repository.m b/iOS_SDK/OneSignalSDK/OneSignalOutcomes/Source/OutcomeEvents/Controller/V2/OSOutcomeEventsV2Repository.m index 5fe25d190..5d8f3fa7d 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalOutcomes/Source/OutcomeEvents/Controller/V2/OSOutcomeEventsV2Repository.m +++ b/iOS_SDK/OneSignalSDK/OneSignalOutcomes/Source/OutcomeEvents/Controller/V2/OSOutcomeEventsV2Repository.m @@ -43,7 +43,9 @@ - (void)requestMeasureOutcomeEventWithAppId:(NSString *)appId appId:appId deviceType:deviceType]; - [OneSignalCoreImpl.sharedClient executeRequest:request onSuccess:successBlock onFailure:failureBlock]; + [OneSignalCoreImpl.sharedClient executeRequest:request onSuccess:successBlock onFailure:^(OneSignalClientError *error) { + failureBlock(error.underlyingError); + }]; } @end diff --git a/iOS_SDK/OneSignalSDK/OneSignalOutcomes/Source/OutcomeEvents/OneSignalOutcomeEventsController.m b/iOS_SDK/OneSignalSDK/OneSignalOutcomes/Source/OutcomeEvents/OneSignalOutcomeEventsController.m index 99d0a7a75..b9f17231a 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalOutcomes/Source/OutcomeEvents/OneSignalOutcomeEventsController.m +++ b/iOS_SDK/OneSignalSDK/OneSignalOutcomes/Source/OutcomeEvents/OneSignalOutcomeEventsController.m @@ -121,10 +121,10 @@ - (void)sendSessionEndOutcomes:(NSNumber * _Nonnull)timeElapsed if (successBlock) { successBlock(result); } - } onFailure:^(NSError *error) { + } onFailure:^(OneSignalClientError *error) { [OneSignalLog onesignalLog:ONE_S_LL_ERROR message:@"OneSignalOutcomeEventsController:sendSessionEndOutcomes attributed failed"]; if (failureBlock) { - failureBlock(error); + failureBlock(error.underlyingError); } }]; } diff --git a/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSIdentityOperationExecutor.swift b/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSIdentityOperationExecutor.swift index 6a7b44b4d..2af8ea812 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSIdentityOperationExecutor.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSIdentityOperationExecutor.swift @@ -218,28 +218,26 @@ class OSIdentityOperationExecutor: OSOperationExecutor { } onFailure: { error in OneSignalLog.onesignalLog(.LL_ERROR, message: "OSIdentityOperationExecutor add aliases request failed with error: \(error.debugDescription)") self.dispatchQueue.async { - if let nsError = error as? NSError { - let responseType = OSNetworkingUtils.getResponseStatusType(nsError.code) - if responseType == .missing { - // Remove from cache and queue - self.addRequestQueue.removeAll(where: { $0 == request}) - OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self.addRequestQueue) - // Logout if the user in the SDK is the same - guard OneSignalUserManagerImpl.sharedInstance.isCurrentUser(request.identityModel) - else { - if inBackground { - OSBackgroundTaskManager.endBackgroundTask(backgroundTaskIdentifier) - } - return + let responseType = OSNetworkingUtils.getResponseStatusType(error.code) + if responseType == .missing { + // Remove from cache and queue + self.addRequestQueue.removeAll(where: { $0 == request}) + OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self.addRequestQueue) + // Logout if the user in the SDK is the same + guard OneSignalUserManagerImpl.sharedInstance.isCurrentUser(request.identityModel) + else { + if inBackground { + OSBackgroundTaskManager.endBackgroundTask(backgroundTaskIdentifier) } - // The subscription has been deleted along with the user, so remove the subscription_id but keep the same push subscription model - OneSignalUserManagerImpl.sharedInstance.pushSubscriptionModel?.subscriptionId = nil - OneSignalUserManagerImpl.sharedInstance._logout() - } else if responseType != .retryable { - // Fail, no retry, remove from cache and queue - self.addRequestQueue.removeAll(where: { $0 == request}) - OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self.addRequestQueue) + return } + // The subscription has been deleted along with the user, so remove the subscription_id but keep the same push subscription model + OneSignalUserManagerImpl.sharedInstance.pushSubscriptionModel?.subscriptionId = nil + OneSignalUserManagerImpl.sharedInstance._logout() + } else if responseType != .retryable { + // Fail, no retry, remove from cache and queue + self.addRequestQueue.removeAll(where: { $0 == request}) + OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self.addRequestQueue) } if inBackground { OSBackgroundTaskManager.endBackgroundTask(backgroundTaskIdentifier) @@ -277,14 +275,12 @@ class OSIdentityOperationExecutor: OSOperationExecutor { } onFailure: { error in OneSignalLog.onesignalLog(.LL_ERROR, message: "OSIdentityOperationExecutor remove alias request failed with error: \(error.debugDescription)") self.dispatchQueue.async { - if let nsError = error as? NSError { - let responseType = OSNetworkingUtils.getResponseStatusType(nsError.code) - if responseType != .retryable { - // Fail, no retry, remove from cache and queue - // A response of .missing could mean the alias doesn't exist on this user OR this user has been deleted - self.removeRequestQueue.removeAll(where: { $0 == request}) - OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY, withValue: self.removeRequestQueue) - } + let responseType = OSNetworkingUtils.getResponseStatusType(error.code) + if responseType != .retryable { + // Fail, no retry, remove from cache and queue + // A response of .missing could mean the alias doesn't exist on this user OR this user has been deleted + self.removeRequestQueue.removeAll(where: { $0 == request}) + OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_IDENTITY_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY, withValue: self.removeRequestQueue) } if inBackground { OSBackgroundTaskManager.endBackgroundTask(backgroundTaskIdentifier) diff --git a/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSPropertyOperationExecutor.swift b/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSPropertyOperationExecutor.swift index a8dc7c072..427a930dc 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSPropertyOperationExecutor.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSPropertyOperationExecutor.swift @@ -273,28 +273,26 @@ class OSPropertyOperationExecutor: OSOperationExecutor { } onFailure: { error in OneSignalLog.onesignalLog(.LL_ERROR, message: "OSPropertyOperationExecutor update properties request failed with error: \(error.debugDescription)") self.dispatchQueue.async { - if let nsError = error as? NSError { - let responseType = OSNetworkingUtils.getResponseStatusType(nsError.code) - if responseType == .missing { - // remove from cache and queue - self.updateRequestQueue.removeAll(where: { $0 == request}) - OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_PROPERTIES_EXECUTOR_UPDATE_REQUEST_QUEUE_KEY, withValue: self.updateRequestQueue) - // Logout if the user in the SDK is the same - guard OneSignalUserManagerImpl.sharedInstance.isCurrentUser(request.identityModel) - else { - if inBackground { - OSBackgroundTaskManager.endBackgroundTask(backgroundTaskIdentifier) - } - return + let responseType = OSNetworkingUtils.getResponseStatusType(error.code) + if responseType == .missing { + // remove from cache and queue + self.updateRequestQueue.removeAll(where: { $0 == request}) + OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_PROPERTIES_EXECUTOR_UPDATE_REQUEST_QUEUE_KEY, withValue: self.updateRequestQueue) + // Logout if the user in the SDK is the same + guard OneSignalUserManagerImpl.sharedInstance.isCurrentUser(request.identityModel) + else { + if inBackground { + OSBackgroundTaskManager.endBackgroundTask(backgroundTaskIdentifier) } - // The subscription has been deleted along with the user, so remove the subscription_id but keep the same push subscription model - OneSignalUserManagerImpl.sharedInstance.pushSubscriptionModel?.subscriptionId = nil - OneSignalUserManagerImpl.sharedInstance._logout() - } else if responseType != .retryable { - // Fail, no retry, remove from cache and queue - self.updateRequestQueue.removeAll(where: { $0 == request}) - OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_PROPERTIES_EXECUTOR_UPDATE_REQUEST_QUEUE_KEY, withValue: self.updateRequestQueue) + return } + // The subscription has been deleted along with the user, so remove the subscription_id but keep the same push subscription model + OneSignalUserManagerImpl.sharedInstance.pushSubscriptionModel?.subscriptionId = nil + OneSignalUserManagerImpl.sharedInstance._logout() + } else if responseType != .retryable { + // Fail, no retry, remove from cache and queue + self.updateRequestQueue.removeAll(where: { $0 == request}) + OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_PROPERTIES_EXECUTOR_UPDATE_REQUEST_QUEUE_KEY, withValue: self.updateRequestQueue) } if inBackground { OSBackgroundTaskManager.endBackgroundTask(backgroundTaskIdentifier) diff --git a/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSSubscriptionOperationExecutor.swift b/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSSubscriptionOperationExecutor.swift index 090c43dd7..f44d84157 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSSubscriptionOperationExecutor.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSSubscriptionOperationExecutor.swift @@ -321,27 +321,25 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor { } onFailure: { error in OneSignalLog.onesignalLog(.LL_ERROR, message: "OSSubscriptionOperationExecutor create subscription request failed with error: \(error.debugDescription)") self.dispatchQueue.async { - if let nsError = error as? NSError { - let responseType = OSNetworkingUtils.getResponseStatusType(nsError.code) - if responseType == .missing { - self.addRequestQueue.removeAll(where: { $0 == request}) - OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_SUBSCRIPTION_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self.addRequestQueue) - // Logout if the user in the SDK is the same - guard OneSignalUserManagerImpl.sharedInstance.isCurrentUser(request.identityModel) - else { - if inBackground { - OSBackgroundTaskManager.endBackgroundTask(backgroundTaskIdentifier) - } - return + let responseType = OSNetworkingUtils.getResponseStatusType(error.code) + if responseType == .missing { + self.addRequestQueue.removeAll(where: { $0 == request}) + OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_SUBSCRIPTION_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self.addRequestQueue) + // Logout if the user in the SDK is the same + guard OneSignalUserManagerImpl.sharedInstance.isCurrentUser(request.identityModel) + else { + if inBackground { + OSBackgroundTaskManager.endBackgroundTask(backgroundTaskIdentifier) } - // The subscription has been deleted along with the user, so remove the subscription_id but keep the same push subscription model - OneSignalUserManagerImpl.sharedInstance.pushSubscriptionModel?.subscriptionId = nil - OneSignalUserManagerImpl.sharedInstance._logout() - } else if responseType != .retryable { - // Fail, no retry, remove from cache and queue - self.addRequestQueue.removeAll(where: { $0 == request}) - OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_SUBSCRIPTION_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self.addRequestQueue) + return } + // The subscription has been deleted along with the user, so remove the subscription_id but keep the same push subscription model + OneSignalUserManagerImpl.sharedInstance.pushSubscriptionModel?.subscriptionId = nil + OneSignalUserManagerImpl.sharedInstance._logout() + } else if responseType != .retryable { + // Fail, no retry, remove from cache and queue + self.addRequestQueue.removeAll(where: { $0 == request}) + OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_SUBSCRIPTION_EXECUTOR_ADD_REQUEST_QUEUE_KEY, withValue: self.addRequestQueue) } if inBackground { OSBackgroundTaskManager.endBackgroundTask(backgroundTaskIdentifier) @@ -379,14 +377,12 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor { } onFailure: { error in OneSignalLog.onesignalLog(.LL_ERROR, message: "OSSubscriptionOperationExecutor delete subscription request failed with error: \(error.debugDescription)") self.dispatchQueue.async { - if let nsError = error as? NSError { - let responseType = OSNetworkingUtils.getResponseStatusType(nsError.code) - if responseType != .retryable { - // Fail, no retry, remove from cache and queue - // If this request returns a missing status, that is ok as this is a delete request - self.removeRequestQueue.removeAll(where: { $0 == request}) - OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_SUBSCRIPTION_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY, withValue: self.removeRequestQueue) - } + let responseType = OSNetworkingUtils.getResponseStatusType(error.code) + if responseType != .retryable { + // Fail, no retry, remove from cache and queue + // If this request returns a missing status, that is ok as this is a delete request + self.removeRequestQueue.removeAll(where: { $0 == request}) + OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_SUBSCRIPTION_EXECUTOR_REMOVE_REQUEST_QUEUE_KEY, withValue: self.removeRequestQueue) } if inBackground { OSBackgroundTaskManager.endBackgroundTask(backgroundTaskIdentifier) @@ -437,13 +433,11 @@ class OSSubscriptionOperationExecutor: OSOperationExecutor { } onFailure: { error in OneSignalLog.onesignalLog(.LL_ERROR, message: "OSSubscriptionOperationExecutor update subscription request failed with error: \(error.debugDescription)") self.dispatchQueue.async { - if let nsError = error as? NSError { - let responseType = OSNetworkingUtils.getResponseStatusType(nsError.code) - if responseType != .retryable { - // Fail, no retry, remove from cache and queue - self.updateRequestQueue.removeAll(where: { $0 == request}) - OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_SUBSCRIPTION_EXECUTOR_UPDATE_REQUEST_QUEUE_KEY, withValue: self.updateRequestQueue) - } + let responseType = OSNetworkingUtils.getResponseStatusType(error.code) + if responseType != .retryable { + // Fail, no retry, remove from cache and queue + self.updateRequestQueue.removeAll(where: { $0 == request}) + OneSignalUserDefaults.initShared().saveCodeableData(forKey: OS_SUBSCRIPTION_EXECUTOR_UPDATE_REQUEST_QUEUE_KEY, withValue: self.updateRequestQueue) } if inBackground { OSBackgroundTaskManager.endBackgroundTask(backgroundTaskIdentifier) diff --git a/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSUserExecutor.swift b/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSUserExecutor.swift index 3ca2e4c39..244c5ae04 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSUserExecutor.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalUser/Source/Executors/OSUserExecutor.swift @@ -277,17 +277,13 @@ extension OSUserExecutor { OSOperationRepo.sharedInstance.paused = false } onFailure: { error in OneSignalLog.onesignalLog(.LL_ERROR, message: "OSUserExecutor create user request failed with error: \(error.debugDescription)") - if let nsError = error as? NSError { - let responseType = OSNetworkingUtils.getResponseStatusType(nsError.code) - if responseType != .retryable { - // A failed create user request would leave the SDK in a bad state - // Don't remove the request from cache and pause the operation repo - // We will retry this request on a new session - OSOperationRepo.sharedInstance.paused = true - request.sentToClient = false - } - } else { - self.executePendingRequests() + let responseType = OSNetworkingUtils.getResponseStatusType(error.code) + if responseType != .retryable { + // A failed create user request would leave the SDK in a bad state + // Don't remove the request from cache and pause the operation repo + // We will retry this request on a new session + OSOperationRepo.sharedInstance.paused = true + request.sentToClient = false } } } @@ -333,13 +329,11 @@ extension OSUserExecutor { } } onFailure: { error in OneSignalLog.onesignalLog(.LL_ERROR, message: "OSUserExecutor executeFetchIdentityBySubscriptionRequest failed with error: \(error.debugDescription)") - if let nsError = error as? NSError { - let responseType = OSNetworkingUtils.getResponseStatusType(nsError.code) - if responseType != .retryable { - // Fail, no retry, remove the subscription_id but keep the same push subscription model - OneSignalUserManagerImpl.sharedInstance.pushSubscriptionModel?.subscriptionId = nil - self.removeFromQueue(request) - } + let responseType = OSNetworkingUtils.getResponseStatusType(error.code) + if responseType != .retryable { + // Fail, no retry, remove the subscription_id but keep the same push subscription model + OneSignalUserManagerImpl.sharedInstance.pushSubscriptionModel?.subscriptionId = nil + self.removeFromQueue(request) } self.executePendingRequests() } @@ -395,39 +389,35 @@ extension OSUserExecutor { self.executePendingRequests() } } onFailure: { error in - if let nsError = error as? NSError { - let responseType = OSNetworkingUtils.getResponseStatusType(nsError.code) - if responseType == .conflict { - // Returns 409 if any provided (label, id) pair exists on another User, so the SDK will switch to this user. - OneSignalLog.onesignalLog(.LL_DEBUG, message: "executeIdentifyUserRequest returned error code user-2. Now handling user-2 error response... switch to this user.") + let responseType = OSNetworkingUtils.getResponseStatusType(error.code) + if responseType == .conflict { + // Returns 409 if any provided (label, id) pair exists on another User, so the SDK will switch to this user. + OneSignalLog.onesignalLog(.LL_DEBUG, message: "executeIdentifyUserRequest returned error code user-2. Now handling user-2 error response... switch to this user.") - self.removeFromQueue(request) + self.removeFromQueue(request) - if OneSignalUserManagerImpl.sharedInstance.isCurrentUser(request.identityModelToUpdate) { - // Generate a Create User request, if it's still the current user - self.createUser(OneSignalUserManagerImpl.sharedInstance.user) - } else { - // This will hydrate the OneSignal ID for any pending requests - self.createUser(aliasLabel: request.aliasLabel, aliasId: request.aliasId, identityModel: request.identityModelToUpdate) - } - } else if responseType == .invalid || responseType == .unauthorized { - // Failed, no retry - self.removeFromQueue(request) - self.executePendingRequests() - } else if responseType == .missing { - self.removeFromQueue(request) - self.executePendingRequests() - // Logout if the user in the SDK is the same - guard OneSignalUserManagerImpl.sharedInstance.isCurrentUser(request.identityModelToUpdate) - else { - return - } - // The subscription has been deleted along with the user, so remove the subscription_id but keep the same push subscription model - OneSignalUserManagerImpl.sharedInstance.pushSubscriptionModel?.subscriptionId = nil - OneSignalUserManagerImpl.sharedInstance._logout() + if OneSignalUserManagerImpl.sharedInstance.isCurrentUser(request.identityModelToUpdate) { + // Generate a Create User request, if it's still the current user + self.createUser(OneSignalUserManagerImpl.sharedInstance.user) + } else { + // This will hydrate the OneSignal ID for any pending requests + self.createUser(aliasLabel: request.aliasLabel, aliasId: request.aliasId, identityModel: request.identityModelToUpdate) } - } else { + } else if responseType == .invalid || responseType == .unauthorized { + // Failed, no retry + self.removeFromQueue(request) + self.executePendingRequests() + } else if responseType == .missing { + self.removeFromQueue(request) self.executePendingRequests() + // Logout if the user in the SDK is the same + guard OneSignalUserManagerImpl.sharedInstance.isCurrentUser(request.identityModelToUpdate) + else { + return + } + // The subscription has been deleted along with the user, so remove the subscription_id but keep the same push subscription model + OneSignalUserManagerImpl.sharedInstance.pushSubscriptionModel?.subscriptionId = nil + OneSignalUserManagerImpl.sharedInstance._logout() } } } @@ -485,22 +475,20 @@ extension OSUserExecutor { self.executePendingRequests() } onFailure: { error in OneSignalLog.onesignalLog(.LL_ERROR, message: "OSUserExecutor executeFetchUserRequest failed with error: \(error.debugDescription)") - if let nsError = error as? NSError { - let responseType = OSNetworkingUtils.getResponseStatusType(nsError.code) - if responseType == .missing { - self.removeFromQueue(request) - // Logout if the user in the SDK is the same - guard OneSignalUserManagerImpl.sharedInstance.isCurrentUser(request.identityModel) - else { - return - } - // The subscription has been deleted along with the user, so remove the subscription_id but keep the same push subscription model - OneSignalUserManagerImpl.sharedInstance.pushSubscriptionModel?.subscriptionId = nil - OneSignalUserManagerImpl.sharedInstance._logout() - } else if responseType != .retryable { - // If the error is not retryable, remove from cache and queue - self.removeFromQueue(request) + let responseType = OSNetworkingUtils.getResponseStatusType(error.code) + if responseType == .missing { + self.removeFromQueue(request) + // Logout if the user in the SDK is the same + guard OneSignalUserManagerImpl.sharedInstance.isCurrentUser(request.identityModel) + else { + return } + // The subscription has been deleted along with the user, so remove the subscription_id but keep the same push subscription model + OneSignalUserManagerImpl.sharedInstance.pushSubscriptionModel?.subscriptionId = nil + OneSignalUserManagerImpl.sharedInstance._logout() + } else if responseType != .retryable { + // If the error is not retryable, remove from cache and queue + self.removeFromQueue(request) } self.executePendingRequests() } diff --git a/iOS_SDK/OneSignalSDK/OneSignalUserMocks/MockUserRequests.swift b/iOS_SDK/OneSignalSDK/OneSignalUserMocks/MockUserRequests.swift index 77560bd28..7864d2905 100644 --- a/iOS_SDK/OneSignalSDK/OneSignalUserMocks/MockUserRequests.swift +++ b/iOS_SDK/OneSignalSDK/OneSignalUserMocks/MockUserRequests.swift @@ -108,7 +108,7 @@ extension MockUserRequests { fetchResponse = MockUserRequests.testIdentityPayload(onesignalId: osid, externalId: externalId) client.setMockFailureResponseForRequest( request: "", - error: NSError(domain: "not-important", code: 409) + error: OneSignalClientError(code: 409, message: "not-important", responseHeaders: nil, response: nil, underlyingError: nil) ) // 2. Set the response for the subsequent Create User request let userResponse = MockUserRequests.testIdentityPayload(onesignalId: osid, externalId: externalId) diff --git a/iOS_SDK/OneSignalSDK/Source/OneSignal.m b/iOS_SDK/OneSignalSDK/Source/OneSignal.m index cb2bc54ea..35a46eccd 100755 --- a/iOS_SDK/OneSignalSDK/Source/OneSignal.m +++ b/iOS_SDK/OneSignalSDK/Source/OneSignal.m @@ -655,7 +655,7 @@ + (void)downloadIOSParamsWithAppId:(NSString *)appId { _downloadedParameters = true; - } onFailure:^(NSError *error) { + } onFailure:^(OneSignalClientError *error) { _didCallDownloadParameters = false; }]; }