[unity]iOS の生体認証を実装してみる

C# から直接 Swift のコードを呼び出す、の例として生体認証(TouchID、FaceID)を実装します。

Swift ド素人が書いた適当コードなので、色々と目を瞑ってください……。

GitHub

コード

iOSAuthentication.cs

using UnityEngine;
using System.Runtime.InteropServices;
using System;

public class iOSAuthentication : MonoBehaviour
{
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    delegate void CallbackDelegate([MarshalAs(UnmanagedType.I4)] Int32 num);
    
    [DllImport("__Internal", EntryPoint = "registerAuthCallback")]
    static extern void RegisterAuthCallback([MarshalAs(UnmanagedType.FunctionPtr)] CallbackDelegate callback);

    [DllImport("__Internal", EntryPoint = "authentication")]
    static extern long Authentication();

    void Start()
    {
        RegisterAuthCallback(callback);
    }

    public void onPressButton()
    {
        Authentication();
    }

    [AOT.MonoPInvokeCallbackAttribute(typeof(CallbackDelegate))]
    static void callback(Int32 num)
    {
        Debug.Log($"call native code: {num}");
    }
}

Plugin/iOS/iOSAuthentication.swift

import Foundation
import LocalAuthentication

public typealias CallbackDelegate = @convention(c) (Int32) -> Void

public class iOSAuthentication
{
    static private var authCallbackDelegate: CallbackDelegate? = nil;

    public static func registerAuthCallback(_ delegate: @escaping CallbackDelegate)
    {
        authCallbackDelegate = delegate
    }

    public static func authentication()
    {
        var description: String = "サインイン"
        let context = LAContext()
        context.localizedFallbackTitle = "他の方法を試す"
        var error: NSError?

        // Face ID, Touch IDが利用できるデバイスか確認する
        if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)
        {
            // Face ID, Touch IDが利用できる場合は認証用ダイアログを表示
            context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: description,
                reply:
                {
                    success, evaluateError in
                    if (success)
                    {
                        // 認証成功
                        switch context.biometryType
                        {
                        case .faceID:
                            authCallbackDelegate?(1)
                            break
                        case .touchID:
                            authCallbackDelegate?(1)
                            break
                        case .none:
                            // Face ID, Touch IDが利用出来ない (unknown)
                            authCallbackDelegate?(0)
                            break
                        @unknown default:
                            authCallbackDelegate?(0)
                            break
                        }
                    }
                    else
                    {
                        // 認証失敗
                        authCallbackDelegate?(0)
                    }
                }
            )
        }
        else
        {
            // Face ID, Touch IDが利用出来ない
            authCallbackDelegate?(-1)
        }
    }
}

@_cdecl("registerAuthCallback")
public func registerAuthCallback(_ delegate: @escaping CallbackDelegate)
{
    return iOSAuthentication.registerAuthCallback(delegate)
}

@_cdecl("authentication")
public func authentication()
{
    return iOSAuthentication.authentication()
}

Editor/OnPostBuildProcess.cs

FaceID を有効にするためには、Info.plist にキーを用意しておく必要があります。

using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using System.IO;
#if UNITY_IOS
using UnityEditor.iOS.Xcode;
#endif

public class OnPostBuildProcess : MonoBehaviour
{
    [PostProcessBuild]
    public static void OnPostProcessBuild(BuildTarget buildTarget, string path)
    {
        if (buildTarget == BuildTarget.iOS)
        {
            processForiOS(path);
        }
    }

    static void processForiOS(string path)
    {
#if UNITY_IOS
        var plistPath = Path.Combine(path, "Info.plist");
        var plist = new PlistDocument();

        plist.ReadFromFile(plistPath);
        var root = plist.root;
        root.SetString("NSFaceIDUsageDescription", "認証に必要");
        plist.WriteToFile(plistPath);
#endif
    }
}

実行

TouchID、FaceID 両方に対応しています。
Authentification() で認証スタート、認証画面が終わると RegisterAuthCallback() で設定したコールバックに値を返します。

-1 .. TouchID、FaceID が許可されていない
0 .. 認証失敗
1 .. 認証成功

シミュレーターで確認可能

Xcode のシミュレーターで確認するのがお手軽です(Face ID は実機で見た方がいいかも)。

TouchID、FaceID を許可する

Features > Touch(Face)ID > Enrolled

Enrolled に✓マークがつくと、TouchID・FaceIDの動作を確認することができます。

判定の OK、NG

Features > Touch(Face)ID > Matching Touch(Face)
Features > Touch(Face)ID > Non-matching Touch(Face)

認証判定の OK、NG をシミュレートするにはこの2つのコマンドを選択します。

AppStore に提出する場合

一点問題があります。それについては別の記事にしましたので、必要に応じてご覧ください。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA