見出し画像

MGL週報 #35 - Appleの「理由の宣言が求められるAPI」の宣言方法など

このエントリはゲーム開発用フレームワーク「MGL」の開発記録です.MGLはzlibライセンスの下に無償で提供されています.



今週の作業内容

理由の宣言が求められるAPIへの対応

以前にも記事にした,iOSなどで不正なユーザー追跡に悪用できてしまうAPIへの対応です.

MGLでは時間の計測にmach_absolute_time()を使用しています.このAPIはシステムが起動してからの時間を,CPUの動作クロックに基づいた単位で取得するものです.これは多くのプラットフォームで最も高精度な時間単位であり,ゲームのようなリアルタイム処理には欠かせない存在となっています.

このmach_absolute_time()は理由の宣言の対象APIとなっており,これを他のAPIで代替できないかと検討していました.と,言うのも,このAPIとよく似たmach_continuous_time()は対象外となっており,こちらが使えないのかと考えていたのです.

両者の違いは,スリープ中にも時間をカウントするか否かです.mach_absolute_time()はスリープ中には時間が経過しませんが,mach_continuous_time()は時間が経過します.

結論としては,素直に理由を宣言したうえでmach_absolute_time()を使うことにしました.ちょっと手を加えれば代替できそうではあるのですが,そもそも後ろめたい理由で使う訳ではないので,無理に避ける必要は無いだろうという判断です.

この理由の宣言方法ですが,ドキュメントを読んでもちょっと分かりにくい部分もあったため,備忘録も兼ねて本記事で後述することにしました.iOSやtvOSでゲームを作る人にとっては無縁ではないため,他のゲーム開発者の方の参考になればと思います.

UIまわりの調整

先日のキー入力の対応でUI関連の大きな作業は片付きましたが,いくつか残っていた細かい作業の対応になります.

表示状態とイベントとの連動は,非表示のウィジットのイベント更新処理を省いたり,フォーカス中のウィジットを非表示にした際にアンフォーカスイベントを発行したりなど.これらは前のバージョンでは入っていたのですが,作り変える際に一旦消してしまっていたのですよね.忘れないで良かった.(忘れてた)

入力スコープは,マウスなどの入力判定をそのエリア内に限定するための機能です.これは何に使うのかというと,スクロールを実装する場合などに必要になります.単にウィジットの範囲のみで判定してしまうと,スクロールによって一部が表示されている場合に表示領域外に判定が残ってしまうためです.

その他,標準のイベントデリゲートからマウスとタッチを無効化する機能など,タスク化してない細かい調整なども適宜行なっています.

リネーム

ただのリネームですね.該当箇所はMGL内部でしか使用していないためアプリケーション側に影響は無いのですが,ドキュメントにも記述があったので忘れないようにタスク化しておいたものです.


Appleの「理由の宣言が求められるAPI」の宣言方法

先述の通り,理由の宣言が必要なAPIを使用するための方法について書き残しておきましょう.これは難しくはないのですが,Appleの開発環境に慣れていないとちょっと分かりにくいと思います.

そもそもなぜこの対応が必要なのかについては,次のリンク先で視聴できる今年のWWDCの動画が分かりやすと思います.

英語の解説ですが,右下にある「>>>」みたいなアイコンから字幕→日本語とすることで日本語字幕も表示できます.また,MGL週報でも以前話題にしています.こちらもよろしければどうぞ.

Step1: プライバシーマニフェストの追加

この対応が必要になった背景にはユーザーのプライバシー保護があります.そのため,理由の宣言はプライバシーマニフェストと呼ばれる設定ファイルに記述する必要があります.このファイルは新規作成時には含まれていないため,まずはこれをプロジェクトへと追加しましょう.

まずは追加したいディレクトリで右クリック→「New File...」を選択します.ファイル選択ウィンドウの中から,「Resource」の項目下にある「App Privacy」を選択してください.これがプライバシーマニフェストと呼ばれているファイルで,その内容はAppleの開発環境ではお馴染みのプロパティリストとなっています.

プライバシーマニフェストの新規追加

プライバシーマニフェストのファイル名は「PrivacyInfo.xcprivacy」です.この名前は変更不可ですので注意してください.

Step2: APIの使用宣言を表す要素を追加

