>_ DevTrendsja

言語

ホーム

言語

セクション

フロントエンド バックエンド モバイル DevOps AI / ML ゲーム開発 ブロックチェーン 組み込み セキュリティ
JavaScript

React NativeにAppleサインインを追加する実践ガイド

Googleやソーシャルログインを使ってモバイルアプリをApp Storeにデプロイしたことがある方なら、リビュアーの厳格なルール遇到过のことでしょう: third-party sign-inを追加する場合は、Appleサインインも必ず含めなければなりません。そうしないと、リリースビルドのコンパイルが終わるよりも早くリジェクトされます。

最初はシンプルな作業に見えます。しかし、ネイティブコールの呼び出し、シミュレータの問題、AppleのAPIの癖などを調べ始めると、多くの落とし穴が姿を現します。Invertaseチーム(React Native Firebaseの裏もいる同じ人々)が作ったreact-native-apple-authenticationというライブラリが、iOSとAndroidの両方でこれを処理してくれます。

apple-auth

内部構造と必要な理由

このライブラリはAppleの認証メカニズムへのフルアクセスを提供します。バージョン0.60からのバニラReact Nativeで動作し、Expoと良好に連携し(prebuildとentitlements設定経由、app.json)、macOSをサポートし、Androidユーザーをブラウザフロー経由で認証することすら可能です。

最大の利点は、すぐに使えるTypeScript定義と готовыеネイティブボタンコンポーネントです(AppleButton)。ボタンデザインはAppleのガイドラインによって厳しく規制されています。自分で描くと、リビュアーが喜んでアプリをリジェクトします。ここでは、スタイルとローカライゼーションがネイティブシステムから直接取得されます。

iOSの基本フローの仕組み

インストールは標準的です:yarnまたはnpmでパッケージをインストールし、iosフォルダでpod installを実行します。モジュールはautolinkingをサポートしているため、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にバグがあると明記されています:スコープは正確にこの順序で渡す必要があります([FULL_NAME, EMAIL])。順序を入れ替えると、最初のリクエストで名前が失われる可能性があります。

シミュレータとエラー1000

currentUserメソッド getCredentialStateForUserはデバイスの真正性を確認します。iOSシミュレータでは、定期的にエラー1000 com.apple.AuthenticationServices.AuthorizationError error 1000でクラッシュします。認証チェーンを完全にテストするには、物理デバイスでのみ可能です。

シミュレータがこのエラーで完全にスタックした場合、開発者はApple ID管理ウェブサイトにアクセスし、関連デバイスのリストを見つけて、シミュレータをアカウントから削除することをお勧めします。

show-devices

remove-from-manager

ログアウトは幻想

モジュールの列挙型にはログアウト操作が含まれていますが(appleAuth.Operation.LOGOUT)、実際にはネイティブiOS SDKでは何も処理しません。Appleはデバイスレベルでシステムから強制ログアウトする方法を提供していません。クライアント側のログアウトとは、ローカルセッション、保存されたトークン、app stateをクリアすることを意味します。

アクセスの取り消し

ユーザーはいつでも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を確認する必要があります。

モジュールは、Appleに送信する前に渡されたnonceのSHA256ハッシュを自動的に計算します(Firebase Authと同様の方法、nonce)。これをバックエンドで覚えておいてください:ハッシュ化された値を比較する必要があります。

App Store Reviewの要件を迅速に満たすこと、またはFace IDによる便利なワントップログインをユーザーに提供することが目標なら、InvertaseライブラリはReact Nativeエコシステムで最も信頼できる選択肢です。Swift/Objective-Cで独自のネイティブブリッジを書くことから解放し、ボタンのスタイリングを適切に処理し、メンテナンス担当者によって一貫して更新されています。インストールし、Apple Developer Consoleで証明書を設定し、ハンドラを設定すれば—リリースの提出準備完了です。

関連プロジェクト