20
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

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

Last updated at Posted at 2022-02-03

はじめに

自分で開発しているアプリに以下の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周りは挙動が怪しいので、コードを疑いつつソフトウェアそのものにも疑いを持つようにしよう。

20
9
1

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
  3. You can use dark theme
What you can do with signing up
20
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?