概要

弊社ではtwitter/facebookアカウントによるSNS連携(アカウント移行機能)を有するアプリがあるため、2020年4月以降Sign in with Appleに対応が必須になります。
また同じく、2020年4月からApp StoreアプリのXcode11/SDK13対応が必須になるため、本稿ではそれらの対応内容を紹介します。

Sign in with Apple 対応

Sign in with Apple とは Apple IDを使用したApple公式の認証システムで、使用するIDは2段階認証が必須となります。
パスワード/TouchID/FaceIDで認証可能ですが、アプリには必要最小限の情報しか渡りません。
サービスに伝えるメールアドレスにAppleが自動生成した匿名アドレスを使用できますが、その場合はサービス側にはAppleIDのメールアドレスは知らされません。
サービス側は匿名アドレス宛にメールを送ることができ、そのメールはAppleがAppleIDアドレスに転送します。
REST API 方式の利用によって、iOSアプリの他にウェブサイトやAndroidでも使用可能です。
Sign in with Apple はユーザー側からいつでも無効化が可能です。

Sign in with Apple:
https://developer.apple.com/sign-in-with-apple/

Sign in with Apple JS:
https://developer.apple.com/documentation/signinwithapplejs

とあるプロジェクトのでの対応方針

下記は対応当初のプロジェクト内資料を抜粋した画像です。

資料内のリンク:
Unity プラグイン: https://assetstore.unity.com/packages/tools/sign-in-with-apple-154202
Unity blog: https://blogs.unity3d.com/2019/09/19/support-for-apple-sign-in/

認証フローは下記画像の2案考えられましたが、2つめ画像の「プロジェクト側で正当性を確認するフロー」を採用しています。


AppleおよびUnity公式の認証フローにある資料を参考にして採用しました。
https://blogs.unity3d.com/jp/2019/09/19/support-for-apple-sign-in/
Appleサーバーを利用してrefresh_tokenが取得できるかどうかを確認すれば結果的にはより堅牢になりますが、SNS連携程度だとrefresh_tokenをその後の通信で継続して使ったりしないので、idTokenのサーバー検証だけで十分だと判断しました。

注意点

AppIDとCapability

Sign in with Appleは、課金テストやApple Payと同じ扱いでApple Enterprise Developer Programのアプリでは利用できないようです。

Supported capabilities (iOS)
https://help.apple.com/developer-account/#/dev21218dfd6

Service ID

ServiceIDは、iOSアプリ本体以外の関連するサービス(WebサイトやAndroid)で同じ認証を使用する場合に必要です。

AndroidアプリやWebでSign in with Appleを利用する場合に設定します。

公式プラグインとサンプル動作確認

Unity 公式プラグイン:
https://assetstore.unity.com/packages/tools/sign-in-with-apple-154202

サンプルに不具合があったため以下のように修正しています。

SignInWithApple.cs l141

GetCredentialStateInternal(userID);

SignInWithAppleTest.cs l34
<userid>で渡しているが、正しいやり方が不明でした。
Login時に得られたuserIDを保存し、それを渡すように修正したら成功しています。

このプラグインは実装が古くnonceやAuthorization Codeに対応していないため、必要になったら対応が必要です。
またC#のCouncrrentQueueを使用していますが、今回のプロジェクトはまだ.NET3.5のため、修正が必要でした。

Xcodeprojの設定

サンプルではframeworkとCapabilityを追加する処理が入っていないので、Xcodeで開いた時に手動で追加します。実際のプロダクトではこれらの設定を自動的に追加する対応を行っています。

  • General→FrameworksにAuthenticationServices.frameworkを追加
  • Build Phases→Link Binary With Libraries→AuthenticationServices.frameworkをOptionalに設定
  • Signing&CapabilitiesでSign in with AppleのCapabitlityを追加
  • Build Settings→Signing→Code Signing EntitlementsにUnity-iPhone/IronAPTestRelease.entitlementsを設定(Capabitlity追加時点ではReleaseにしか追加されないので)

実行

テスト端末を用意します。
テスト用のアカウントが2段階認証設定されていない場合は、2段階認証を設定するか設定済みテストアカウントを用いてください。
アプリを実行してSign in with Appleのボタンを押すと、認証が開始されます。

応答

以下の情報が得られます。

  • ユーザーID
  • メールアドレス(匿名の場合自動生成されたもの)
  • displayName
  • idToken(JWT)
  • エラー情報・ステータス

作業途中で発生したエラーコード

AKAuthenticationError Code=-7026

