Darwin Build Environment Help Center

Missing Privacy Manifest

append delete Lucas Peres

• Windows version: 11
• Builder version 3.70.3
• iOS SDK version: 18.2
• I would actually like to know if adding the privacy manifest is something the builder should do or if there is something wrong.

SDKs like Firebase are required to include a privacy manifest, which I checked and is indeed in their Pod, but I believe the builder is not adding it to the package, since after uploading I'm getting the following message:

ITMS-91061: Missing privacy manifest - Your app includes “Frameworks/FirebaseCore.framework/FirebaseCore”, which includes FirebaseCore, an SDK that was identified in the documentation as a commonly used third-party SDK. Starting February 12, 2025, if a new app includes a commonly used third-party SDK, or an app update adds a new commonly used third-party SDK, the SDK must include a privacy manifest file or you won’t be able to submit the app for review in App Store Connect. Please contact the provider of the SDK that includes this file to get an updated SDK version with a privacy manifest. For more details about this policy, including a list of SDKs that are required to include signatures and manifests, visit: https://developer.apple.com/support/third-party-SDK-requirements.

I actually don't know if there is something I need to do.

Thanks a lot for all the support you've done

Reply RSS

Replies

append delete #1. MaroLFC

i have the same problem too

append delete #2. YoNeyers

did you find a fix for it? i got same thing today

append delete #3. YoNeyers

i found this video, but in xcode.
https://www.youtube.com/watch?v=T6IvImk66m8

can we use it with builder?

append delete #4. Ruslan

The same problem
Maybe someone knows the decision? Editing some files?

append delete #5. Pierre-Marie Baty

Hello

Use a pre-packaging script to copy the final PrivacyInfo.xcprivacy file in your app bundle's next to the final Info.plist. Something like this:

% embed-privacy-info.bat
@echo off

rem // copy the PrivacyInfo.xcprivacy file that the App Store expects to find for your app
copy /y /b "C:\path\to\my\apps\PrivacyInfo.xcprivacy" "%TARGET_BUILD_DIR%\%NAME%.app"

rem // if third-party frameworks have a PrivacyInfo.xcprivacy file too, copy them in the relevant places
copy /y /b "C:\path\to\framework1\PrivacyInfo.xcprivacy" "%TARGET_BUILD_DIR%\%NAME%.app\Frameworks\framework1.framework"
 copy /y /b "C:\path\to\framework2\PrivacyInfo.xcprivacy" "%TARGET_BUILD_DIR%\%NAME%.app\Frameworks\framework2.framework"
rem // etc...
%

:: @Pierre-Marie Baty added on 03 Mar ’25 · 15:24

*edit* more info about pre-packaging scripts can be found in the builder's documentation (readme.html).

append delete #6. YoNeyers

thank you so mcuh Pierre-Marie Baty,

can you give me an example with firebase?
or just should i use embed-privacy-info.bat as it's.

what should i change ^_^ , thank you so much

append delete #7. Ancelotti

Same issue here, I’d really appreciate your help, @Pierre-Marie Baty.

append delete #8. Pierre-Marie Baty

You need to copy the file called "PrivacyInfo.xcprivacy" for your app (if your code use APIs from the iOS SDK that imply you need one) next to your app's Info.plist in the app bundle.

And similarly, you need to copy the file called "PrivacyInfo.xcprivacy" of each framework that requires one next to that framework's Info.plist.

The app bundle is the directory ending in ".app" that the builder constructs, and which is then zipped into an .ipa file. Before it is zipped, it can be found (for a Unity project) in build\Release-iphoneos\iPhone-target\yourAppName.app.

Just write a batch script that does this. If you're not comfortable with batch scripts, write a powershell one.

I can provide more details on whatever point that needs it (just ask), but I cannot write the keys-in-hand script for everyone of you : every project has its own particularities, each one of you has it under a different path, each of you has a different set of .xcprivacy files, located in different places, and I'd feel I'd be doing everybody's homework here.

append delete #9. YoNeyers

thanks again Pierre-Marie Baty :)
Pierre-Marie Batyif it's wrong correct me.

guys i made a bat code , and it's worked i uploaded my game with no error.
i hope it's helped.

% 
@echo off
setlocal enabledelayedexpansion

:: Define paths
set "AppBundlePath=D:\WORK BUILD UNITY\XCODE\59Firebase\build\Release-iphoneos\iPhone-target\ProductName.app"
set "FrameworksPath=%AppBundlePath%\Frameworks"
set "AppPrivacyFile=D:\WORK BUILD UNITY\XCODE\59Firebase\UnityFramework\PrivacyInfo.xcprivacy"

