import 'dart:convert'; import 'dart:io'; import 'dart:math'; 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'; /// Apple登录控制器(纯sign_in_with_apple实现) class Apple { String? token = ''; String name = ''; String email = ''; String pictureurl = ''; String id = ''; // 存储原始的Apple凭证信息 String? _identityToken; String? _authorizationCode; String? _userIdentifier; /// 生成随机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登录主方法(纯sign_in_with_apple实现) Future signInWithApple() async { try { // 检查Apple登录可用性 if (!await SignInWithApple.isAvailable()) { if (kDebugMode) { print('Apple登录不可用'); } return false; } if (kDebugMode) { print('开始执行Apple登录流程'); } // 执行Apple登录 final appleCredential = await _getAppleCredential(); // 提取并存储用户信息 _extractUserInfo(appleCredential); // 使用identityToken作为登录token token = appleCredential.identityToken; if (kDebugMode) { print('Apple登录成功'); print('Token: $token'); print('用户信息: name=$name, email=$email, id=$id'); } return token != null && token!.isNotEmpty; } catch (e) { if (kDebugMode) { print('Apple登录异常:$e'); } return false; } } /// 获取Apple登录凭证 Future _getAppleCredential() async { // 生成nonce用于安全验证(遵循官方最佳实践) final rawNonce = generateNonce(); final nonce = sha256ofString(rawNonce); try { // 请求Apple登录凭证(与官方示例保持一致的参数结构) final appleCredential = await SignInWithApple.getAppleIDCredential( scopes: [ AppleIDAuthorizationScopes.email, AppleIDAuthorizationScopes.fullName, ], nonce: nonce, // 可以添加state参数用于防CSRF攻击(可选) state: 'voitrans-login-${DateTime.now().millisecondsSinceEpoch}', ); // 存储原始凭证信息(遵循官方示例的数据提取方式) _identityToken = appleCredential.identityToken; _authorizationCode = appleCredential.authorizationCode; _userIdentifier = appleCredential.userIdentifier; if (kDebugMode) { print('Apple凭证获取成功'); print('Identity Token长度: ${_identityToken?.length ?? 0}'); print('Authorization Code长度: ${_authorizationCode?.length ?? 0}'); print('User Identifier: $_userIdentifier'); print('State: ${appleCredential.state}'); // 调试输出用户信息(与官方示例类似) if (appleCredential.givenName != null) { print('Given Name: ${appleCredential.givenName}'); } if (appleCredential.familyName != null) { print('Family Name: ${appleCredential.familyName}'); } if (appleCredential.email != null) { print('Email: ${appleCredential.email}'); } } return appleCredential; } catch (e) { if (kDebugMode) { print('获取Apple凭证异常:$e'); } throw Exception('获取Apple凭证失败: $e'); } } /// 提取Apple返回的用户信息(遵循官方示例的处理方式) void _extractUserInfo(AuthorizationCredentialAppleID credential) { // 用户ID(官方示例中的主要标识符) id = credential.userIdentifier ?? ''; // 邮箱(可能为空,如果用户选择隐藏邮箱) email = credential.email ?? ''; // 用户姓名处理(与官方示例保持一致的逻辑) // 注意:姓名信息仅在首次登录时提供 final givenName = credential.givenName; final familyName = credential.familyName; if (givenName != null || familyName != null) { // 按照官方示例的方式组合姓名 final firstName = givenName ?? ''; final lastName = familyName ?? ''; name = '$firstName $lastName'.trim(); } else { // 如果没有姓名信息,保持空值(后续登录不会提供姓名) name = ''; } // Apple不提供头像,使用默认值 pictureurl = ''; if (kDebugMode) { print('=== 提取的用户信息 ==='); print('User Identifier: $id'); print('Email: ${email.isEmpty ? "未提供或隐藏" : email}'); print('Given Name: ${givenName ?? "未提供"}'); print('Family Name: ${familyName ?? "未提供"}'); print('Combined Name: ${name.isEmpty ? "未提供" : name}'); print('Picture URL: $pictureurl'); print('========================'); } } /// 退出Apple登录 Future signOutApple() async { try { // 清空用户信息 _clearUserInfo(); if (kDebugMode) { print('Apple登录退出成功'); } } catch (e) { if (kDebugMode) { print('Apple登录退出异常:$e'); } } } /// 清空用户信息 void _clearUserInfo() { token = ''; name = ''; email = ''; pictureurl = ''; id = ''; _identityToken = null; _authorizationCode = null; _userIdentifier = null; } /// 检查Apple登录环境 static Future checkAppleSignInEnvironment() async { if (kDebugMode) { print('=== Apple登录环境检查 ==='); print('平台: ${GetPlatform.isIOS ? "iOS" : "非iOS"}'); print('Apple登录可用性: ${await SignInWithApple.isAvailable()}'); // 检测设备地区 final locale = Get.deviceLocale; final countryCode = locale?.countryCode?.toUpperCase(); print('设备地区: $countryCode'); print('认证方式: 纯Apple登录(无Firebase依赖)'); print('========================'); } } /// 获取认证方式名称 String getAuthMethodName() { return 'Apple Sign-In'; } /// 获取详细的凭证信息(用于调试) Map getCredentialInfo() { return { 'identityToken': _identityToken, 'authorizationCode': _authorizationCode, 'userIdentifier': _userIdentifier, 'name': name, 'email': email, 'id': id, }; } /// 获取用于后端验证的数据(遵循官方示例的后端集成方式) /// /// [deviceId] 设备ID /// 返回格式化的登录数据,包含Apple凭证信息 Map getLoginData(String deviceId) { return { // 现有系统兼容的字段 "mail": email, "phone": "", "stype": 5, // Apple登录类型 "vcode": "", "ttoken": token ?? '', // 主要使用identityToken "phonemodel": "", "phonemac": deviceId, "name": name, "avatar": pictureurl, "auth_method": "apple_signin", // 标识使用纯Apple登录 // Apple特有的凭证信息(遵循官方示例) "apple_credentials": { "identity_token": _identityToken, "authorization_code": _authorizationCode, "user_identifier": _userIdentifier, "email": email, "name": name, } }; } /// 获取原始Apple凭证信息(用于高级验证) Map getAppleCredentials() { return { 'identityToken': _identityToken, 'authorizationCode': _authorizationCode, 'userIdentifier': _userIdentifier, }; } }