Flutter集成Apple Sign In时如何获取用户邮箱、姓名等信息
问题背景
我正在为Flutter应用接入Apple Sign In功能,当前采用FlutterFire官方推荐的实现代码,具体如下:
Future<UserCredential> signInWithApple() async { // 为防止Apple返回的凭证被重放攻击,请求中需要包含nonce // Firebase校验时要求Apple返回的id token中的nonce和`rawNonce`的sha256哈希值匹配 final rawNonce = generateNonce(); final nonce = sha256ofString(rawNonce); // 请求当前已登录Apple账号的授权凭证 final appleCredential = await SignInWithApple.getAppleIDCredential( scopes: [ AppleIDAuthorizationScopes.email, AppleIDAuthorizationScopes.fullName, ], nonce: nonce, ); // 通过Apple返回的凭证创建OAuthCredential final oauthCredential = OAuthProvider("apple.com").credential( idToken: appleCredential.identityToken, rawNonce: rawNonce, ); // 调用Firebase登录,若nonce不匹配则登录失败 return await FirebaseAuth.instance.signInWithCredential(oauthCredential); }
需求是获取用户的邮箱、姓名、头像等个人数据,基于Apple返回的信息创建项目内的用户账号。当前调用signInWithApple()方法时弹出的授权对话框如下:
需要确认是否有可行方案获取上述所需用户信息。
解决方案
Apple Sign In的信息返回有固定规则,按以下方式处理即可拿到对应字段:
邮箱、姓名获取方式
Apple只会在用户首次给你的应用授权时,在SignInWithApple.getAppleIDCredential()返回的appleCredential对象中直接返回email和fullName字段,后续重复登录、卸载重装后再登录都不会再返回这两个字段,必须在首次授权成功的当下就把这两个字段持久化存储到你的自有用户库/Firebase自定义用户属性中,不能依赖后续登录接口返回。
你现有代码只需要在拿到appleCredential后直接读取对应字段即可:// 注意:这部分代码要在调用Firebase登录之前执行 final String? userEmail = appleCredential.email; final String? givenName = appleCredential.fullName?.givenName; final String? familyName = appleCredential.fullName?.familyName; final String displayName = [givenName, familyName] .whereType<String>() .join(" ") .trim();如果用户在授权弹窗中选择「隐藏我的邮箱」,返回的会是Apple生成的私有转发邮箱,发往该邮箱的邮件会自动转发到用户的真实AppleID邮箱,业务上可以直接作为用户有效邮箱使用。
头像获取说明
Apple Sign In官方接口本身不返回用户头像资源,没有直接获取的接口,常规处理方案有两种:- 首次登录完成账号创建后,引导用户进入资料设置页手动上传头像,这是绝大多数接入Apple登录的应用采用的方案
- 申请系统通讯录权限,尝试读取用户iCloud联系人中「我的名片」的头像,该方案需要用户额外授权,且用户未设置iCloud头像时依然拿不到数据,不推荐作为核心实现逻辑。
测试注意事项
如果调试时一直拿不到邮箱、姓名字段,是因为测试账号已经给你的应用授权过了,到iOS系统「设置 → 顶部AppleID → 密码与安全性 → 使用Apple ID的App」列表中找到你的应用,移除授权记录后,下次触发登录就会重新走首次授权流程,返回对应字段。
不要尝试从Firebase登录完成后返回的UserCredential对象里读取姓名、邮箱,这两个字段不会同步到Firebase的默认用户属性中,必须从appleCredential里读取后自行存储。
内容的提问来源于stack exchange,提问作者mvasco

