Open14

iOSアプリを審査に提出したら「ITMS-91053: Missing API declaration」というメールが来た。Privacy Manifest対応についてのメモ。

matsuchiyomatsuchiyo
  • 先日iOSアプリを提出したら、Appleから以下のようなメールが来ていた。
    • 以下の「API categories」について、reasonsが必要らしい。
      • NSPrivacyAccessedAPICategoryDiskSpace
      • NSPrivacyAccessedAPICategoryUserDefaults
      • NSPrivacyAccessedAPICategoryFileTimestamp
    • 5/1以降の提出に、必要になる。

The uploaded {app name} has one or more issues.
...
ITMS-91053: Missing API declaration - Your app’s code in the “Runner” file references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategoryDiskSpace. While no action is required at this time, starting May 1, 2024, when you upload a new app or app update, you must include a NSPrivacyAccessedAPITypes array in your app’s privacy manifest to provide approved reasons for these APIs used by your app’s code. For more details about this policy, including a list of required reason APIs and approved reasons for usage, visit: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api.

ITMS-91053: Missing API declaration - Your app’s code in the “Runner” file references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategoryUserDefaults. While no action is required at this time, starting May 1, 2024, when you upload a new app or app update, you must include a NSPrivacyAccessedAPITypes array in your app’s privacy manifest to provide approved reasons for these APIs used by your app’s code. For more details about this policy, including a list of required reason APIs and approved reasons for usage, visit: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api.

ITMS-91053: Missing API declaration - Your app’s code in the “Runner” file references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategoryFileTimestamp. While no action is required at this time, starting May 1, 2024, when you upload a new app or app update, you must include a NSPrivacyAccessedAPITypes array in your app’s privacy manifest to provide approved reasons for these APIs used by your app’s code. For more details about this policy, including a list of required reason APIs and approved reasons for usage, visit: https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api.

matsuchiyomatsuchiyo
  • 上のメール本文のリンク: Describing use of required reason API
    • Overview
      • ユーザーの特定・追跡のため乱用される可能性があるデバイスの信号、いわゆるfingerprinting(多分ipアドレスやデバイスのモデルなどを含むのかな → "required reason API"としてはリストアップされてなかったため含まないみたい)を取得することについてもユーザーに明示したいみたい。何年か前に対応したATT (App Tracking Transparencyだっけ?)の延長にある、Appleの取り組みなのかな。

        Some APIs that your app uses to deliver its core functionality — in code you write or included in a third-party SDK — have the potential of being misused to access device signals to try to identify the device or user, also known as fingerprinting. Regardless of whether a user gives your app permission to track, fingerprinting is not allowed.

      • "required reason API"のカテゴリごとに、NSPrivacyAccessedAPITypes配列にdictionaryを追加する。

        For each category of required reason API that your app or third-party SDK uses, add a dictionary to the NSPrivacyAccessedAPITypes array in your app or third-party SDK’s privacy manifest file that reports the reasons your app uses the API category.

      • アプリ側で"required reason API"に依存していたら、アプリのmanifest fileに追加する。

        (上のparagraphの続き)If you use the API in your app’s code, then you need to report the API in your app’s privacy manifest file.

      • third party SDKが依存していたら、third party SDKのmanifest fileに追加する。アプリのmanifest fileや他のthird party SDKのmanifest fileを頼ってはダメ。

        (上のparagraphの続き)If you use the API in your third-party SDK’s code, then you need to report the API in your third-party SDK’s privacy manifest file. Your third-party SDK can’t rely on the privacy manifest files for apps that link the third-party SDK, or those of other third-party SDKs the app links, to report your third-party SDK’s use of required reasons API.

        • これは、third party SDKの開発者に頼るしかないのかな。利用者側ではどうすることもできない?
          • そうだとしたら、third party SDK側でprivacy manifest fileを追加してもらわない限り、審査をパスできない。流石にそれはないのかな。
          • third party SDK側でprivacy manifest fileを追加してくれたとしても、全てのlibraryを最新にしないといけない。これは大変そう。⭐️
            • minSdkVersion(Deployment Target)を上げないといけないかもしれない。
            • 結構前の話だけど、Nukeのバージョンをあえて下げてた。当時の最新だと画像が欠ける挙動をすることがあったため。これ治っているかな。
      • ↓ Adjustどうなるの?Adjustはfingerprintを使って、attributionを行っていた気がする(attributionもtrackingに含まれるはず)。

        Important
        ..., and you may not use the APIs or derived data for tracking.

      • NSPrivacyAccessedAPITypes array内の、(カテゴリごとの) 各dictionaryには、keyとしてNSPrivacyAccessedAPIType、valueとしてNSPrivacyAccessedAPITypeReasonsが含まれる。

        Each dictionary in the NSPrivacyAccessedAPITypes array needs to contain these keys and values:
        NSPrivacyAccessedAPIType
        ...
        NSPrivacyAccessedAPITypeReasons
        ..

        • NSPrivacyAccessedAPITypeReasonsは、自由記述ではなく、あらかじめ定められた中から選ぶみたい。ない場合、Appleにリクエスト。⭐️

          The values you provide must be the values associated with the accessed API type in the sections below.
          ...
          ..., for a reason that isn’t listed here, submit a request for a new approved reason.

      • manifest fileの作り方は以下のリンク参照。

        For more information on creating a privacy manifest file, see Create a privacy manifest.

        • App Privacy File(PrivavcyInfo.xcprivacy。plist形式?)というファイルを作るらしい。

          To add the privacy manifest to your app in Xcode, choose File > New File, and scroll down to the Resource section. Select the App Privacy file type, click Next, then click Create. By default, the file is named PrivacyInfo.xcprivacy; don’t change the filename. At the top level of this property list file, add the following keys to the dictionary.

          • 配置場所はプロジェクトルートでいいのかな?
