How to create a privacy manifest and include it in your iOS app

Starting from the 1st of May 2024, iOS apps submitted to the AppStore must include a privacy manifest.

What is a Privacy Manifest?

A privacy manifest is a property list file (with the extension .xcprivacy) that contains information about your app's data collection practices and the reasons for using specific privacy-sensitive APIs. This file must be included in your app's bundle.

Creating a Privacy Manifest

The easiest way is to edit the default Privacy Manifest template, which will be automatically included in your standalone as of LiveCode 9.6.12 RC-1:

You need to provide values for the NSPrivacyAccessedAPITypeReasons key, for each one of these 3 NSPrivacyAccessedAPITypes:

- NSPrivacyAccessedAPICategoryFileTimestamp

- NSPrivacyAccessedAPICategorySystemBootTime

- NSPrivacyAccessedAPICategoryDiskSpace (optional)

File timestamp APIs

Use the string NSPrivacyAccessedAPICategoryFileTimestamp as the value for the NSPrivacyAccessedAPIType key in your NSPrivacyAccessedAPITypes dictionary.

In your NSPrivacyAccessedAPITypeReasons array, supply the relevant values from this list.

DDA9.1

Declare this reason to display file timestamps to the person using the device.Information accessed for this reason, or any derived information, may not be sent off-device.

C617.1 (included in default privacy manifest)

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.

3B52.1 (included in default privacy manifest)

Declare this reason to access the timestamps, size, or other metadata of files or directories that the user specifically granted access to, such as using a document picker view controller.

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).

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.

Example part of the manifest:

		<dict>
			<key>NSPrivacyAccessedAPIType</key>
			<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
			<key>NSPrivacyAccessedAPITypeReasons</key>
			<array>
				<string>C617.1</string>
				<string>3B52.1</string>
			</array>
		</dict>

System boot time APIs

Use the string NSPrivacyAccessedAPICategorySystemBootTime as the value for the NSPrivacyAccessedAPIType key in your NSPrivacyAccessedAPITypes dictionary.

In your NSPrivacyAccessedAPITypeReasons array, supply the relevant values from the list below.

35F9.1 (included in default privacy manifest)

Declare this reason to access the system boot time in order to measure the amount of time that has elapsed between events that occurred within the app or to perform calculations to enable timers.

Information accessed for this reason, or any derived information, may not be sent off-device. There is an exception for information about the amount of time that has elapsed between events that occurred within the app, which may be sent off-device.

8FFB.1 (included in default privacy manifest)

Declare this reason to access the system boot time to calculate absolute timestamps for events that occurred within your app, such as events related to the UIKit or AVFAudio frameworks.

Absolute timestamps for events that occurred within your app may be sent off-device. System boot time accessed for this reason, or any other information derived from system boot time, may not be sent off-device.

3D61.1

Declare this reason to include system boot time information in an optional bug report that the person using the device chooses to submit. The system boot time information must be prominently displayed to the person as part of the report.

Information accessed for this reason, or any derived information, may be sent off-device only after the user affirmatively chooses to submit the specific bug report including system boot time information, and only for the purpose of investigating or responding to the bug report.

Example part of the manifest:

		<dict>
			<key>NSPrivacyAccessedAPIType</key>
			<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
			<key>NSPrivacyAccessedAPITypeReasons</key>
			<array>
				<string>35F9.1</string>
				<string>8FFB.1</string>
			</array>
		</dict>

Disk space APIs

Use the string NSPrivacyAccessedAPICategoryDiskSpace as the value for the NSPrivacyAccessedAPIType key in your NSPrivacyAccessedAPITypes dictionary.

In your NSPrivacyAccessedAPITypeReasons array, supply the relevant values from the list below.

85F4.1

Declare this reason to display disk space information to the person using the device. Disk space may be displayed in units of information (such as bytes) or units of time combined with a media type (such as minutes of HD video).

Information accessed for this reason, or any derived information, may not be sent off-device. There is an exception that allows the app to send disk space information over the local network to another device operated by the same person only for the purpose of displaying disk space information on that device; this exception only applies if the user has provided explicit permission to send disk space information, and the information may not be sent over the Internet.

E174.1 (included in default privacy manifest)

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.

Information accessed for this reason, or any derived information, may not be sent off-device. There is an exception that allows the app to avoid downloading files from a server when disk space is insufficient.

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.

Information accessed for this reason, or any derived information, may be sent off-device only after the user affirmatively chooses to submit the specific bug report including disk space information, and only for the purpose of investigating or responding to the bug report.

