Skip to content

Commit

Permalink
Merge pull request #1528 from OneSignal/fix/client_error_callback
Browse files Browse the repository at this point in the history
Fix: Use new OneSignalClientError type for callbacks
  • Loading branch information
nan-li authored Dec 17, 2024
2 parents f08811e + 8186def commit 64d3eff
Show file tree
Hide file tree
Showing 23 changed files with 281 additions and 213 deletions.
8 changes: 8 additions & 0 deletions iOS_SDK/OneSignalSDK/OneSignal.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -1263,6 +1265,8 @@
3C6299A82BEEA46C00649187 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
3C6299AA2BEEA4C000649187 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
3C67F7792BEB2B710085A0F0 /* SwitchUserIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwitchUserIntegrationTests.swift; sourceTree = "<group>"; };
3C70FA652D0B68A100031066 /* OneSignalClientError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OneSignalClientError.h; sourceTree = "<group>"; };
3C70FA662D0B68A100031066 /* OneSignalClientError.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OneSignalClientError.m; sourceTree = "<group>"; };
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 = "<group>"; };
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@

#import <Foundation/Foundation.h>
#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
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@

#import <Foundation/Foundation.h>
#import <OneSignalCore/OneSignalRequest.h>
#import <OneSignalCore/OneSignalClientError.h>

#ifndef OneSignalClient_h
#define OneSignalClient_h

@protocol IOneSignalClient <NSObject>
- (void)executeRequest:(OneSignalRequest *)request onSuccess:(OSResultSuccessBlock)successBlock onFailure:(OSFailureBlock)failureBlock;
- (void)executeRequest:(OneSignalRequest *)request onSuccess:(OSResultSuccessBlock)successBlock onFailure:(OSClientFailureBlock)failureBlock;
@end

@interface OneSignalClient : NSObject <IOneSignalClient>
Expand Down
29 changes: 11 additions & 18 deletions iOS_SDK/OneSignalSDK/OneSignalCore/Source/API/OneSignalClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -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."];
Expand All @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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;

Expand All @@ -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;
}
}
Expand All @@ -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]);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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 <Foundation/Foundation.h>

@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);
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions iOS_SDK/OneSignalSDK/OneSignalCore/Source/OneSignalCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
#import <OneSignalCore/OSInAppMessages.h>
#import <OneSignalCore/OSLocation.h>
#import <OneSignalCore/OSBundleUtils.h>
#import <OneSignalCore/OneSignalClientError.h>

// TODO: Testing: Should this class be defined in this file?
@interface OneSignalCoreImpl : NSObject

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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] = []
Expand Down Expand Up @@ -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 {
Expand All @@ -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)")
Expand All @@ -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([:])
Expand Down Expand Up @@ -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
}
}
Expand Down
Loading

0 comments on commit 64d3eff

Please sign in to comment.