アプリにCapabilityが追加されていないか、Entitlementsが設定されていない
Entitlements設定が間違っていた時に出ました。

AKAuthenticationError Code=-7030

Credentialが無効
正しくUserIDを渡していない時に出ました。

資料

公式
https://developer.apple.com/jp/sign-in-with-apple/get-started/

REST API
https://developer.apple.com/documentation/signinwithapplerestapi

UIガイドライン
https://developer.apple.com/design/human-interface-guidelines/sign-in-with-apple/overview/

サードパーティーアセット
https://github.com/lupidan/apple-signin-unity


Xcode 11 / iOS13 対応

WWDC時点でドリコムのプロダクトが対応するにあたって必須になるとされていた項目は下記の通りでした。

  • サードパーティログインに対応している場合、Sign in with Appleに対応すること
  • LaunchImagesが廃止されるため、Sotryboardへ移行を行う必要がある
  • iPadのマルチウィンドウ対応
  • ダークモード対応
  • UIWebView廃止に伴う対応

参考:
https://techracho.bpsinc.jp/yoshi-k/2019_08_28/79514

準備

jenkinsのOSアップデート

Xcode11はMojave以上が必須でしたが、対象のプロジェクトのCI機のOSはHigh Sierraのままだったので、更新しています。
この際、Catalinaまで上げてしまうとチェックコストが高いので、今回はMojaveを選択しました。
事前ダウンロードされていたアップデーターがなんと証明書期限切れで実行時にエラーとなってしまうので、/Applications フォルダから削除し、再ダウンロードが必要でした。
https://discussionsjapan.apple.com/thread/250834337

対応項目

LaunchImagesの排除

LaunchImagesが廃止になり、スプラッシュをStoryboardに移行しなければなりません。
今回のプロジェクトでは従来からLaunchScreenを使用していてLegacy LaunchImagesは設定していませんでしたが、何らかの理由でビルド時にLaunchImagesが自動で作成されるようになっていました。
当初Xcode11 betaではLaunchImagesが含まれているだけでビルドが失敗するという厳しい対応でしたが、リリース版では緩和されて失敗にはならなくなりました。
しかしリジェクト要因と予想されるため、排除対応しています。

対応

ポストプロセスビルドで、project.pbxprojの各configのASSETCATALOG_COMPILER_LAUNCHIMAGE_NAMEを空白にしています。

// remove LaunchImages
{
    foreach(string targetConfig in proj.BuildConfigNames())
    {
        proj.SetBuildPropertyForConfig(proj.BuildConfigByName(target, targetConfig), "ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME", "");
    }
}

File.WriteAllText(projPath, proj.WriteToString());

これで、ipaにLaunchImagesが含まれなくなりました。

ダークモード対応(の無効化)

ダークモードへの対応が今後必須となると想定されますが、前提としてUIUserInterfaceStyleの設定が要求されています。
現在は過渡的処置としてLight(ダーク設定でも強制でライトテーマにする)を設定することが許されていますが、ダークモードへの対応は今後強制となり、Light設定は禁止されるという情報もあります。

対応

ポストプロセスビルドでInfo.plistにUIUserInterfaceStyle=Lightを追加しています。
Lightは頭大文字である必要があります。(lightだとエラー)

// disable dark mode
{
    rootDict.SetString("UIUserInterfaceStyle", "Light");
}

File.WriteAllText(plistPath, plist.WriteToString());

UIKitを使わないゲームアプリなどにダークモード対応が今後どの程度求められるかは、まだ未知数です。

iOS12.0でのクラッシュ対応

Unityにバグがあり、Unity2017.4.33以前+Xcode11+iOS12.0の特定環境でクラッシュが発生していました。
Unit2017.4.34以上で修正されているため、Unity2017のマイナーアップデートが必要になりました。

IL2CPP: Prevented a possible crash on iOS 12.0 on certain devices when a managed exception occurs. (1185656)

UnityはAndroid 64bit対応の時にも不具合が見られたため、環境更新で何か問題があったらUnityのフォーラムも見ておくと良いでしょう。

対応しなかった項目

iPadマルチウィンドウ対応

必須化されると言われていましたが、最終的に努力義務となったため今回の対応は見送りました。
https://developer.apple.com/jp/news/?id=01132020b

UIWebView の廃止

今回のプロジェクトでは使用箇所はなかったため対応していません。


おわりに

本稿ではドリコムのとあるプロジェクトの Sign in with Apple 対応と Xcode 11 / iOS 13 対応を紹介させていただきました。
実際のプロジェクトでの対応事例が皆様の参考になれば幸いです。