B728.1

Declare this reason if your app is a health research app, and you access this API category to detect and inform research participants about low disk space impacting the research data collection.

Your app must comply with App Store Review Guideline 5.1.3 (see here). Your app must not offer any functionality other than providing information about and allowing people to participate in health research.

Example part of the manifest:

		<dict>
			<key>NSPrivacyAccessedAPIType</key>
			<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
			<key>NSPrivacyAccessedAPITypeReasons</key>
			<array>
				<string>E174.1</string>
			</array>
		</dict>

More APIs that need a reasons array

Note that the first two 2 NSPrivacyAccessedAPITypes (NSPrivacyAccessedAPICategoryFileTimestamp and NSPrivacyAccessedAPICategorySystemBootTimehave) have to be included in your privacy manifest, along with their reasons arrays, since they are referring to APIs that the LiveCode engine uses. If your app uses the revDB external with SQLite, then you have to include the NSPrivacyAccessedAPICategoryDiskSpace NSPrivacyAccessedAPIType too.

There are another 2 NSPrivacyAccessedAPITypes, which you have to include in the privacy manifest, if your app uses an LC external or an LCB extension that uses the following APIs:

Active keyboard APIs

The following API for accessing the list of active keyboards requires reasons for use. Use the string NSPrivacyAccessedAPICategoryActiveKeyboards as the value for the NSPrivacyAccessedAPIType key in your NSPrivacyAccessedAPITypes dictionary.

activeInputModes https://developer.apple.com/documentation/uikit/uitextinputmode/1614522-activeinputmodes?language=objc

In your NSPrivacyAccessedAPITypeReasons array, supply the relevant values from the list below.

3EC4.1

Declare this reason if your app is a custom keyboard app, and you access this API category to determine the keyboards that are active on the device.

Providing a systemwide custom keyboard to the user must be the primary functionality of the app.

Information accessed for this reason, or any derived information, may not be sent off-device.

54BD.1

Declare this reason to access active keyboard information to present the correct customized user interface to the person using the device. The app must have text fields for entering or editing text and must behave differently based on active keyboards in a way that is observable to users.

Information accessed for this reason, or any derived information, may not be sent off-device.

User defaults APIs

The following API for accessing user defaults requires reasons for use. Use the string NSPrivacyAccessedAPICategoryUserDefaults as the value for the NSPrivacyAccessedAPIType key in your NSPrivacyAccessedAPITypes dictionary.

NSUserDefaults https://developer.apple.com/documentation/foundation/nsuserdefaults?language=objc

In your NSPrivacyAccessedAPITypeReasons array, supply the relevant values from the list below.

CA92.1

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

This reason does not permit reading information that was written by other apps or the system, or writing information that can be accessed by other apps.

1C8F.1

Declare this reason to access user defaults to read and write information that is only accessible to the apps, app extensions, and App Clips that are members of the same App Group as the app itself.

This reason does not permit reading information that was written by apps, app extensions, or App Clips outside the same App Group or by the system. Your app is not responsible if the system provides information from the global domain because a key is not present in your requested domain while your app is attempting to read information that apps, app extensions, or App Clips in your app's App Group write.

This reason also does not permit writing information that can be accessed by apps, app extensions, or App Clips outside the same App Group.

C56D.1

Declare this reason if your third-party SDK is providing a wrapper function around user defaults API(s) for the app to use, and you only access the user defaults 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).

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.

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.

How to include the privacy manifest file in my iOS app?

All you have to do, is to ensure your privacy manifest file is named PrivacyInfo.xcprivacy and then add it to the Copy Files section of the standalone application settings. This will replace any default privacy manifest that is added by LiveCode (as of LiveCode 9.6.12 RC1 and above)

For more info, you can have a look at Apple's official docs here

2 Comments

Trevix

Sigh...I may need some user case example, to apply this lesson.
I find it really hard to understand which data collection practice applies or not applies.
At first, it seems that any "complete" commercial app does everything of the above.
Regards

Panos Merakos

Hello Trevix,

I think the main question is does the data being collected stay in the device - or is it sent to a server or such?

If the data stays in the device, then the default privacy manifest that is auto-included when building with LC 9.6.12 RC-1 or 10 DP-8 is likely to cover most (if not all) of your use cases.

If the data leaves the device - then you might have to add the relevant codes in each category in a custom manifest and include it in the Copy Files.

Regards,
Panos
--

Add your comment

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.