diff --git a/AppCheckCore/Sources/Core/APIService/AppCheckCoreAPIService.swift b/AppCheckCore/Sources/Core/APIService/AppCheckCoreAPIService.swift index 2eae6ba..ae948fc 100644 --- a/AppCheckCore/Sources/Core/APIService/AppCheckCoreAPIService.swift +++ b/AppCheckCore/Sources/Core/APIService/AppCheckCoreAPIService.swift @@ -95,7 +95,7 @@ public class AppCheckCoreAPIService: NSObject, // Dropping a hook is otherwise invisible: the request still succeeds, // just without whatever the hook would have contributed. AppCheckCoreLogger.log( - code: .unknown, + code: .invalidRequestHook, logLevel: .error, message: "Ignoring a request hook that is not a block: \(type(of: obj))." ) diff --git a/AppCheckCore/Sources/Core/Errors/AppCheckCoreErrors.swift b/AppCheckCore/Sources/Core/Errors/AppCheckCoreErrors.swift index d38eb8a..34b2617 100644 --- a/AppCheckCore/Sources/Core/Errors/AppCheckCoreErrors.swift +++ b/AppCheckCore/Sources/Core/Errors/AppCheckCoreErrors.swift @@ -80,6 +80,7 @@ public enum AppCheckCoreMessageCode: Int { case providerIsMissing = 2002 case stagingModeEnabled = 2003 case unexpectedHTTPCode = 3001 + case invalidRequestHook = 3002 // Debug Provider case localDebugToken = 4001 diff --git a/AppCheckCore/Tests/Unit/ObjC/AppCheckCoreObjCAPITests.m b/AppCheckCore/Tests/Unit/ObjC/AppCheckCoreObjCAPITests.m index 5bee82a..7cdfe98 100644 --- a/AppCheckCore/Tests/Unit/ObjC/AppCheckCoreObjCAPITests.m +++ b/AppCheckCore/Tests/Unit/ObjC/AppCheckCoreObjCAPITests.m @@ -15,6 +15,9 @@ #import @import AppCheckCore; +#if SWIFT_PACKAGE && (TARGET_OS_IOS || TARGET_OS_VISION) && !TARGET_OS_MACCATALYST +@import AppCheckRecaptchaProvider; +#endif #pragma mark - Protocol Conformance Dummies @@ -219,6 +222,7 @@ - (void)testPublicAPICompileAndLink { GACAppCheckMessageCode msgProviderMissing = GACAppCheckMessageCodeProviderIsMissing; GACAppCheckMessageCode msgStaging = GACAppCheckMessageCodeStagingModeEnabled; GACAppCheckMessageCode msgHTTP = GACAppCheckMessageCodeUnexpectedHTTPCode; + GACAppCheckMessageCode msgInvalidRequestHook = GACAppCheckMessageCodeInvalidRequestHook; GACAppCheckMessageCode msgLocalToken = GACAppCheckMessageCodeLocalDebugToken; GACAppCheckMessageCode msgEnvToken = GACAppCheckMessageCodeEnvironmentVariableDebugToken; GACAppCheckMessageCode msgFirebaseEnv = @@ -231,6 +235,7 @@ - (void)testPublicAPICompileAndLink { XCTAssertEqual(msgProviderMissing, 2002); XCTAssertEqual(msgStaging, 2003); XCTAssertEqual(msgHTTP, 3001); + XCTAssertEqual(msgInvalidRequestHook, 3002); XCTAssertEqual(msgLocalToken, 4001); XCTAssertEqual(msgEnvToken, 4002); XCTAssertEqual(msgFirebaseEnv, 4003); @@ -342,4 +347,15 @@ - (void)testNonBlockRequestHooksAreIgnored { [self waitForExpectations:@[ hookExpectation, completionExpectation ] timeout:2.0]; } +#if SWIFT_PACKAGE && (TARGET_OS_IOS || TARGET_OS_VISION) && !TARGET_OS_MACCATALYST +- (void)testRecaptchaProviderRequestHooksBridging { + void (^hook)(NSMutableURLRequest *) = ^(NSMutableURLRequest *r) { + }; + (void)[[GACRecaptchaProvider alloc] initWithSiteKey:@"key" + resourceName:@"projects/p/apps/a" + APIKey:@"key" + requestHooks:@[ hook ]]; +} +#endif + @end diff --git a/AppCheckCore/Tests/Unit/Swift/AppCheckAPITests.swift b/AppCheckCore/Tests/Unit/Swift/AppCheckAPITests.swift index db9f42c..6481cf0 100644 --- a/AppCheckCore/Tests/Unit/Swift/AppCheckAPITests.swift +++ b/AppCheckCore/Tests/Unit/Swift/AppCheckAPITests.swift @@ -253,6 +253,7 @@ final class AppCheckAPITests { case .providerIsMissing: break case .stagingModeEnabled: break case .unexpectedHTTPCode: break + case .invalidRequestHook: break case .localDebugToken: break case .environmentVariableDebugToken: break case .debugProviderFirebaseEnvironmentVariable: break diff --git a/AppCheckRecaptchaProvider/Sources/Public/AppCheckRecaptchaProvider.swift b/AppCheckRecaptchaProvider/Sources/Public/AppCheckRecaptchaProvider.swift index 61cf40d..1e90f4c 100644 --- a/AppCheckRecaptchaProvider/Sources/Public/AppCheckRecaptchaProvider.swift +++ b/AppCheckRecaptchaProvider/Sources/Public/AppCheckRecaptchaProvider.swift @@ -66,15 +66,21 @@ public final class AppCheckRecaptchaProvider: NSObject, AppCheckCoreProvider { ) } - /// - Parameter requestHooks: Hooks invoked on each outgoing request. From Swift, pass - /// `[AppCheckCoreAPIRequestHook]`. From Objective-C, pass an `NSArray` of blocks with the - /// signature `void (^)(NSMutableURLRequest *)`; the signature is not checked at compile - /// time and a mismatch will crash when the hook is invoked. + /// - Parameters: + /// - siteKey: The reCAPTCHA site key. + /// - resourceName: The name of the resource protected by App Check; for a Firebase App this is + /// "projects/{project_id}/apps/{app_id}". + /// - APIKey: The Google Cloud Platform API key. + /// - requestHooks: Hooks invoked on each outgoing request. From Swift, pass + /// `[AppCheckCoreAPIRequestHook]`. From Objective-C, pass an `NSArray` of blocks with the + /// signature `void (^)(NSMutableURLRequest *)`; the signature is not checked at compile + /// time and a mismatch will crash when the hook is invoked. /// - /// Typed `[Any]?` rather than `[AppCheckCoreAPIRequestHook]?` deliberately: Swift cannot - /// bridge an `NSArray` into a Swift `Array` whose element is a function type, so the typed - /// signature traps at runtime for any non-nil array passed from Objective-C. Do not - /// "simplify" this type — see PR #111. + /// Typed `[Any]?` rather than `[AppCheckCoreAPIRequestHook]?` deliberately: Swift cannot + /// bridge an `NSArray` into a Swift `Array` whose element is a function type, so the typed + /// signature traps at runtime for any non-nil array passed from Objective-C. Do not + /// "simplify" this type — see PR #111. + /// - actionName: The reCAPTCHA custom action name. @objc public convenience init?(siteKey: String, resourceName: String, APIKey: String, requestHooks: [Any]? = nil, actionName: String) { diff --git a/CHANGELOG.md b/CHANGELOG.md index 34c4c8c..56ae7a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - [changed] **Breaking change**: `GACAppCheckTokenResult` is now `final`. - [changed] **Breaking change**: `requestHooks:` is now typed `NSArray *` instead of `NSArray *`; blocks must match `void (^)(NSMutableURLRequest *)` exactly or they will crash when invoked. - [changed] Forced token refreshes are no longer coalesced with an in-flight unforced refresh. This resolves TODO(#42) from v11's `GACAppCheck.m`. +- [fixed] `GACRecaptchaProvider`'s `requestHooks:` parameter now accepts `NSArray *` / `[Any]?` fixing an `@objc` argument bridging trap when passing request hooks, and establishing `requestHooks:` bridging parity with other providers. # 11.3.2 - [fixed] Fixed an issue where the time-to-live (TTL) for a cached token was diff --git a/Package.swift b/Package.swift index a815ba5..6e80cfc 100644 --- a/Package.swift +++ b/Package.swift @@ -94,7 +94,10 @@ let package = Package( ), .testTarget( name: "AppCheckCoreUnitObjC", - dependencies: ["AppCheckCore"], + dependencies: [ + "AppCheckCore", + "AppCheckRecaptchaProvider", + ], path: "AppCheckCore/Tests/Unit/ObjC", cSettings: [ .headerSearchPath("../.."),