matsuchiyomatsuchiyo
  • 上の「Describing use of required reason API」の続き
    • ここからは、"required reason API"のカテゴリーを列挙して、説明しているみたい。
    • File timestamp APIs
      • 以下のNSPrivacyAccessedAPITypeReasonsがよくわからない。アプリ領域のファイルにアクセスしているだけの場合に指定する?(この場合、アプリが自分のタイミングで作ったファイルに過ぎないから、そのtimestampにアクセスしたとしてもユーザーのプライバシーの観点から何も問題ないということなのかな)

        C617.1
        Declare this reason to access the timestamps, size, or other metadata of files inside the app container, app group container, or the app’s CloudKit container.

      • 以下も難しい。

        0A2A.1
        Declare this reason if your third-party SDK is providing a wrapper function around file timestamp API(s) for the app to use, and you only access the file timestamp APIs when the app calls your wrapper function. This reason may only be declared by third-party SDKs. This reason may not be declared if your third-party SDK was created primarily to wrap required reason API(s).

        • アプリのためにfile timestamp APIをwrapするthird-party SDKが使う。
          • fileにアクセスするためのユーティリティライブラリのようなthird-party SDKを想定しているのかな?
        • 審査をパスするためだけに(?)このreasonを使ったthird party SDKを作ってはいけない。
        • このreasonがthird-party SDK側で宣言されている場合、アプリ側でこのreason以外のreasonを宣言しないといけないと思う。どうなんだろう?⭐️

        (OA2A.1の続き)
        Information accessed for this reason, or any derived information, may not be used for your third-party SDK’s own purposes or sent off-device by your third-party SDK.

        • ↑この理由で(あなたが開発した)third-party SDKが取得した情報は、(あなたが開発した)third-party SDK自身の目的で使ってはいけない(それを利用するアプリのためだけに使うということだと思う。アプリに渡すだけとかしかできないのだと思う)。また、deviceの外に送信してはいけない。
matsuchiyomatsuchiyo
  • 上の「Describing use of required reason API」の続き
    • System boot time APIs
      • ↑これは、今回指摘されなかったためスキップ。
matsuchiyomatsuchiyo
  • 上の「Describing use of required reason API」の続き
    • Disk space APIs
      • E174.1は、以下の理由がある場合に使う。
        • ファイルを書き出すときに、空きがあるか判断する。
        • ディスク容量を空けるため、ファイルを削除すべきか判断する。
        • ディスクの空き容量によって、(ユーザーにわかるように)異なる振る舞いをする必要がある。

        Declare this reason to check whether there is sufficient disk space to write files, or to check whether the disk space is low so that the app can delete files when the disk space is low. The app must behave differently based on disk space in a way that is observable to users.

      • 7D9E.1 は、任意のバグレポートでdisk spaceを送りたい場合に使う。ユーザーが明示的に、disk spaceを送ると選択(同意?)した場合でないと送れないみたい。

        7D9E.1
        Declare this reason to include disk space information in an optional bug report that the person using the device chooses to submit. The disk space information must be prominently displayed to the person as part of the report.

matsuchiyomatsuchiyo
  • 上の「Describing use of required reason API」の続き
    • Active keyboard APIs
      • ↑これは、今回指摘されなかったためスキップ。
