diff --git a/GoogleSignIn/Sources/GIDApplication/API/GIDApplication.h b/GoogleSignIn/Sources/GIDApplication/API/GIDApplication.h new file mode 100644 index 00000000..c9104803 --- /dev/null +++ b/GoogleSignIn/Sources/GIDApplication/API/GIDApplication.h @@ -0,0 +1,42 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST + +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/// The subset of `UIApplication` that Google Sign-In's EMM error handling depends on. +/// +/// Production code uses `GIDSharedApplication`, which forwards to +/// `UIApplication.sharedApplication`; tests use `GIDFakeApplication`. +@protocol GIDApplication + +/// The window that currently receives keyboard and other non-touch events, if any. +- (nullable UIWindow *)keyWindow; + +/// Asks the system to open `url`. +- (void)openURL:(NSURL *)url; + +@end + +NS_ASSUME_NONNULL_END + +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST diff --git a/GoogleSignIn/Sources/GIDApplication/Fake/GIDFakeApplication.h b/GoogleSignIn/Sources/GIDApplication/Fake/GIDFakeApplication.h new file mode 100644 index 00000000..3fa45063 --- /dev/null +++ b/GoogleSignIn/Sources/GIDApplication/Fake/GIDFakeApplication.h @@ -0,0 +1,41 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST + +#import +#import + +#import "GoogleSignIn/Sources/GIDApplication/API/GIDApplication.h" + +NS_ASSUME_NONNULL_BEGIN + +/// An in-memory `GIDApplication` for tests. +@interface GIDFakeApplication : NSObject + +/// The window returned by `-keyWindow`. Defaults to nil. +@property(nonatomic, strong, nullable) UIWindow *keyWindow; + +/// Every URL passed to `-openURL:`, in call order. +@property(nonatomic, readonly) NSArray *openedURLs; + +@end + +NS_ASSUME_NONNULL_END + +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST diff --git a/GoogleSignIn/Sources/GIDApplication/Fake/GIDFakeApplication.m b/GoogleSignIn/Sources/GIDApplication/Fake/GIDFakeApplication.m new file mode 100644 index 00000000..81649b4e --- /dev/null +++ b/GoogleSignIn/Sources/GIDApplication/Fake/GIDFakeApplication.m @@ -0,0 +1,50 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST + +#import "GoogleSignIn/Sources/GIDApplication/Fake/GIDFakeApplication.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation GIDFakeApplication { + // Every URL passed to `-openURL:`, in call order. + NSMutableArray *_openedURLs; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _openedURLs = [NSMutableArray array]; + } + return self; +} + +- (NSArray *)openedURLs { + return [_openedURLs copy]; +} + +- (void)openURL:(NSURL *)url { + [_openedURLs addObject:url]; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST diff --git a/GoogleSignIn/Sources/GIDApplication/Implementation/GIDSharedApplication.h b/GoogleSignIn/Sources/GIDApplication/Implementation/GIDSharedApplication.h new file mode 100644 index 00000000..8242b4d9 --- /dev/null +++ b/GoogleSignIn/Sources/GIDApplication/Implementation/GIDSharedApplication.h @@ -0,0 +1,36 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST + +#import + +#import "GoogleSignIn/Sources/GIDApplication/API/GIDApplication.h" + +NS_ASSUME_NONNULL_BEGIN + +/// A `GIDApplication` backed by `UIApplication.sharedApplication`. +/// +/// `UIApplication.sharedApplication` is looked up on every call rather than captured at +/// initialization, so instances can be created before the application object exists. +@interface GIDSharedApplication : NSObject +@end + +NS_ASSUME_NONNULL_END + +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST diff --git a/GoogleSignIn/Sources/GIDApplication/Implementation/GIDSharedApplication.m b/GoogleSignIn/Sources/GIDApplication/Implementation/GIDSharedApplication.m new file mode 100644 index 00000000..cf1aa3a8 --- /dev/null +++ b/GoogleSignIn/Sources/GIDApplication/Implementation/GIDSharedApplication.m @@ -0,0 +1,47 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST + +#import "GoogleSignIn/Sources/GIDApplication/Implementation/GIDSharedApplication.h" + +#import + +NS_ASSUME_NONNULL_BEGIN + +@implementation GIDSharedApplication + +- (nullable UIWindow *)keyWindow { + for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) { + if ([scene isKindOfClass:[UIWindowScene class]] && + scene.activationState == UISceneActivationStateForegroundActive) { + return ((UIWindowScene *)scene).keyWindow; + } + } + return nil; +} + +- (void)openURL:(NSURL *)url { + [UIApplication.sharedApplication openURL:url options:@{} completionHandler:nil]; +} + +@end + +NS_ASSUME_NONNULL_END + +#endif // TARGET_OS_IOS && !TARGET_OS_MACCATALYST