search
LoginSignup
5

posted at

updated at

Organization

【2022年版】Flutter+FirebaseでAppleアカウント認証を実装する

はじめに

自分で開発しているアプリに以下の3rd-party製の認証をつけてリリース申請をしたところ、Appleから以下のような返事が来た。

App_Store_Connect.jpg

つまり、他のアカウントとの連携認証システム入れるならAppleアカウントとの連携認証も入れなさい、とのこと。

現状は以下のサービスのアカウントとの連携認証を実装しているので、これにAppleアカウントとの連携認証機能も追加していく。

  • MailAddress/Password
  • Google account
  • Twitter account

ちなみに上記のサービスのアカウントとの連携認証に関しては、以下の記事に記述している。

実装

Flutter packageでapple sign inで調べたら何個かヒットした。
その中で一番likeが多く、READMEも丁寧に書かれていてやりやすそうな以下のパッケージを選択。

基本的にREADMEを読めば問題はないが、英語読むのめんどい時のためにメモ。
大まかな流れは以下。

  1. apple developer programでアプリのbundleIdを登録(既にしている場合はスキップ)
  2. bundleIdに、sign in with appleを許可する
  3. FirebaseAuthenticationで、appleでのサインインを設定
  4. xcodeへの導入
  5. コードを修正

1. アプリのBundleIdを登録

page: Apple Developer: Certificates, Identifiers & Profiles

すでにあったら大丈夫。

2. sign in with appleを許可

1.のページから、該当アプリのBundleIdを選択し、クリック。
そこで、Sign in with Appleを有効化する。

スクリーンショット_2022-02-04_0_37_25.jpg

ユーザ情報の変更通知等を受け取らなくていい場合は、下の部分は気にしないで良い。
Certificates__Identifiers___Profiles_-_Apple_Developer.jpg

3. Firebase Authenticationの設定

iPhoneアプリからしか使わない場合は、下は無視して良い。
photo-app_-_Authentication_-_Firebase_コンソール-2.jpg

追加されているか確認
photo-app_-_Authentication_-_Firebase_コンソール.jpg

4. xcodeへの導入

該当アプリのrunner.xcodeprjファイルをxcodeで開き、Capabilityをクリックし、Sign in With Appleを検索しクリック。
そうすると、画像のようにSign in With Appleがアプリに追加される。

Runner_xcodeproj.jpg

5. コードの修正

以下のブランチが、今回の変更を行っているブランチ。

以下のPRを見ると、差分がわかりやすいかもしれない。

パッケージの導入

pubspec.yaml
dependencies:
  flutter:
    sdk: flutter

  # 以下追加
  sign_in_with_apple: ^3.3.0

パッケージの利用

sign_in_screen.dart
import 'package:sign_in_with_apple/sign_in_with_apple.dart';

// ログインメソッド
Future<void> _onSignInWithApple(User? user) async {
    try{

      // AuthorizationCredentialAppleIDのインスタンスを取得
      final appleCredential = await SignInWithApple.getAppleIDCredential(
        scopes: [
          AppleIDAuthorizationScopes.email,
          AppleIDAuthorizationScopes.fullName,
        ],
      );

      // OAthCredentialのインスタンスを作成
      OAuthProvider oauthProvider = OAuthProvider('apple.com');
      final credential = oauthProvider.credential(
        idToken: appleCredential.identityToken,
        accessToken: appleCredential.authorizationCode,
      );

      if (user !=null && user.isAnonymous) {
        await user.linkWithCredential(credential);
        Navigator.of(context).pop();
      } else {
        await FirebaseAuth.instance.signInWithCredential(credential);

        if (Navigator.of(context).canPop()) {
          Navigator.of(context).pop();
        } else {
          Navigator.of(context).pushReplacement(
            MaterialPageRoute(
              builder: (_) => PhotoListScreen(),
            ),
          );
        }
      }
    } catch(e) {
      await showDialog(
          context: context,
          builder: (context) {
            return AlertDialog(
              title: Text('エラー'),
              content: Text(e.toString()),
            );
          }
      );
    }
  }

// コンポーネント
if (Platform.isIOS) SignInButton(
  Buttons.Apple,
  onPressed: () {
    _onSignInWithApple(user);
  },
)

UIパッケージの利用

Buttonの見た目には、flutter_signin_buttonというパッケージを用いている。

Credentialの扱い

sign_in_with_appleを用いて取得したAuthorizationCredentialAppleIDは、そのままfirebaseに渡すことはできない。
Firebaseに渡す用に、AuthorizationCredentialAppleIDから情報を抜き出してOAthCredentialのインスタンスを作成しなければならない。

      // AuthorizationCredentialAppleIDのインスタンスを取得
      final appleCredential = await SignInWithApple.getAppleIDCredential(
        scopes: [
          AppleIDAuthorizationScopes.email,
          AppleIDAuthorizationScopes.fullName,
        ],
      );

      // OAthCredentialのインスタンスを作成
      OAuthProvider oauthProvider = OAuthProvider('apple.com');
      final credential = oauthProvider.credential(
        idToken: appleCredential.identityToken,
        accessToken: appleCredential.authorizationCode,
      );

ちなみにAuthorizationCredentialAppleIDに含まれる情報は以下。

authorization_credential.dart
@immutable
class AuthorizationCredentialAppleID {
  /// Creates an instance which contains the result of a successful Sign in with Apple flow.
  const AuthorizationCredentialAppleID({
    @required this.userIdentifier,
    @required this.givenName,
    @required this.familyName,
    required this.authorizationCode,
    @required this.email,
    @required this.identityToken,
    @required this.state,
  });
  ...

どの変数が何を意味しているかは、以下の記事をみるとなんとなくわかる。
完全にはわからないが、動いたからよしとしている。

既知の問題

ちなみに、simulatorでいくら試してもこのコードは動かない(2022/2/3時点)
githubディレクトリ飛んでissueでも作って文句言ってやろうかと思ったら、すでにあった。
どうやらsimulatorの問題らしく、実機でテストをするときちんと動くことが確認できた。

スクリーンショット_2022_02_04_1_03.jpg

まとめ

今回は、appleから直々に怒られたので、appleアカウント連携認証を実装してみた。
全然難しくない変更ではあるが、simulatorの問題でめちゃくちゃ引っかかってしまった。
xcode周りは挙動が怪しいので、コードを疑いつつソフトウェアそのものにも疑いを持つようにしよう。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
5