matsuchiyomatsuchiyo
  • 上の「Describing use of required reason API」の続き
    • User defaults API
      • CA92.1は、そのアプリ自身からのみ利用される情報の読み書きに使う場合、指定する。何かの一覧のソート順をUserDefaultsで保持している場合などがこれに当たりそう。

        CA92.1
        Declare this reason to access user defaults to read and write information that is only accessible to the app itself.

      • ↑と少し似ているけど、1C8F.1は、同じApp Group内のアプリ等から利用される情報の読み書きに使う場合指定する。
      • C56D.1は、File timestamp APIの0A2A.1と同じ感じかな。
      • AC6B.1が、よくわからない。

        AC6B.1
        Declare this reason to access user defaults to read the com.apple.configuration.managed key to retrieve the managed app configuration set by MDM, or to set the com.apple.feedback.managed key to store feedback information to be queried over MDM, as described in the Apple Mobile Device Management Protocol Reference documentation.

        • ?: MDMとは?→ 組織が、メンバーのiOSデバイスを管理するための機能みたい。今回は関係なさそう。

          モバイルデバイス管理のセキュリティの概要
          Appleのオペレーティングシステムはモバイルデバイス管理(MDM)に対応しています。これによって、組織は規模に応じて導入されているAppleデバイスを安全に設定し、管理することができます。
          ...
          MDMが安全に機能する仕組み
          ... IT部門はMDMを使用することで、企業環境へのAppleデバイスの登録、ワイヤレスでの設定の構成や更新、企業ポリシーへの準拠状況の監視、ソフトウェア・アップデート・ポリシーの管理、管理対象デバイスのリモートワイプやリモートロックなどを行うことができます。
          https://support.apple.com/ja-jp/guide/security/sec013b5d35d/web

matsuchiyomatsuchiyo
  • 上の「Describing use of required reason API」の続き
    • このドキュメントに関する疑問点
      • どのthird-party SDKが、どの"required reason API"を使っているか知る方法。
        • → 下のコメントの記事にある通り、ツールを使うとある程度見つけられそう。
      • 利用中のthird-party SDKが、privacy manifest fileを追加してくれない場合どうする?
        • → ライブラリの使用をやめる。
      • 利用しているthird-party SDKでfile timestamp APIの0A2A.1が宣言されている場合、アプリ側でfile timestamp APIのreasonを宣言する必要はあるのか?(した方が無難だと思うけど)
      • Crashlyticsどうしよう。disk spaceを自動で送っているはず。この自動で送るやり方は、当てはまるreasonがないから、今後は認められないのではないか。
        • appleに新しいreasonとしてリクエストするか?
        • Crashlyticsで、disk spaceを送信するかどうか指定できないか?
        • その通りで、今後は認められない。上の別コメントに記載の通り、Crashlyticsでdisk spaceにアクセスするのはやめたっぽい。そのため、firebase consoleではdisk spaceは見れなくなる。
        • 開発者としては、Crashlyticsを最新にすればOK。
      • Adjustによるattributionができなくなるのではないか。どうする?
matsuchiyomatsuchiyo
  • Privacy manifest files
    • このスクラップの2番目のコメント〜1つ上のコメントまで読んできた「Describing use of required reason API」の上位ドキュメント。
    • Privacy manifest fileで、appやthird-party SDKが、集めるデータと利用する"required reason API"を宣言する。また、集める理由、利用する理由も宣言する。

      The privacy manifest is a property list that records the types of data collected by your app or third-party SDK, and the required reasons APIs your app or third-party SDK uses. For each type of data your app or third-party SDK collects and category of required reasons API it uses, record the reasons in your privacy manifest file.

    • Privacy manifest fileでは、以下を設定する。
      • NSPrivacyTracking: App Tracking Trasparency Frameworkを使って追跡するかどうかの真偽値。
      • NSPrivacyTrackingDomains: 追跡するに当たって、広告ID(だっけ?)の送り先のドメイン。
        • この辺は、例えばAdMobを使っているなら、AdMobのドキュメントを見た方がいいのかも。
        • Adjustで広告IDを使っている場合、このドメインをAdjustのドキュメントで調べる必要がある。
      • NSPrivacyCollectedDataTypes: 収集するデータ(と、その理由?)
      • NSPrivacyAccessedAPITypes: 利用する"required reason API"とその理由
matsuchiyomatsuchiyo
  • Describing data use in privacy manifefsts : 当スクラップの1つ上のコメントのドキュメントのサブドキュメント。
    • ちゃんと読んでないけど、これまでApp Store Connectのフォーム(App Privacy?)で入力してきた内容を、Privacy manifest fileでも宣言する感じなのかな。
