Skip to content

Commit

Permalink
Added Apple privacy manifests for iOS and macOS (#8680)
Browse files Browse the repository at this point in the history
* Added Apple privacy manifests for iOS and macOS

* Upload manifest to extender and use in bundle

* Update BundleHelper.java

* Update BundleHelper.java

* Update game.project
  • Loading branch information
britzl committed Mar 27, 2024
1 parent bb12481 commit 1411e25
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,33 @@ public List<ExtenderResource> writeManifestFiles(Platform platform, File manifes
return resolvedManifests;
}

/**
* Copy a PrivacyInfo.xcprivacy to a target folder. The file will either be
* copied from the extender build results or if that doesn't exist it will
* copy from the privacy manifest set in game.project
* @param project
* @param platform
* @param appDir Directory to copy to
*/
public static void copyPrivacyManifest(Project project, Platform platform, File appDir) throws IOException {
final String privacyManifestFilename = "PrivacyInfo.xcprivacy";
File targetPrivacyManifest = new File(appDir, privacyManifestFilename);

File extenderBuildDir = new File(project.getRootDirectory(), "build");
File extenderBuildPlatformDir = new File(extenderBuildDir, platform.getExtenderPair());

File extenderPrivacyManifest = new File(extenderBuildPlatformDir, privacyManifestFilename);
if (extenderPrivacyManifest.exists()) {
FileUtils.copyFile(extenderPrivacyManifest, targetPrivacyManifest);
}
else {
IResource defaultPrivacyManifest = project.getResource(platform.getExtenderPaths()[0], "privacymanifest", false);
if (defaultPrivacyManifest.exists()) {
ExtenderUtil.writeResourceToFile(defaultPrivacyManifest, targetPrivacyManifest);
}
}
}

public void updateTemplateProperties() throws CompileExceptionError, IOException {
String title = this.projectProperties.getStringValue("project", "title", "Unnamed");
String exeName = BundleHelper.projectNameToBinaryName(title);
Expand All @@ -247,7 +274,8 @@ public void updateTemplateProperties() throws CompileExceptionError, IOException
IBundler bundler = getOrCreateBundler();
bundler.updateManifestProperties(project, platform, this.projectProperties, this.propertiesMap, this.templateProperties);
}
private File getAppManifestFile(Platform platform, File appDir) throws CompileExceptionError {

private File getAppManifestFile(Platform platform, File appDir) throws CompileExceptionError {
IBundler bundler = getOrCreateBundler();
String name = bundler.getMainManifestTargetPath(platform);
return new File(appDir, name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,10 @@ else if (identity == null) {

BundleHelper.throwIfCanceled(canceled);

// Copy PrivacyManifest.xcprivacy
BundleHelper.copyPrivacyManifest(project, platform, appDir);
BundleHelper.throwIfCanceled(canceled);

// Package zip file
File tmpZipDir = createTempDirectory();
FileUtil.deleteOnExit(tmpZipDir);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,5 +180,8 @@ public void bundleApplication(Project project, Platform platform, File bundleDir
}

BundleHelper.throwIfCanceled(canceled);

// Copy PrivacyManifest.xcprivacy
BundleHelper.copyPrivacyManifest(project, platform, appDir);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,10 @@ infoplist.type = resource
infoplist.help = custom Info.plist template file
infoplist.default = /builtins/manifests/ios/Info.plist
privacymanifest.type = resource
privacymanifest.help = Privacy Manifest file
privacymanifest.default = /builtins/manifests/ios/PrivacyInfo.xcprivacy
default_language.type = string
default_language.help = default language and region (CFBundleDevelopmentRegion)
default_language.default = en
Expand Down Expand Up @@ -522,10 +526,15 @@ help = Mac OSX related settings
app_icon.type = resource
app_icon.help = bundle icon file (.icns)
app_icon.default =
infoplist.type = resource
infoplist.help = custom Info.plist template file
infoplist.default = /builtins/manifests/osx/Info.plist
privacymanifest.type = resource
privacymanifest.help = Privacy Manifest file
privacymanifest.default = /builtins/manifests/osx/PrivacyInfo.xcprivacy
bundle_identifier.type = string
bundle_identifier.help = bundle identifier (CFBundleIdentifier)
bundle_identifier.default = example.unnamed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public class ExtenderUtil {

public static final String appManifestPath = "_app/" + ExtenderClient.appManifestFilename;
public static final String proguardPath = "_app/app.pro";
public static final String privacyManifestPath = "_app/PrivacyInfo.xcprivacy";
public static final String JAR_RE = "(.+\\.jar)";

private static class FSExtenderResource implements ExtenderResource {
Expand Down Expand Up @@ -533,6 +534,20 @@ public static List<ExtenderResource> getExtensionSources(Project project, Platfo
}
}

// For iOS and macOS only: Add the project privacy manifest
if (platform == Platform.Arm64Ios || platform == Platform.X86_64Ios) {
IResource resource = getProjectResource(project, "ios", "privacymanifest");
if (resource != null) {
sources.add(new FSAliasResource(resource, project.getRootDirectory(), privacyManifestPath));
}
}
else if (platform == Platform.Arm64MacOS || platform == Platform.X86_64MacOS) {
IResource resource = getProjectResource(project, "osx", "privacymanifest");
if (resource != null) {
sources.add(new FSAliasResource(resource, project.getRootDirectory(), privacyManifestPath));
}
}

// Find engine extension folders
List<String> extensionFolders = getEngineExtensionFolders(project);
for (String extension : extensionFolders) {
Expand Down
14 changes: 14 additions & 0 deletions editor/resources/meta.edn
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,13 @@
:label "Info.plist"
:default "/builtins/manifests/ios/Info.plist",
:path ["ios" "infoplist"]}
{:type :resource,
:filter "xcprivacy",
:preserve-extension true,
:help "Privacy Manifest file",
:label "PrivacyInfo.xcprivacy"
:default "/builtins/manifests/ios/PrivacyInfo.xcprivacy",
:path ["ios" "privacymanifest"]}
{:type :resource,
:filter ["entitlements", "xcent", "plist"],
:preserve-extension true,
Expand Down Expand Up @@ -731,6 +738,13 @@
:label "Info.plist",
:default "/builtins/manifests/osx/Info.plist",
:path ["osx" "infoplist"]}
{:type :resource,
:filter "xcprivacy",
:preserve-extension true,
:help "Privacy Manifest file",
:label "PrivacyInfo.xcprivacy"
:default "/builtins/manifests/osx/PrivacyInfo.xcprivacy",
:path ["osx" "privacymanifest"]}
{:type :string,
:help "default language and region (CFBundleDevelopmentRegion)",
:default "en",
Expand Down
2 changes: 2 additions & 0 deletions editor/test/resources/save_data_project/game.project
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ bundle_identifier = com.defold.save-data-project
bundle_name = Save Data Project
bundle_version = 1.0
infoplist = /builtins/manifests/ios/Info.plist
privacymanifest = /builtins/manifests/ios/PrivacyInfo.xcprivacy
default_language = en
localizations = en
entitlements = /referenced/entitlements.plist
Expand All @@ -114,6 +115,7 @@ bundle_identifier = com.defold.save-data-project
bundle_name = Save Data Project
bundle_version = 1.0
infoplist = /builtins/manifests/osx/Info.plist
privacymanifest = /builtins/manifests/osx/PrivacyInfo.xcprivacy
app_icon = /referenced/icon-macos.icns

[windows]
Expand Down
35 changes: 35 additions & 0 deletions engine/engine/content/builtins/manifests/ios/PrivacyInfo.xcprivacy
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyTrackingDomains</key>
<array>
</array>
<key>NSPrivacyCollectedDataTypes</key>
<array>
</array>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<!-- fstat() in mount_mmap.cpp -->
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
<!-- NSPrivacyAccessedAPICategorySystemBootTime() in Remotery.c -->
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
</array>
</dict>
</array>
</dict>
</plist>
35 changes: 35 additions & 0 deletions engine/engine/content/builtins/manifests/osx/PrivacyInfo.xcprivacy
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyTrackingDomains</key>
<array>
</array>
<key>NSPrivacyCollectedDataTypes</key>
<array>
</array>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<!-- fstat() in mount_mmap.cpp -->
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
<!-- NSPrivacyAccessedAPICategorySystemBootTime() in Remotery.c -->
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
</array>
</dict>
</array>
</dict>
</plist>

0 comments on commit 1411e25

Please sign in to comment.