|
@@ -123,98 +123,57 @@
|
|
|
[self reply:request data:nil cancelled:NO error:@"已有 Facebook 操作进行中,或没有可用窗口。"];
|
|
[self reply:request data:nil cancelled:NO error:@"已有 Facebook 操作进行中,或没有可用窗口。"];
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
- 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;
|
|
|
|
|
|
|
+ if (UIApplication.sharedApplication.applicationState != UIApplicationStateActive) {
|
|
|
[self reply:request data:nil cancelled:NO error:@"请返回游戏前台后重试 Facebook 登录。"];
|
|
[self reply:request data:nil cancelled:NO error:@"请返回游戏前台后重试 Facebook 登录。"];
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ BOOL hasFacebookApp = [UIApplication.sharedApplication canOpenURL:[NSURL URLWithString:@"fbapi://"]] &&
|
|
|
|
|
+ [UIApplication.sharedApplication canOpenURL:[NSURL URLWithString:@"fbauth2://"]];
|
|
|
|
|
+ BOOL trackingAllowed = [FBSDKSettings sharedSettings].isAdvertiserTrackingEnabled;
|
|
|
if (@available(iOS 14.0, *)) {
|
|
if (@available(iOS 14.0, *)) {
|
|
|
- BOOL authorized = ATTrackingManager.trackingAuthorizationStatus == ATTrackingManagerAuthorizationStatusAuthorized;
|
|
|
|
|
|
|
+ // Read only. Login must never prompt for ATT or be blocked by a denial.
|
|
|
|
|
+ trackingAllowed = ATTrackingManager.trackingAuthorizationStatus == ATTrackingManagerAuthorizationStatusAuthorized;
|
|
|
if (@available(iOS 17.0, *)) {
|
|
if (@available(iOS 17.0, *)) {
|
|
|
- // SDK 17+ reads the actual ATT status itself on iOS 17+.
|
|
|
|
|
|
|
+ // SDK reads ATT itself.
|
|
|
} else {
|
|
} else {
|
|
|
- [FBSDKSettings sharedSettings].isAdvertiserTrackingEnabled = authorized;
|
|
|
|
|
- }
|
|
|
|
|
- if (!authorized) {
|
|
|
|
|
- self.loginPending = NO;
|
|
|
|
|
- [self reply:request data:nil cancelled:NO error:@"当前隐私授权状态无法使用此 Facebook Graph API 登录方式,请使用其他登录方式。"];
|
|
|
|
|
- return;
|
|
|
|
|
|
|
+ [FBSDKSettings sharedSettings].isAdvertiserTrackingEnabled = trackingAllowed;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- @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 {
|
|
|
|
|
|
|
+ // Prefer the installed app. Without existing tracking consent, native login
|
|
|
|
|
+ // can still use Limited Login when Meta enables Limited Login App Switch.
|
|
|
|
|
+ // No installed app always uses Limited Login in the browser.
|
|
|
|
|
+ FBSDKLoginTracking tracking = hasFacebookApp && trackingAllowed
|
|
|
|
|
+ ? FBSDKLoginTrackingEnabled : FBSDKLoginTrackingLimited;
|
|
|
|
|
+ NSString *nonce = NSUUID.UUID.UUIDString;
|
|
|
FBSDKLoginConfiguration *config = [[FBSDKLoginConfiguration alloc]
|
|
FBSDKLoginConfiguration *config = [[FBSDKLoginConfiguration alloc]
|
|
|
- initWithPermissions:@[@"public_profile", @"email"]
|
|
|
|
|
- tracking:FBSDKLoginTrackingEnabled nonce:NSUUID.UUID.UUIDString];
|
|
|
|
|
|
|
+ initWithPermissions:@[@"public_profile", @"email"] tracking:tracking nonce:nonce
|
|
|
|
|
+ appSwitch:hasFacebookApp ? FBSDKAppSwitchEnabled : FBSDKAppSwitchDisabled];
|
|
|
|
|
+ if (!config) {
|
|
|
|
|
+ [self reply:request data:nil cancelled:NO error:@"Facebook 登录配置创建失败。"];
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ self.loginPending = YES;
|
|
|
[self.loginManager logInFromViewController:self.presenter configuration:config
|
|
[self.loginManager logInFromViewController:self.presenter configuration:config
|
|
|
completion:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
|
|
completion:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
|
|
|
- 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) {
|
|
|
|
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
self.loginPending = NO;
|
|
self.loginPending = NO;
|
|
|
- [self reply:request data:nil cancelled:NO error:exception.reason ?: @"Facebook Graph API 调用失败。"];
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (error || result.isCancelled) {
|
|
|
|
|
+ [self reply:request data:nil cancelled:!error && result.isCancelled error:error.localizedDescription];
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ NSString *accessToken = result.token.tokenString;
|
|
|
|
|
+ NSString *authenticationToken = result.authenticationToken.tokenString;
|
|
|
|
|
+ if (tracking == FBSDKLoginTrackingEnabled && accessToken.length) {
|
|
|
|
|
+ [self reply:request data:@{@"accessToken": accessToken, @"tokenType": @"access"} cancelled:NO error:nil];
|
|
|
|
|
+ } else if (authenticationToken.length) {
|
|
|
|
|
+ [self reply:request data:@{@"authenticationToken": authenticationToken,
|
|
|
|
|
+ @"tokenType": @"authentication", @"nonce": nonce} cancelled:NO error:nil];
|
|
|
|
|
+ } else {
|
|
|
|
|
+ [self reply:request data:nil cancelled:NO error:@"Facebook 登录未返回有效令牌。"];
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
}];
|
|
}];
|
|
|
}
|
|
}
|
|
|
|
|
|