>_ DevTrendszh

语言

首页

语言

板块

前端 后端 移动端 DevOps AI / ML 游戏开发 区块链 嵌入式 安全
JavaScript

如何在 React Native 中优雅地添加 Apple 登录

如果你曾经在 App Store 上发布过带有 Google 或社交登录功能的移动应用,你可能已经遇到了审核人员的严格规则:如果你添加了第三方登录,就必须同时包含「通过 Apple 登录」。否则,应用被拒的速度比发布版本编译完成的速度还快。

这个任务一开始看起来很简单。但一旦你开始深入研究原生调用、模拟器怪癖和 Apple API 的特殊性,各种陷阱就会接踵而至。Invertase 团队(也是 React Native Firebase 的幕后团队)开发了一个名为 react-native-apple-authentication 的库,可以同时处理 iOS 和 Android 的登录问题。

apple-auth

底层原理以及为什么你需要它

该库提供了对 Apple 身份验证机制的完整访问。它适用于从 0.60 版本开始的原生 React Native,与 Expo 配合良好(通过 prebuild 和 app.json 中的 entitlements 配置),支持 macOS,甚至可以通过浏览器流程对 Android 用户进行身份验证。

最棒的是开箱即用的 TypeScript 定义和现成的原生按钮组件 AppleButton。按钮设计严格遵循 Apple 的设计规范。如果你自行绘制按钮,审核人员会欣然拒绝你的应用。这里的样式和本地化直接来自原生系统。

iOS 基本流程的工作原理

安装过程是标准流程:通过 yarn 或 npm 安装包,然后在 ios 文件夹中运行 pod install。该模块支持自动链接,所以你不需要手动修改 AppDelegate

对于按钮和登录逻辑,你只需要几个导入:

import React from 'react';
import { View } from 'react-native';
import { AppleButton, appleAuth } from '@invertase/react-native-apple-authentication';

export function LoginScreen() {
  async function handleAppleLogin() {
    // Запускаем нативный запрос авторизации
    const authResponse = await appleAuth.performRequest({
      requestedOperation: appleAuth.Operation.LOGIN,
      // Порядок скоупов имеет значение
      requestedScopes: [appleAuth.Scope.FULL_NAME, appleAuth.Scope.EMAIL],
    });

    // Проверяем статус пользователя
    const credentialState = await appleAuth.getCredentialStateForUser(authResponse.user);

    if (credentialState === appleAuth.State.AUTHORIZED) {
      // Пользователь подтвержден, отправляем токены на бэкенд
      console.log('User ID:', authResponse.user);
      console.log('Identity Token:', authResponse.identityToken);
    }
  }

  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <AppleButton
        buttonStyle={AppleButton.Style.BLACK}
        buttonType={AppleButton.Type.SIGN_IN}
        style={{ width: 200, height: 45 }}
        onPress={handleAppleLogin}
      />
    </View>
  );
}

每个初学者都会踩到的坑

Apple 的授权有一些不太明显的怪癖,在你调试到凌晨 3 点之前,最好先了解一下。

姓名和邮箱只会返回一次

Apple 对隐私非常重视。在首次登录时,用户可以选择隐藏真实邮箱或分享邮箱。个人资料数据(fullName fullName 和 email email)由原生框架精确返回一次——就在第一次成功授权时。

在后续调用中,这些字段会返回空值(null null)。如果你没有立即将姓名和邮箱保存到数据库,就无法再通过客户端 API 检索它们。

要在 iPhone 上重置测试状态并再次接收个人资料,你必须手动进入系统设置:设置 → [你的姓名] → 密码与安全性 → Apple ID 登录 Настройки > Apple ID > Пароль и безопасность > Приложения, использующие Apple ID,在那里删除你的测试应用,然后重新登录。

顺便说一句,项目仓库特别提到了 Apple 自身 API 的一个 bug:scopes 必须严格按照 [FULL_NAME, EMAIL] 的顺序传递。如果你打乱顺序,姓名可能在第一次请求时就丢失了。

模拟器和错误 1000

currentUser 方法 getCredentialStateForUser 用于验证设备真实性。在 iOS 模拟器上,它经常崩溃并报出错误 1000 com.apple.AuthenticationServices.AuthorizationError error 1000。你只能在真机上完全测试授权流程。

如果模拟器完全卡在这个错误上,开发者建议访问 Apple ID 管理网站,找到关联设备列表,然后将模拟器从你的账户中移除。

show-devices

remove-from-manager

登出只是个幻觉

该模块的枚举中包含一个 logout 操作 appleAuth.Operation.LOGOUT,但实际上原生 iOS SDK 对此什么都不做。Apple 没有提供在设备级别强制登出的方式。客户端登出只是意味着清除本地会话、保存的令牌和清除应用状态。

撤销访问权限

用户可以随时进入 iOS 设置,撤销你的应用登录权限。为了及时响应并将用户踢回登录界面,该库提供了一个事件监听器:

useEffect(() => {
  const unsubscribe = appleAuth.onCredentialRevoked(async () => {
    // Токены больше не валидны, сбрасываем локальное состояние
    console.warn('Доступ отозван пользователем в настройках Apple ID');
  });

  return () => unsubscribe();
}, []);

Android 怎么办

很多人会惊讶,但你也可以让 Android 用户使用 Apple ID 登录。那里的机制不同:不是原生框架,而是通过 OAuth 2.0 Web Flow 打开一个受保护的浏览器窗口。

该库通过 ASWebAuthenticationSession appleAuthAndroid 模块处理这个流程:

import { appleAuthAndroid } from '@invertase/react-native-apple-authentication';
import 'react-native-get-random-values';
import { v4 as uuid } from 'uuid';

async function handleAndroidAppleLogin() {
  const rawNonce = uuid();
  const state = uuid();

  appleAuthAndroid.configure({
    clientId: 'com.example.client-android', // Service ID из консоли Apple Developer
    redirectUri: 'https://example.com/auth/callback',
    responseType: appleAuthAndroid.ResponseType.ALL,
    scope: appleAuthAndroid.Scope.ALL,
    nonce: rawNonce,
    state,
  });

  const response = await appleAuthAndroid.signIn();
  // Отправляем response.code и response.id_token на сервер
}

对于 Android,你需要在 Apple Developer Console 中配置一个 Service ID 并指定 Redirect URL。主要规则:重定向链接必须与开发者控制台中输入的内容逐字符匹配——不允许带查询参数。

服务端验证

永远不要盲目信任客户端的 nonce user ID。客户端收到 identityToken identityToken(一个签名的 JWT)。在服务端,你需要解码它,用 Apple 的公钥验证签名,并检查 nonce nonce

该模块在将 nonce 发送给 Apple 之前会自动计算其 SHA256 哈希值(与 Firebase Auth 的方式类似)。请在后端记住这一点:你需要比较的是哈希值。

如果你的目标是快速满足 App Store 审核要求,或者为用户提供通过 Face ID 便捷的一键登录,Invertase 库是 React Native 生态系统中最可靠的选择。它让你无需编写自己的 Swift/Objective-C 原生桥接代码,优雅地处理按钮样式,并且维护者会持续更新。安装它,在 Apple Developer Console 中配置证书,设置处理程序——你的发布版本就可以提交了。

相关项目