次に,追加したプライバシーマニフェストにAPIの使用理由の宣言を格納する項目を追加します.

先ほど追加したプライバシーマニフェストをXcodeで開き,一番上の「App Pricacy Configurations」を右クリックして,「Add Row」→「Privacy Accessed API Types」と選択してください.これがAPIの使用理由の宣言を表す項目になります.

APIの使用宣言を表す項目を追加

APIの理由の宣言はこの下の階層に記述します.また,ここでは無関係なので触れませんが,正当なユーザー追跡などを行う場合もこのファイルに理由の宣言と並ぶように追加していくことになります.

Step3: 使用するAPIのカテゴリを追加

さて,ここからがちょっと分かりにくいところ.

追加された項目を展開し,「Item 0」を更に展開した状態で右クリック→「Add Row」→「Privacy Accessed API Types」を選択します.これがちょっとトラップでして,「Item 0」を展開していない状態で「Add Row」を選択した場合は「Item 1」が追加されます.要素の左側のアイコンが下を向いていることを確認してから「Add Row」を選択してください.

「Privacy Accessed API Types」の追加方法

この要素は1つとは限らないため,複数設定できるよう配列となっています.もし複数のAPIカテゴリを追加したい場合は「Item 0」を展開していない状態で「Item 1」「Item 2」... と要素を増やして対応します.

また,「Privacy Accessed API Types」という名前の項目がここで再登場しますが,これは誤りではありません.そういうものですのであまり気にしないでください.

さて,次に追加した「Privacy Accessed API Types」のValueの右にあるプルダウンを開き,使いたいAPIのカテゴリを選択します.ここでは例として,今回MGLで対応を行ったmach_absolute_time()の追加を想定しましょう.そのAPIがどのカテゴリに属しているかは次のドキュメントを参照する必要があります.

今回追加したい mach_absolute_time() は 「System boot time APIs」の項目にありますので,右側のプルダウンメニューから「System Boot Time」を選択します.

APIカテゴリの値の設定

ここもちょっと分かりにくいところで,ドキュメントには値に文字列として「NSPrivacyAccessedAPICategorySystemBootTime」を指定しろと書いてあります.実は,プルダウンメニューは分かりやすいラベルに置き換えており,「System Boot Time」を選択すると内部的にこの文字列が記録されるのです.

Step 4: 使用するAPIの用途を設定

最後に,追加したカテゴリに対して理由を設定します.

先ほど追加した「Privacy Accessed API Types」を右クリックして,「Add Row」→「Privacy Accessed API Reasons」を追加します.この項目も複数設定できるように配列となっていますので,展開して「Item 0」の値に理由を設定しましょう.

プルダウンメニューには全ての理由が含まれていますが,実際に指定可能な理由はAPIカテゴリごとに定められています.その情報も先述のドキュメントに記されていますので,それを元に設定してください.ここでは「System Boot Time」に対応する唯一の用途である「35F9.1: ...」を選択します.APIによっては複数の理由を指定することもありますので,その場合は「Item 1」「Item 2」... と配列の項目を増やして対応してください.

最終的には次のような設定になります.

MGLのプライバシーマニフェスト

全体的に見ると,使用するAPIのカテゴリを追加して,その理由を1つ以上設定していく形になります.もちろん,これを対応したところで該当APIが好き放題使える訳ではなく,ここで設定した用途以外の使用は禁止されています.言い換えると,理由としてリストアップされていない使い方は例え悪意がなくとも不可能ですので,その場合は別の実装方法を探るかAppleさんに直訴しましょう.なお,MGLはファイル情報の取得にstat()を使用していましたが,これが抵触したためiOS/tvOSのファイルデリゲートを分けた経緯があります.

そして,Appleの開発環境は難しくはないのですが,初見殺しのトラップが多めなことに注意してください.パターンを覚えれば比較的安定するようになります.


その他

UI関連もおおよそ片付いてきたため,次はタスクシステムの並列化を対応しようかなと考えています.この2つは実際のゲーム開発に用いてテストしたいので,早めに導入してしまいたいのですよね.

ただまあ,今作っているゲームはUIはともかく,タスクの並列化は使い所が無さそうでして……さてどうしよう?

この記事が気に入ったらサポートをしてみませんか?