matsuchiyomatsuchiyo
  • アプリ開発者が Privacy Manifests 対応でやることについて調べてみた
    • 「アプリ開発者がやるべきことは大きく分けて 2つ です。」
      1. アプリ側で Privacy Manifests の宣言をする
      2. アプリが利用している Third-party SDK を Privacy Manifests 対応バージョンにアップデートする
    • Privacy manifest fileのNSPrivacyCollectedDataTypesは、自動でApp Store Connectには反映されない。二重管理が必要。

      ちなみにですが、現時点で Privacy Manifests の値を App Store Connect の設定に自動で反映してくれるような機構は残念ながらなさそう

    • NSPrivacyAccessedAPITypesについて、これ↓は知らなかった。

      UserDefaults では AppleKeyboards というキーでキーボードの情報が入手でき、こういった情報がフィンガープリントとして利用できるようです。したがって、利用用途を宣言する API として含まれているようです。

      • ?: ↑ AppleKeyboardsを使っている場合(third-party SDKが利用している場合含め。具体的にはAdjustとか使ってそう)、どうするの?⭐️
        • あてはまるreasonが見当たらないから、使ってはいけないということなのかな。
      • ↓以下のリンクで、2023/12/7時点でprivacy manifest対応がされた、主要SDKの一覧が見れるみたい。あとで見る。

        また、2023年12月7日に Apple から「一般的に使用される Third-party SDK」が公表されました。
        https://developer.apple.com/jp/support/third-party-SDK-requirements/

    • やはり、third-party SDKが対応してくれない場合、乗り換えないといけないみたい。

      対応されない場合、 SDK の乗り換えを検討する。

    • 以下のツールを使うと、ある程度検出できるみたい。

      ...nm コマンドを利用した検出ツール(スクリプト)を作っている方がいたのでそちらを紹介しようと思います。
      ...
      https://github.com/omarzl/ios_17_required_reason_api_scanner

    • required reason APIを使っている、すべてのthird-party SDKがprivacy manifestの対象。

      Apple が公開した「一般的に使用される Third-party SDK」のリストにある SDK 以外の Third-party SDK も Privacy Manifests 対応の対象か?
      記事中に記載の通り、データ収集を行なっているか、Required reason API を使っている場合は全て対象になるそうです。
      こちらの Apple Developer Forum の Apple の回答を参照ください。Apple Developer Program のサポートに問い合わせてもこの Forum の回答が正しいという回答をもらいました。

      • Forumの記載は以下。

        Any app and third party SDK that collects data, uses required reason API, or both must include a privacy manifest file. If your app uses an SDK not listed but that falls under the mentioned requirements, then this SDK must include a privacy manifest.
        Privacy manifest requirement for SDKs - https://developer.apple.com/forums/thread/743295?answerId=776587022#776587022

