Unity

【Unity】iOSでSign in with Appleの実装を解説

UnityでiOS向けのSing in with Appleを実装し、FirebaseAuthと連携していく方法を解説します。
とても簡単です。

前提として、「Firebaseにアプリのプロジェクトを作成」し、かつ、「iOSの開発ライセンスも取得済み」とします。

 

Android向けのSign in with Appleはコチラの記事を参照してみてください。

【Unity】AndroidでSign in with Appleの実装を解説UnityでAndroid用にSign in with Appleを実装し、Firebase Authと連携していく手順を解説します。 ...

Googleログインの実装はコチラの記事を参照してみてください。

【Unity】iOSネイティブ連携でGoogle Sign Inを実装する方法UnityでGoogle Sign Inを実装する場合、Google公式のライブラリを利用するのが一般的です。 しかし、最...
【Unity】Androidネイティブ連携でGoogle Sign Inを実装する方法UnityでGoogle Sign Inを実装する場合、Google公式のライブラリを利用するのが一般的です。 しかし、最...

 

XCodeでSign in With Appleの有効化

UnityでiOSビルドをし、iOSプロジェクトをXCodeで開きます。

TARGETSからアプリを選択して、Signing & Capabilitiesタブを選択して、+ Capabilityボタンを押す。

 

リストからSign in with Appleを選択。

 

これでプロジェクトにSign in with Appleが有効になります。

 

FirebaseでSign In With Appleの有効化

Firebaseで該当プロジェクトを開き、Authenticationメニューで、Sign-in methodタブを選び、新しいプロバイダを追加ボタンを押し、Apple認証を追加します。

iOSの場合、有効化するだけで、各種オプションの入力は不要です。

 

実装

FirebaseAuthパッケージの導入

以下のリンクから最新版のFirebase Unity SDKをダウンロードします。
今回はバージョン11.2.0を導入しています。

既に他のFirebaseパッケージを導入済の場合は同じバージョンのFirebaseAuthパッケージを入れるか、最新のパッケージを全て入れ直してください。
そうしないとエラーで動きません。

ダウンロードしたら解凍して、FirebaseAuth.unitypackage をimportします。

 

Sign in with Appleパッケージの導入

次に非公式Sign in with Appleパッケージをimportします。

 

C#の実装

後は実装するだけです。
詳細はソースのコメントを参照してください。

using UnityEngine;
using Firebase.Auth;
using Firebase.Extensions;
using System.Runtime.InteropServices;
using System;
using System.Collections.Generic;
using AppleAuth.Interfaces;
using AppleAuth;
using AppleAuth.Native;
using AppleAuth.Enums;
using System.Threading.Tasks;
using System.Security.Cryptography;
using System.Text;


public class TestController : MonoBehaviour
{
    private FirebaseAuth auth;
    Firebase.DependencyStatus dependencyStatus = Firebase.DependencyStatus.UnavailableOther;
    private AppleAuthManager appleAuthManager;

    private void Start()
    {
        // FirebaseAuthの初期化
        Firebase.FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task =>
        {
            dependencyStatus = task.Result;
            if (dependencyStatus == Firebase.DependencyStatus.Available)
            {
                auth = FirebaseAuth.DefaultInstance;
            }
            else
            {
                Debug.Log($"error: {dependencyStatus}");
            }
        });
    }

    private void Update()
    {
        // これやらないとSign In後の処理が進まない
        if (this.appleAuthManager != null)
        {
            this.appleAuthManager.Update();
        }
    }


    public void SignInWithAppleForiOS()
    {
        var deserializer = new PayloadDeserializer();
        this.appleAuthManager = new AppleAuthManager(deserializer);

        // 暗号化した文字列(nonce)を渡して認証し、認証結果に暗号化前の文字列を渡して改ざんチェックをする
        var rawNonce = GenerateRandomString(32);
        var nonce = GenerateSHA256NonceFromRawNonce(rawNonce);
        var loginArgs = new AppleAuthLoginArgs(LoginOptions.IncludeEmail | LoginOptions.IncludeFullName, nonce);
        appleAuthManager.LoginWithAppleId(
            loginArgs,
            credential =>
            {
                var appleIdCredential = credential as IAppleIDCredential;
                if (appleIdCredential != null)
                {
                    // Sign In成功!

                    var identityToken = Encoding.UTF8.GetString(appleIdCredential.IdentityToken);
                    var authorizationCode = Encoding.UTF8.GetString(appleIdCredential.AuthorizationCode);
                    Credential credencial = OAuthProvider.GetCredential("apple.com", identityToken, rawNonce, authorizationCode);
                    var signInCompleted = new TaskCompletionSource<FirebaseUser>();

                    // AppleアカウントをFirebaseAuthに紐付ける
                    auth.SignInWithCredentialAsync(credencial).ContinueWith(task =>
                    {
                        if (task.IsCanceled)
                        {
                            Debug.Log($"canceled");
                            signInCompleted.SetCanceled();
                        }
                        else if (task.IsFaulted)
                        {
                            Debug.Log($"fault {task.Exception}");
                            signInCompleted.SetException(task.Exception);
                        }
                        else
                        {
                            Debug.Log($"complete!");
                            signInCompleted.SetResult(task.Result);
                        }
                    });
                } else
                {
                    Debug.Log($"no credential!");
                }
            },
            error =>
            {
                Debug.Log($"sign in error");
            });
    }



    private static string GenerateRandomString(int length)
    {
        if (length <= 0)
        {
            throw new Exception("Expected nonce to have positive length");
        }

        const string charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._";
        var cryptographicallySecureRandomNumberGenerator = new RNGCryptoServiceProvider();
        var result = string.Empty;
        var remainingLength = length;

        var randomNumberHolder = new byte;
        while (remainingLength > 0)
        {
            var randomNumbers = new List<int>(16);
            for (var randomNumberCount = 0; randomNumberCount < 16; randomNumberCount++)
            {
                cryptographicallySecureRandomNumberGenerator.GetBytes(randomNumberHolder);
                randomNumbers.Add(randomNumberHolder[0]);
            }

            for (var randomNumberIndex = 0; randomNumberIndex < randomNumbers.Count; randomNumberIndex++)
            {
                if (remainingLength == 0)
                {
                    break;
                }

                var randomNumber = randomNumbers[randomNumberIndex];
                if (randomNumber < charset.Length)
                {
                    result += charset[randomNumber];
                    remainingLength--;
                }
            }
        }

        return result;
    }

    private static string GenerateSHA256NonceFromRawNonce(string rawNonce)
    {
        var sha = new SHA256Managed();
        var utf8RawNonce = Encoding.UTF8.GetBytes(rawNonce);
        var hash = sha.ComputeHash(utf8RawNonce);

        var result = string.Empty;
        for (var i = 0; i < hash.Length; i++)
        {
            result += hash[i].ToString("x2");
        }
        return result;
    }
}

 

Sign in with Appleが成功し、FirebaseAuthとの連携が成功すると、FirebaseにAppleと連携したアカウントが作成されます。