:: Check if the main PrivacyInfo.xcprivacy file exists
if exist "%AppPrivacyFile%" (
    copy "%AppPrivacyFile%" "%AppBundlePath%\" /Y
    echo ✅ Copied main PrivacyInfo.xcprivacy to App Bundle
) else (
    echo ❌ ERROR: Main PrivacyInfo.xcprivacy file not found at %AppPrivacyFile%
    pause
    exit /b
)

:: Copy PrivacyInfo.xcprivacy to each framework (if frameworks exist)
if exist "%FrameworksPath%" (
    for /D %%F in ("%FrameworksPath%\*") do (
        set "TargetFolder=%%F"
        copy "%AppPrivacyFile%" "!TargetFolder!\" /Y
        echo ✅ Copied PrivacyInfo.xcprivacy to !TargetFolder!
    )
) else (
    echo ❌ WARNING: Frameworks directory not found at %FrameworksPath%
)

echo ✅ PrivacyInfo.xcprivacy files copied successfully!

%

YOU need to change these :

① AppBundlePath : put your build path there , then ⇉ \build\Release-iphoneos\iPhone-target\ProductName.app"

②AppPrivacyFile : put where is the PrivacyInfo.xcprivacy is , it was under "UnityFramework\PrivacyInfo.xcprivacy".

③Before Upload it , check the Packages folder "ProductName.ipa" make it "zip" file , then open Payload>ProductName.app> there you sholud see PrivacyInfo.xcprivacy next to Info.plist.

④Open Frameworks folder > check all your frameworks folders it should all has PrivacyInfo.xcprivacy inside it.

upload your ProductName.ipa and see if it's works.

* when i uploaded that ITMS-91061: Missing privacy manifest email gone , now i'm waiting for review, i just need to wait now.

append delete #10. YoNeyers

i can confirm now , my game accepted

append delete #11. Pierre-Marie Baty

@YoNeyers: this script can work, but note here that you're copying the same PrivacyInfo.xcprivacy in two places. I think one should be enough, so if you have only one .xcprivacy file, it might be best to copy it just once, in the app bundle.

Also note that when the pre-packaging script is run, there are already a few environment variables set by the master build script that you can reuse, that already point to common build locations. To obtain the list of those variables, put "set & pause" somewhere in your script. The variables will be displayed the next time you build your project and it'll wait for you to press a key. Copy/paste them somewhere for reference, and remove "set & pause". Then you can rewrite your script into a reusable one using these variables, that will automatically adjust the paths to your specific project.

#12. YoNeyers

This post was deleted by its owner

append delete #13. YoNeyers

ah i see thanks ,

btw do you know how i can get the bath of the project?
i wanna get the path that are put in iOS builder ,
so the code will run automatically without need to change it in code "AppBundlePath ".

append delete #14. Pierre-Marie Baty

Like I said. Use the %TARGET_BUILD_DIR% and %NAME% environment variables like this: %TARGET_BUILD_DIR%\%NAME%.app

append delete #15. Ruslan

Hello Pierre-Marie Baty,

In my case, I am using CocoaPods, and the files are located in different folders. This is screenshot
https://i.postimg.cc/hjzWJZnB/image-2025-03-20-213911766.png

In this situation, do I need to specify the path for each file separately? But then, what should I do if there is only one framework in the Frameworks folder: C:\Users\LocalComp\Desktop\build\Frameworks\com.unity.ads?

For example, with your command:
"copy /y /b "C:\path\to\framework1\PrivacyInfo.xcprivacy" "%TARGET_BUILD_DIR%\%NAME%.app\Frameworks\framework1.framework"", I have nothing to associate this file with.
Could you please advise?

The solution described above by another person also doesn't work for me because the files are not located in the corresponding paths in my project.

Thank you in advance!

append delete #16. Pierre-Marie Baty

Hello Ruslan,

If your project has multiple PrivacyInfo.xcprivacy files, supplied by different pods, try in this order:

