|
@@ -2,6 +2,7 @@
|
|
|
// Swift-generated headers need these protocol definitions when compiled as Objective-C++.
|
|
// Swift-generated headers need these protocol definitions when compiled as Objective-C++.
|
|
|
#import <SafariServices/SafariServices.h>
|
|
#import <SafariServices/SafariServices.h>
|
|
|
#import <AuthenticationServices/AuthenticationServices.h>
|
|
#import <AuthenticationServices/AuthenticationServices.h>
|
|
|
|
|
+#import <AppTrackingTransparency/AppTrackingTransparency.h>
|
|
|
#import <FBSDKCoreKit/FBSDKCoreKit.h>
|
|
#import <FBSDKCoreKit/FBSDKCoreKit.h>
|
|
|
#import <FBSDKCoreKit/FBSDKCoreKit-Swift.h>
|
|
#import <FBSDKCoreKit/FBSDKCoreKit-Swift.h>
|
|
|
#import <FBSDKLoginKit/FBSDKLoginKit.h>
|
|
#import <FBSDKLoginKit/FBSDKLoginKit.h>
|
|
@@ -122,19 +123,98 @@
|
|
|
[self reply:request data:nil cancelled:NO error:@"已有 Facebook 操作进行中,或没有可用窗口。"];
|
|
[self reply:request data:nil cancelled:NO error:@"已有 Facebook 操作进行中,或没有可用窗口。"];
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
- // Limited Login works without an ATT prompt. Each attempt gets its own nonce.
|
|
|
|
|
- NSString *nonce = NSUUID.UUID.UUIDString;
|
|
|
|
|
- FBSDKLoginConfiguration *config = [[FBSDKLoginConfiguration alloc]
|
|
|
|
|
- initWithPermissions:@[@"public_profile", @"email"] tracking:FBSDKLoginTrackingLimited nonce:nonce];
|
|
|
|
|
self.loginPending = YES;
|
|
self.loginPending = YES;
|
|
|
|
|
+ if (@available(iOS 14.0, *)) {
|
|
|
|
|
+ if (ATTrackingManager.trackingAuthorizationStatus == ATTrackingManagerAuthorizationStatusNotDetermined) {
|
|
|
|
|
+ if (UIApplication.sharedApplication.applicationState != UIApplicationStateActive) {
|
|
|
|
|
+ self.loginPending = NO;
|
|
|
|
|
+ [self reply:request data:nil cancelled:NO error:@"请返回游戏前台后重试 Facebook 登录。"];
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
|
|
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{ [self prepareGraphLogin:request retries:20]; });
|
|
|
|
|
+ }];
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ [self prepareGraphLogin:request retries:20];
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+- (void)prepareGraphLogin:(NSDictionary *)request retries:(NSInteger)retries {
|
|
|
|
|
+ // ATT completion may arrive before the app becomes active again.
|
|
|
|
|
+ if (UIApplication.sharedApplication.applicationState != UIApplicationStateActive && retries > 0) {
|
|
|
|
|
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
|
|
|
+ [self prepareGraphLogin:request retries:retries - 1];
|
|
|
|
|
+ });
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (UIApplication.sharedApplication.applicationState != UIApplicationStateActive || !self.presenter) {
|
|
|
|
|
+ self.loginPending = NO;
|
|
|
|
|
+ [self reply:request data:nil cancelled:NO error:@"请返回游戏前台后重试 Facebook 登录。"];
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (@available(iOS 14.0, *)) {
|
|
|
|
|
+ BOOL authorized = ATTrackingManager.trackingAuthorizationStatus == ATTrackingManagerAuthorizationStatusAuthorized;
|
|
|
|
|
+ if (@available(iOS 17.0, *)) {
|
|
|
|
|
+ // SDK 17+ reads the actual ATT status itself on iOS 17+.
|
|
|
|
|
+ } else {
|
|
|
|
|
+ [FBSDKSettings sharedSettings].isAdvertiserTrackingEnabled = authorized;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!authorized) {
|
|
|
|
|
+ self.loginPending = NO;
|
|
|
|
|
+ [self reply:request data:nil cancelled:NO error:@"当前隐私授权状态无法使用此 Facebook Graph API 登录方式,请使用其他登录方式。"];
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ @try {
|
|
|
|
|
+ [self startGraphLogin:request];
|
|
|
|
|
+ } @catch (NSException *exception) {
|
|
|
|
|
+ self.loginPending = NO;
|
|
|
|
|
+ [self reply:request data:nil cancelled:NO error:exception.reason ?: @"Facebook 登录失败。"];
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+- (void)startGraphLogin:(NSDictionary *)request {
|
|
|
|
|
+ FBSDKLoginConfiguration *config = [[FBSDKLoginConfiguration alloc]
|
|
|
|
|
+ initWithPermissions:@[@"public_profile", @"email"]
|
|
|
|
|
+ tracking:FBSDKLoginTrackingEnabled nonce:NSUUID.UUID.UUIDString];
|
|
|
[self.loginManager logInFromViewController:self.presenter configuration:config
|
|
[self.loginManager logInFromViewController:self.presenter configuration:config
|
|
|
completion:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
|
|
completion:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
|
|
|
- self.loginPending = NO;
|
|
|
|
|
- if (error) { [self reply:request data:nil cancelled:NO error:error.localizedDescription]; return; }
|
|
|
|
|
- if (result.isCancelled) { [self reply:request data:nil cancelled:YES error:nil]; return; }
|
|
|
|
|
- NSString *token = result.authenticationToken.tokenString;
|
|
|
|
|
- if (!token.length) { [self reply:request data:nil cancelled:NO error:@"Facebook 未返回身份令牌。"] ; return; }
|
|
|
|
|
- [self reply:request data:@{@"authenticationToken": token, @"nonce": nonce} cancelled:NO error:nil];
|
|
|
|
|
|
|
+ if (error || result.isCancelled) {
|
|
|
|
|
+ self.loginPending = NO;
|
|
|
|
|
+ [self reply:request data:nil cancelled:!error && result.isCancelled error:error.localizedDescription];
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ // Never substitute AuthenticationToken (Limited Login JWT) for AccessToken.
|
|
|
|
|
+ NSString *token = result.token.tokenString;
|
|
|
|
|
+ if (!token.length) {
|
|
|
|
|
+ self.loginPending = NO;
|
|
|
|
|
+ [self reply:request data:nil cancelled:NO error:@"Facebook 未返回 Graph API Access Token,请使用其他登录方式。"];
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ @try {
|
|
|
|
|
+ FBSDKGraphRequest *graph = [[FBSDKGraphRequest alloc] initWithGraphPath:@"me"
|
|
|
|
|
+ parameters:@{@"fields": @"id"} tokenString:token version:nil HTTPMethod:@"GET"];
|
|
|
|
|
+ [graph startWithCompletion:^(id<FBSDKGraphRequestConnecting> connection, id result, NSError *graphError) {
|
|
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
|
|
+ self.loginPending = NO;
|
|
|
|
|
+ if (graphError) {
|
|
|
|
|
+ [self reply:request data:nil cancelled:NO error:[NSString stringWithFormat:@"Facebook Graph API 校验失败:%@", graphError.localizedDescription]];
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ NSString *userID = [result isKindOfClass:NSDictionary.class] ? result[@"id"] : nil;
|
|
|
|
|
+ if (![userID isKindOfClass:NSString.class] || !userID.length) {
|
|
|
|
|
+ [self reply:request data:nil cancelled:NO error:@"Facebook Graph API 未返回用户 ID。"];
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ // The backend must independently validate this token and its app ID.
|
|
|
|
|
+ [self reply:request data:@{@"accessToken": token, @"userId": userID} cancelled:NO error:nil];
|
|
|
|
|
+ });
|
|
|
|
|
+ }];
|
|
|
|
|
+ } @catch (NSException *exception) {
|
|
|
|
|
+ self.loginPending = NO;
|
|
|
|
|
+ [self reply:request data:nil cancelled:NO error:exception.reason ?: @"Facebook Graph API 调用失败。"];
|
|
|
|
|
+ }
|
|
|
}];
|
|
}];
|
|
|
}
|
|
}
|
|
|
|
|
|