matsuchiyomatsuchiyo
  • Adjustのドキュメントを見てみる。
    • Adjust周りで気になっている点。
      • 引き続きattributionできるのか?
        • 広告IDが使えなくても、finger printでattributionしてた気がするけど、何を使っていたっけ?
          • → basic device info、IPアドレスなど。以下のAdjustのドキュメントによると、privacy manifestでAppleがfingerprintingとしているものには該当しないみたい。
        • 広告IDを送るためのエンドポイントは?
          • privacy manifestには設定不要。以下に記載したAdjust SDKのissueコメント参照。
        • "required reason API"を使っているのか?
          • この辺はわからない。以下に記載したAdjust SDKのissueコメントによると、Adjust SDKはprivacy manifestの対応をしなくていいらしい。すべての"requried reason API"を利用するthird-party SDKが対応するものだと思ってたので、納得できない...。
            • "required reason API"を使っていないのかも。
    • Making sense of iOS 14.5: attribution methods 2021/4/25
      • これを読んだ感じ、今回のAppleのPrivacy manifestは影響しなそう。
      • Adjust等は、fingerprintingからprobablisitic attributionに移行した。

        With the upcoming 14.5 changes, some companies (Adjust included) moved from fingerprinting to strictly probabilistic attribution.

      • fingerprintingは、デバイス情報を使って永続的かつユニークな識別子を使って追跡する方法。

        What is fingerprinting? A method to track users cross-site by utilizing device information to create a persistent and unique ID.

      • 一方、probabilisticでは、attributionのため一時的なデータを利用する。

        As 80% of installs happen within the first hour after click, such attribution does not require any persistent ID. We can make our predictions with temporary data that becomes obsolete within a few hours. ... We look at parameters such as time of click, time of install, and basic device info. These limited parameters allow us to estimate the source of an install for a few hours after a click.

    • What is mobile ad attribution? An introduction to app tracking
      • まずは「Device ID」(IDFA, AAID)で照合。
      • それがとれなかったら、広告タップ時のIPとインストール後起動時のIPを比較?
      • ...のような感じでattributionする。
      • ATTにopt-inすれば、これまで通りattributionできる(インストールされたアプリだけでなく広告が表示されたアプリでもopt-inされている必要があると思う)。opt-inされてなかったら、SKAdNetwork(SKAN)が使われる。
        • ?: ということは、今回のAppleのPrivacy Manifestで、ATTをtrueにしてdomainを指定する必要がある?
    • Apple App Storeにプライバシーに関する情報を提出
      • privacy manifest対応はまだリリースされていない。

        Adjustは、Appleのプライバシーマニフェストに対応するためのSDKアップデートを近日中にリリースする予定です。

      • Adjust SDKにはprivacy manifestは不要???

        注意:
        Adjust SDKのパーミッションを開示するためのプライバシーマニフェストの提出は任意です。お客様のアプリにAdjust SDKのみが含まれている場合、プライバシーマニフェストを提出する必要はありません。プライバシーマニフェストを必要とするサードパーティSDKのAppleのリストをご覧ください。

        • ?: "required reason API"は一切使ってないということ?
        • adjust/ios_sdkには、今のところPrivacyInfo.xcprivacyファイルは見当たらない。
        • 以下のissueのコメントによると、appleがリストアップしていないから、Adjust SDKはprivacy manifestの対応をする必要はないらしい。Adjustはユーザーへのわかりやすさのためprivacy manifest対応を進めているらしい。

          Additionally, Apple has not included our iOS SDK in the list of third-party SDKs that require a privacy manifest. That means our clients can publish or update new apps with our iOS SDK without including a privacy manifest.
          https://github.com/adjust/ios_sdk/issues/693#issuecomment-1954897383

          • ?: 全ての"required reason API"を利用するthird-party SDKが対応する必要があるのではないのか???⭐️
            • 上のコメントの記事を見ても、必要であるはず。Appleのサポートからも必要と言われたみたいなので、正しいはず。
            • Adjustは、"required reason API"を使っていないのかもしれない。
        • また同じコメントによると、privacy manifestへのdomainの追加も不要みたい。AppleからPoints of INterestと見なされていないため。(初めて知ったけど、ユーザーを追跡するためのドメインがAppleによってPoints of Interestとしてリストアップされているのかな。そこに当てはまる場合domainの追加が必要)

          I suggest not adding our URL "app.adjust.com" to the privacy manifest under NSPrivacyTrackingDomains. It should be all right not to have it configured because our URL isn't marked under the Points of Interest track.

matsuchiyomatsuchiyo

このスクラップの上のコメント記載のツールを使ってみる。

テキストベース検索:

% sh required_reason_api_text_scanner.sh ~/work/flutter_app/app_name/ios
Searching for use of required reason API
See https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api
Found potentially required reason API usage 'UserDefaults' in '~/work/flutter_app/app_name/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatLoggingTestUtils.swift'
Line numbers: 29 119 
Found potentially required reason API usage 'UserDefaults' in '~/work/flutter_app/app_name/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift'
Line numbers: 80 
Found potentially required reason API usage 'UserDefaults' in '~/work/flutter_app/app_name/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/Storage.swift'
Line numbers: 103 106 108 116 
Found potentially required reason API usage 'UserDefaults' in '~/work/flutter_app/app_name/ios/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/StorageFactory.swift'
Line numbers: 21 54 56 58 62 64 
Found potentially required reason API usage 'UserDefaults' in '~/work/flutter_app/app_name/ios/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsCacheClient.swift'
Line numbers: 38 39 44 49 51 56 59 66 77 86 87 

バイナリからの検索:

% sh required_reason_api_binary_scanner.sh ~/Library/Developer/Xcode/DerivedData/Runner-fzmmhafgpgdnvadlaugnmirfqlwa/Build/Products/Debug-iphoneos
Analyzing binaries: ./Runner.app/Runner ./qr_code_scanner/qr_code_scanner.framework/qr_code_scanner ...省略...
---
Used symbols in binary ./Runner.app/Runner: NSFileCreationDate, NSFileSystemFreeSize, NSFileSystemSize, NSUserDefaults, stat
Used symbols in binary ./qr_code_scanner/qr_code_scanner.framework/qr_code_scanner:
...省略...

これで、"required reason API"を使っているSDKを一つ一つ、更新していけば良さそう。

matsuchiyomatsuchiyo

上の結果を元に、Third-party SDKの更新

  • Firebase系
  • AdMob
  • Flutter
  • shared_preferences_ios
  • GoogleSignIn
  • flutter_local_notifications