1. Merge all these files into one using a text editor (they're basically XML files, so just copy the key/values to form one single XML file, merging the keys that have the same name), then use only the resulting PrivacyInfo.xcprivacy file as the sole privacy info file source for your app, and copy it in place using the pre-packaging script technique described above.

2. If the above doesn't work, try copying each .xcprivacy file (from each pod that has one) to its relevant compiled .framework folder (for example, C:\Users\LocalComp\Desktop\build\Pods\GoogleUtilities\GoogleUtilities\Privacy\PrivacyInfo.xcprivacy would go to %TARGET_BUILD_DIR%\%NAME%.app\Frameworks\GoogleUtilities.framework\PrivacyInfo.xcprivacy -- this is just an example) using multiple copy statements, one for each file, using the same technique as above.

I'm not sure how Apple prefers this information to be presented in the final app, either one single .xcprivacy file for the whole app, or one per Mach-O executable. I read there should be one for each executable bundle, but while the compiled .app directory itself is a bundle, each dynamic framework in a .framework directory inside it is *also* a bundle, so...

append delete #17. Ruslan

Hello Pierre-Marie Baty,

I'm writing to you about the same issue. No matter how many times I try, I can't seem to submit the build for review. I thought maybe the new version of your program had implemented automatic detection and inclusion of these entries in the final file, but unfortunately, that doesn't seem to be the case.

My latest attempt was with this batch file:

@echo off

copy /y /b "C:\Users\LocalComp\Desktop\build\Pods\GoogleUtilities\GoogleUtilities\Privacy\Resources\PrivacyInfo.xcprivacy" "%TARGET_BUILD_DIR%\%NAME%.app\Frameworks\GoogleUtilities.framework"
copy /y /b "C:\Users\LocalComp\Desktop\build\Pods\nanopb\spm_resources\PrivacyInfo.xcprivacy" "%TARGET_BUILD_DIR%\%NAME%.app\Frameworks\nanopb.framework"
echo ✅ PrivacyInfo.xcprivacy files copied successfully!

But I keep receiving the same email from Apple every time:
https://postimg.cc/Ff72r8p0

As before, I’ve already shared screenshots of all the files in my project, but I’m attaching them again for reference:
https://i.postimg.cc/hjzWJZnB/image-2025-03-20-213911766.png

I also tried merging everything into a single file as you suggested earlier and adding it to the final build, but it still didn't work.

Could I be doing something wrong with the process?
Here's what I'm doing step by step:

- Build the project in Unity.
- In the iOS builder, I add the executable file to the appropriate window so it gets included during the build.
- That's it.

Am I missing something in this workflow?

I’d really appreciate any help you can provide. I’m exhausted from repeatedly submitting the build only to encounter the same binary error minutes later.

I sincerely apologize for troubling you again regarding this issue.

Best regards,
Ruslan.

append delete #18. Pierre-Marie Baty

Hello @Ruslan

You said: "I also tried merging everything into a single file as you suggested earlier and adding it to the final build, but it still didn't work."

My understanding has progressed on this and I think that's the way to go. So maybe there was a formatting problem in the XML file you created. Could you show me the result of this merge ?

append delete #19. Ruslan

https://pmbaty.com/paste/?a34c30db1249d4bb#FeVCuWbxj8n8nD76r1u2HhC8hgPJkZFACgwL2eon2MYA

In the linked document, I first shared the results, then provided the raw/unedited source code files. Among the 5 files, there were 2 pairs of identical codes, so I ultimately submitted 3 distinct versions

append delete #20. Pierre-Marie Baty

It is possible that the two empty lines at the beginning of the NSPrivacyAccessedAPITypes array make the Apple parser choke. Try removing them. Also, it might be that Apple expects this property list to be converted to binary format. Use the "plconvert" command-line utility (from the Toolchain directory) to do that. Let me know, I think we're close to success.

append delete #21. Ruslan

Can you clarify, when I combine everything into one file, will I need to sign each framework that Apple requires twice in this case?
So, for 1 file, will the two commands for signing each framework look something like this?

copy /y /b "C:\Users\LocalComp\Desktop\build\PrivacyInfo.xcprivacy" "%TARGET_BUILD_DIR%\%NAME%.app\Frameworks\GoogleUtilities.framework"
copy /y /b "C:\Users\LocalComp\Desktop\build\PrivacyInfo.xcprivacy" "%TARGET_BUILD_DIR%\%NAME%.app\Frameworks\nanopb.framework"

Also, I’m not entirely sure how to use your utility—could you provide some guidance? After I make the file binary, will the compiler still read it without any issues and perform the file signing?

Sorry for the large number of questions.

append delete #22. Pierre-Marie Baty

There might be a misunderstanding on terminology here. "Signing" means "code signing", it is the process by which a bundle is sealed by a code signature, embedding a signer certificate, that covers both the code and the resources. This is done at the last step of the build process, by the code signer, after all pre-packaging scripts have been executed, and before the app is packaged in an .ipa bundle. So, if your scripts change anything in the app's structure, the code signer will sign the app in the very state that your scripts left it, and the code signature will be objectively valid - no matter whether the data that was signed was correct. You don't need to sign it again after this point, unless you intend to unpack an .ipa, make changes to it, and pack it again. Also, the code signing process is recursive, which means every signable framework and bundle in your app that can be signed, in addition to the app itself, will be signed, as well as any framework and bundle on which these frameworks depend.

The 2 lines you posted don't "sign" anything. They just copy a file from one location to another.

Property lists in either XML or binary format are read and understood in a strictly equivalent way by the toolchain's utilities. My plist library understands 3 formats: XML, binary and NeXTStep/ASCII (the latter for .pbxproj files, which are also property lists, although this format comes straight from the 1990s and is no longer documented anywhere AFAIK). Converting your .plist files from one format to another is indifferent to the code signer.

I hope it begins to be more clear for you.

append delete #23. Ruslan

Yes, sorry for the misunderstanding in terminology, I might not be expressing myself correctly.

Still, to solve the issue, Apple says that 'the SDK must include a privacy manifest file.'
I wanted to check with you if I'm applying the commands I wrote above correctly.
Do I need to copy the same manifest file into different folders referenced by Apple?

And my second question was about how to use your utility 'plconvert' to convert it into a binary file? I couldn't find any information about this in the README file.

Once again, I apologize—my questions might seem silly.

append delete #24. Pierre-Marie Baty

Forget what I said before. We were on the wrong track.

By reading this article: https://developer.apple.com/documentation/Technotes/tn3181-debugging-invalid-privacy-manifest?language=objc on the Apple website, I am under the impression that an iOS app may include *several* privacy manifests, i.e. one per SDK:

If you upload an app to App Store Connect that contains invalid privacy manifest files, you’ll receive an email that includes the name and path of the invalid files in your app bundle.

Note the plural.
This contradicts the impression I had in post #18.

The conclusion is that you don't need to merge all the privacy manifest files in a single one, just take each of them as they are supplied by each SDK provider, and copy them in the relevant framework in the final app. And there's no need to convert it to binary format either, a simple copy is sufficient.

Use this script and make the necessary changes:

% pre-packaging-script.cmd
@echo off
setlocal enabledelayedexpansion

rem // in case your own code makes use of Apple APIs that require a PrivacyInfo file,
rem // then uncomment these lines and change the path to your own PrivacyInfo.xcprivacy file
rem set PRIVACY_FILE="C:\Path\To\Your\Own\PrivacyInfo.xcprivacy"
rem copy /b /y "%PRIVACY_FILE%" "%TARGET_BUILD_DIR%\%NAME%.app"

rem // now process the PrivacyInfo files supplied by Google
rem // this is based on the screenshot you published in post #15.
if exist "Pods\PromisesObjC\Sources\FBLPromises\Resources\PrivacyInfo.xcprivacy" (
   if exist "%TARGET_BUILD_DIR%\%NAME%.app\Frameworks\FBLPromises.framework\" (
      copy /b /y "Pods\PromisesObjC\Sources\FBLPromises\Resources\PrivacyInfo.xcprivacy" "%TARGET_BUILD_DIR%\%NAME%.app\Frameworks\FBLPromises.framework\"
   )
)
if exist "Pods\GoogleUtilities\GoogleUtilities\Privacy\PrivacyInfo.xcprivacy" (
   if exist "%TARGET_BUILD_DIR%\%NAME%.app\Frameworks\GoogleUtilities.framework\" (
      copy /b /y "Pods\GoogleUtilities\GoogleUtilities\Privacy\PrivacyInfo.xcprivacy" "%TARGET_BUILD_DIR%\%NAME%.app\Frameworks\GoogleUtilities.framework\"
   )
)
if exist "Pods\nanopb\spm_resources\PrivacyInfo.xcprivacy" (
   if exist "%TARGET_BUILD_DIR%\%NAME%.app\Frameworks\nanopb.framework\" (
      copy /b /y "Pods\nanopb\spm_resources\PrivacyInfo.xcprivacy" "%TARGET_BUILD_DIR%\%NAME%.app\Frameworks\nanopb.framework\"
   )
)
if exist "Pods\GoogleUserMessagingPlatform\Frameworks\Release\UserMessagingPlatform.xcframework\ios-arm64\UserMessagingPlatform.framework\PrivacyInfo.xcprivacy" (
   if exist "%TARGET_BUILD_DIR%\%NAME%.app\Frameworks\UserMessagingPlatform.framework\" (
      copy /b /y "Pods\GoogleUserMessagingPlatform\Frameworks\Release\UserMessagingPlatform.xcframework\ios-arm64\UserMessagingPlatform.framework\PrivacyInfo.xcprivacy" "%TARGET_BUILD_DIR%\%NAME%.app\Frameworks\UserMessagingPlatform.framework\"
   )
)
%

I haven't tested this script (and I cannot, since it's specific to your situation), but it should be clear enough for you to understand what's going on and how to fix it if necessary.

Reply

(Leave this as-is, it’s a trap!)

There is no need to “register”, just enter the same name + password of your choice every time.

Pro tip: Use markup to add links, quotes and more.

Moderators: Pierre-Marie Baty