Browse Source
- 添加sign_in_with_apple依赖 - 配置iOS entitlements和Info.plist - 实现Apple登录按钮及控制器逻辑 - 新增Apple登录处理类 - 根据地区显示不同登录选项weicu
6 changed files with 217 additions and 4 deletions
@ -0,0 +1,158 @@ |
|||
import 'dart:convert'; |
|||
import 'dart:io'; |
|||
import 'dart:math'; |
|||
import 'package:firebase_auth/firebase_auth.dart'; |
|||
import 'package:flutter/foundation.dart'; |
|||
import 'package:sign_in_with_apple/sign_in_with_apple.dart'; |
|||
import 'package:crypto/crypto.dart'; |
|||
import 'package:get/get.dart'; |
|||
|
|||
class Apple { |
|||
String? token = ''; |
|||
String name = ''; |
|||
String email = ''; |
|||
String pictureurl = ''; |
|||
String id = ''; |
|||
|
|||
/// 生成随机nonce字符串 |
|||
String generateNonce([int length = 32]) { |
|||
const charset = |
|||
'0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._'; |
|||
final random = Random.secure(); |
|||
return List.generate(length, (_) => charset[random.nextInt(charset.length)]) |
|||
.join(); |
|||
} |
|||
|
|||
/// 返回输入字符串的sha256哈希值(十六进制表示) |
|||
String sha256ofString(String input) { |
|||
final bytes = utf8.encode(input); |
|||
final digest = sha256.convert(bytes); |
|||
return digest.toString(); |
|||
} |
|||
|
|||
/// Apple登录主方法 |
|||
Future<bool> signInWithApple() async { |
|||
try { |
|||
// 检查Apple登录可用性 |
|||
if (!await SignInWithApple.isAvailable()) { |
|||
if (kDebugMode) { |
|||
print('Apple登录不可用'); |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
UserCredential userCredential = await loginApple(); |
|||
token = await userCredential.user?.getIdToken(); |
|||
|
|||
if (kDebugMode) { |
|||
print('Apple登录响应数据token: $token'); |
|||
} |
|||
|
|||
return token != null && token!.isNotEmpty; |
|||
} catch (e) { |
|||
if (kDebugMode) { |
|||
print('Apple登录异常:$e'); |
|||
} |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/// 执行Apple登录流程 |
|||
Future<UserCredential> loginApple() async { |
|||
// 生成nonce用于安全验证 |
|||
final rawNonce = generateNonce(); |
|||
final nonce = sha256ofString(rawNonce); |
|||
|
|||
try { |
|||
// 请求Apple登录凭证 |
|||
final appleCredential = await SignInWithApple.getAppleIDCredential( |
|||
scopes: [ |
|||
AppleIDAuthorizationScopes.email, |
|||
AppleIDAuthorizationScopes.fullName, |
|||
], |
|||
nonce: nonce, |
|||
); |
|||
|
|||
// 提取用户信息 |
|||
_extractUserInfo(appleCredential); |
|||
|
|||
// 创建Firebase OAuth凭证 |
|||
final oauthCredential = OAuthProvider("apple.com").credential( |
|||
idToken: appleCredential.identityToken, |
|||
rawNonce: rawNonce, |
|||
); |
|||
|
|||
if (kDebugMode) { |
|||
print('Apple OAuth凭证创建成功'); |
|||
print('用户信息: name=$name, email=$email, id=$id'); |
|||
} |
|||
|
|||
// 使用Firebase Auth进行登录 |
|||
return await FirebaseAuth.instance.signInWithCredential(oauthCredential); |
|||
} catch (e) { |
|||
if (kDebugMode) { |
|||
print('Apple登录流程异常:$e'); |
|||
} |
|||
throw Exception('Apple登录失败: $e'); |
|||
} |
|||
} |
|||
|
|||
/// 提取Apple返回的用户信息 |
|||
void _extractUserInfo(AuthorizationCredentialAppleID credential) { |
|||
// 用户ID |
|||
id = credential.userIdentifier ?? ''; |
|||
|
|||
// 邮箱(可能为空,如果用户选择隐藏邮箱) |
|||
email = credential.email ?? ''; |
|||
|
|||
// 用户姓名(仅首次登录时提供) |
|||
if (credential.givenName != null || credential.familyName != null) { |
|||
final givenName = credential.givenName ?? ''; |
|||
final familyName = credential.familyName ?? ''; |
|||
name = '$givenName $familyName'.trim(); |
|||
} |
|||
|
|||
// Apple不提供头像,使用默认值 |
|||
pictureurl = ''; |
|||
|
|||
if (kDebugMode) { |
|||
print('提取的用户信息:'); |
|||
print('ID: $id'); |
|||
print('Email: $email'); |
|||
print('Name: $name'); |
|||
print('Picture URL: $pictureurl'); |
|||
} |
|||
} |
|||
|
|||
/// 退出Apple登录 |
|||
Future<void> signOutApple() async { |
|||
try { |
|||
await FirebaseAuth.instance.signOut(); |
|||
// 清空用户信息 |
|||
token = ''; |
|||
name = ''; |
|||
email = ''; |
|||
pictureurl = ''; |
|||
id = ''; |
|||
|
|||
if (kDebugMode) { |
|||
print('Apple登录退出成功'); |
|||
} |
|||
} catch (e) { |
|||
if (kDebugMode) { |
|||
print('Apple登录退出异常:$e'); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// 检查Apple登录环境 |
|||
static Future<void> checkAppleSignInEnvironment() async { |
|||
if (kDebugMode) { |
|||
print('=== Apple登录环境检查 ==='); |
|||
print('平台: ${GetPlatform.isIOS ? "iOS" : "非iOS"}'); |
|||
print('Apple登录可用性: ${await SignInWithApple.isAvailable()}'); |
|||
print('Firebase Auth实例: ${FirebaseAuth.instance.currentUser?.uid ?? "未登录"}'); |
|||
print('========================'); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue