From 7446826ab9a0d740f80f6f72202fe2614d74ce0b Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Mon, 8 Apr 2024 10:18:24 +0300 Subject: [PATCH] =?UTF-8?q?=EF=BB=BF[iOS=20export]=20Add=20support=20for?= =?UTF-8?q?=20privacy=20manifest=20configuration.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- misc/dist/ios_xcode/PrivacyInfo.xcprivacy | 10 + .../godot_ios.xcodeproj/project.pbxproj | 4 + .../doc_classes/EditorExportPlatformIOS.xml | 441 ++++++++++++++++++ platform/ios/export/export_plugin.cpp | 225 +++++++++ 4 files changed, 680 insertions(+) create mode 100644 misc/dist/ios_xcode/PrivacyInfo.xcprivacy diff --git a/misc/dist/ios_xcode/PrivacyInfo.xcprivacy b/misc/dist/ios_xcode/PrivacyInfo.xcprivacy new file mode 100644 index 00000000000..bc4a893d587 --- /dev/null +++ b/misc/dist/ios_xcode/PrivacyInfo.xcprivacy @@ -0,0 +1,10 @@ + + + + + NSPrivacyAccessedAPITypes + $priv_api_types + $priv_tracking + $priv_collection + + diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj index e9efea88094..a5de7e88727 100644 --- a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj +++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 9039D3BE24C093AC0020482C /* MoltenVK.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9039D3BD24C093AC0020482C /* MoltenVK.xcframework */; }; D0BCFE4618AEBDA2004A7AAE /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D0BCFE4418AEBDA2004A7AAE /* InfoPlist.strings */; }; D0BCFE7818AEBFEB004A7AAE /* $binary.pck in Resources */ = {isa = PBXBuildFile; fileRef = D0BCFE7718AEBFEB004A7AAE /* $binary.pck */; }; + F965960D2BC2C3A800579C7E /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = F965960C2BC2C3A800579C7E /* PrivacyInfo.xcprivacy */; }; $pbx_launch_screen_build_reference /* End PBXBuildFile section */ @@ -47,6 +48,7 @@ D0BCFE4518AEBDA2004A7AAE /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; $pbx_locale_file_reference D0BCFE7718AEBFEB004A7AAE /* $binary.pck */ = {isa = PBXFileReference; lastKnownFileType = file; path = "$binary.pck"; sourceTree = ""; }; + F965960C2BC2C3A800579C7E /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; $pbx_launch_screen_file_reference /* End PBXFileReference section */ @@ -75,6 +77,7 @@ D0BCFE4118AEBDA2004A7AAE /* $binary */, D0BCFE3618AEBDA2004A7AAE /* Frameworks */, D0BCFE3518AEBDA2004A7AAE /* Products */, + F965960C2BC2C3A800579C7E /* PrivacyInfo.xcprivacy */, $additional_pbx_resources_refs ); sourceTree = ""; @@ -186,6 +189,7 @@ D0BCFE7818AEBFEB004A7AAE /* $binary.pck in Resources */, $pbx_launch_screen_build_phase D0BCFE4618AEBDA2004A7AAE /* InfoPlist.strings in Resources */, + F965960D2BC2C3A800579C7E /* PrivacyInfo.xcprivacy in Resources */, $additional_pbx_resources_build ); runOnlyForDeploymentPostprocessing = 0; diff --git a/platform/ios/doc_classes/EditorExportPlatformIOS.xml b/platform/ios/doc_classes/EditorExportPlatformIOS.xml index 0c0ded5fea3..eb226c79933 100644 --- a/platform/ios/doc_classes/EditorExportPlatformIOS.xml +++ b/platform/ios/doc_classes/EditorExportPlatformIOS.xml @@ -123,12 +123,441 @@ Spotlight icon file on iPad and iPhone (2x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url]. + + The reasons your app use active keyboard API. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api]Describing use of required reason API[/url]. + A message displayed when requesting access to the device's camera (in English). A message displayed when requesting access to the device's camera (localized). + + Indicates whether your app collects advertising data. + + + The reasons your app collects advertising data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links advertising data to the user's identity. + + + Indicates whether your app uses advertising data for tracking. + + + Indicates whether your app collects audio data data. + + + The reasons your app collects audio data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links audio data data to the user's identity. + + + Indicates whether your app uses audio data data for tracking. + + + Indicates whether your app collects browsing history. + + + The reasons your app collects browsing history. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links browsing history to the user's identity. + + + Indicates whether your app uses browsing history for tracking. + + + Indicates whether your app collects coarse location data. + + + The reasons your app collects coarse location data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links coarse location data to the user's identity. + + + Indicates whether your app uses coarse location data for tracking. + + + Indicates whether your app collects contacts. + + + The reasons your app collects contacts. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links contacts to the user's identity. + + + Indicates whether your app uses contacts for tracking. + + + Indicates whether your app collects crash data. + + + The reasons your app collects crash data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links crash data to the user's identity. + + + Indicates whether your app uses crash data for tracking. + + + Indicates whether your app collects credit information. + + + The reasons your app collects credit information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links credit information to the user's identity. + + + Indicates whether your app uses credit information for tracking. + + + Indicates whether your app collects customer support data. + + + The reasons your app collects customer support data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links customer support data to the user's identity. + + + Indicates whether your app uses customer support data for tracking. + + + Indicates whether your app collects device IDs. + + + The reasons your app collects device IDs. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links device IDs to the user's identity. + + + Indicates whether your app uses device IDs for tracking. + + + Indicates whether your app collects email address. + + + The reasons your app collects email address. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links email address to the user's identity. + + + Indicates whether your app uses email address for tracking. + + + Indicates whether your app collects emails or text messages. + + + The reasons your app collects emails or text messages. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links emails or text messages to the user's identity. + + + Indicates whether your app uses emails or text messages for tracking. + + + Indicates whether your app collects environment scanning data. + + + The reasons your app collects environment scanning data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links environment scanning data to the user's identity. + + + Indicates whether your app uses environment scanning data for tracking. + + + Indicates whether your app collects fitness and exercise data. + + + The reasons your app collects fitness and exercise data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links fitness and exercise data to the user's identity. + + + Indicates whether your app uses fitness and exercise data for tracking. + + + Indicates whether your app collects gameplay content. + + + The reasons your app collects gameplay content. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links gameplay content to the user's identity. + + + Indicates whether your app uses gameplay content for tracking. + + + Indicates whether your app collects user's hand structure and hand movements. + + + The reasons your app collects user's hand structure and hand movements. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links user's hand structure and hand movements to the user's identity. + + + Indicates whether your app uses user's hand structure and hand movements for tracking. + + + Indicates whether your app collects user's head movement. + + + The reasons your app collects user's head movement. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links user's head movement to the user's identity. + + + Indicates whether your app uses user's head movement for tracking. + + + Indicates whether your app collects health and medical data. + + + The reasons your app collects health and medical data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links health and medical data to the user's identity. + + + Indicates whether your app uses health and medical data for tracking. + + + Indicates whether your app collects user's name. + + + The reasons your app collects user's name. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links user's name to the user's identity. + + + Indicates whether your app uses user's name for tracking. + + + Indicates whether your app collects any other contact information. + + + The reasons your app collects any other contact information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links any other contact information to the user's identity. + + + Indicates whether your app uses any other contact information for tracking. + + + Indicates whether your app collects any other data. + + + The reasons your app collects any other data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links any other data to the user's identity. + + + Indicates whether your app uses any other data for tracking. + + + Indicates whether your app collects any other diagnostic data. + + + The reasons your app collects any other diagnostic data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links any other diagnostic data to the user's identity. + + + Indicates whether your app uses any other diagnostic data for tracking. + + + Indicates whether your app collects any other financial information. + + + The reasons your app collects any other financial information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links any other financial information to the user's identity. + + + Indicates whether your app uses any other financial information for tracking. + + + Indicates whether your app collects any other usage data. + + + The reasons your app collects any other usage data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links any other usage data to the user's identity. + + + Indicates whether your app uses any other usage data for tracking. + + + Indicates whether your app collects any other user generated content. + + + The reasons your app collects any other user generated content. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links any other user generated content to the user's identity. + + + Indicates whether your app uses any other user generated content for tracking. + + + Indicates whether your app collects payment information. + + + The reasons your app collects payment information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links payment information to the user's identity. + + + Indicates whether your app uses payment information for tracking. + + + Indicates whether your app collects performance data. + + + The reasons your app collects performance data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links performance data to the user's identity. + + + Indicates whether your app uses performance data for tracking. + + + Indicates whether your app collects phone number. + + + The reasons your app collects phone number. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links phone number to the user's identity. + + + Indicates whether your app uses phone number for tracking. + + + Indicates whether your app collects photos or videos. + + + The reasons your app collects photos or videos. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links photos or videos to the user's identity. + + + Indicates whether your app uses photos or videos for tracking. + + + Indicates whether your app collects physical address. + + + The reasons your app collects physical address. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links physical address to the user's identity. + + + Indicates whether your app uses physical address for tracking. + + + Indicates whether your app collects precise location data. + + + The reasons your app collects precise location data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links precise location data to the user's identity. + + + Indicates whether your app uses precise location data for tracking. + + + Indicates whether your app collects product interaction data. + + + The reasons your app collects product interaction data. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links product interaction data to the user's identity. + + + Indicates whether your app uses product interaction data for tracking. + + + Indicates whether your app collects purchase history. + + + The reasons your app collects purchase history. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links purchase history to the user's identity. + + + Indicates whether your app uses purchase history for tracking. + + + Indicates whether your app collects search history. + + + The reasons your app collects search history. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links search history to the user's identity. + + + Indicates whether your app uses search history for tracking. + + + Indicates whether your app collects sensitive user information. + + + The reasons your app collects sensitive user information. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links sensitive user information to the user's identity. + + + Indicates whether your app uses sensitive user information for tracking. + + + Indicates whether your app collects user IDs. + + + The reasons your app collects user IDs. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_data_use_in_privacy_manifests]Describing data use in privacy manifests[/url]. + + + Indicates whether your app links user IDs to the user's identity. + + + Indicates whether your app uses user IDs for tracking. + + + The reasons your app use free disk space API. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api]Describing use of required reason API[/url]. + + + The reasons your app use file timestamp/metadata API. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api]Describing use of required reason API[/url]. + A message displayed when requesting access to the device's microphone (in English). @@ -141,6 +570,18 @@ A message displayed when requesting access to the user's photo library (localized). + + The reasons your app use system boot time / absolute time API. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api]Describing use of required reason API[/url]. + + + The list of internet domains your app connects to that engage in tracking. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files]Privacy manifest files[/url]. + + + Indicates whether your app uses data for tracking. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files]Privacy manifest files[/url]. + + + The reasons your app use user defaults API. See [url=https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api]Describing use of required reason API[/url]. + A custom background color of the storyboard launch screen. diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp index 33389129b73..ab0018d3214 100644 --- a/platform/ios/export/export_plugin.cpp +++ b/platform/ios/export/export_plugin.cpp @@ -106,6 +106,94 @@ static const IconInfo icon_infos[] = { { PNAME("icons/notification_60x60"), "iphone", "Icon-60.png", "60", "3x", "20x20", false } }; +struct APIAccessInfo { + String prop_name; + String type_name; + Vector prop_flag_value; + Vector prop_flag_name; + int default_value; +}; + +static const APIAccessInfo api_info[] = { + { "file_timestamp", + "NSPrivacyAccessedAPICategoryFileTimestamp", + { "DDA9.1", "C617.1", "3B52.1" }, + { "Display to user on-device:", "Inside app or group container", "Files provided to app by user" }, + 3 }, + { "system_boot_time", + "NSPrivacyAccessedAPICategorySystemBootTime", + { "35F9.1", "8FFB.1", "3D61.1" }, + { "Measure time on-device", "Calculate absolute event timestamps", "User-initiated bug report" }, + 1 }, + { "disk_space", + "NSPrivacyAccessedAPICategoryDiskSpace", + { "E174.1", "85F4.1", "7D9E.1", "B728.1" }, + { "Write or delete file on-device", "Display to user on-device", "User-initiated bug report", "Health research app" }, + 3 }, + { "active_keyboard", + "NSPrivacyAccessedAPICategoryActiveKeyboards", + { "3EC4.1", "54BD.1" }, + { "Custom keyboard app on-device", "Customize UI on-device:2" }, + 0 }, + { "user_defaults", + "NSPrivacyAccessedAPICategoryUserDefaults", + { "1C8F.1", "AC6B.1", "CA92.1" }, + { "Access info from same App Group", "Access managed app configuration", "Access info from same app" }, + 0 } +}; + +struct DataCollectionInfo { + String prop_name; + String type_name; +}; + +static const DataCollectionInfo data_collect_type_info[] = { + { "name", "NSPrivacyCollectedDataTypeName" }, + { "email_address", "NSPrivacyCollectedDataTypeEmailAddress" }, + { "phone_number", "NSPrivacyCollectedDataTypePhoneNumber" }, + { "physical_address", "NSPrivacyCollectedDataTypePhysicalAddress" }, + { "other_contact_info", "NSPrivacyCollectedDataTypeOtherUserContactInfo" }, + { "health", "NSPrivacyCollectedDataTypeHealth" }, + { "fitness", "NSPrivacyCollectedDataTypeFitness" }, + { "payment_info", "NSPrivacyCollectedDataTypePaymentInfo" }, + { "credit_info", "NSPrivacyCollectedDataTypeCreditInfo" }, + { "other_financial_info", "NSPrivacyCollectedDataTypeOtherFinancialInfo" }, + { "precise_location", "NSPrivacyCollectedDataTypePreciseLocation" }, + { "coarse_location", "NSPrivacyCollectedDataTypeCoarseLocation" }, + { "sensitive_info", "NSPrivacyCollectedDataTypeSensitiveInfo" }, + { "contacts", "NSPrivacyCollectedDataTypeContacts" }, + { "emails_or_text_messages", "NSPrivacyCollectedDataTypeEmailsOrTextMessages" }, + { "photos_or_videos", "NSPrivacyCollectedDataTypePhotosorVideos" }, + { "audio_data", "NSPrivacyCollectedDataTypeAudioData" }, + { "gameplay_content", "NSPrivacyCollectedDataTypeGameplayContent" }, + { "customer_support", "NSPrivacyCollectedDataTypeCustomerSupport" }, + { "other_user_content", "NSPrivacyCollectedDataTypeOtherUserContent" }, + { "browsing_history", "NSPrivacyCollectedDataTypeBrowsingHistory" }, + { "search_hhistory", "NSPrivacyCollectedDataTypeSearchHistory" }, + { "user_id", "NSPrivacyCollectedDataTypeUserID" }, + { "device_id", "NSPrivacyCollectedDataTypeDeviceID" }, + { "purchase_history", "NSPrivacyCollectedDataTypePurchaseHistory" }, + { "product_interaction", "NSPrivacyCollectedDataTypeProductInteraction" }, + { "advertising_data", "NSPrivacyCollectedDataTypeAdvertisingData" }, + { "other_usage_data", "NSPrivacyCollectedDataTypeOtherUsageData" }, + { "crash_data", "NSPrivacyCollectedDataTypeCrashData" }, + { "performance_data", "NSPrivacyCollectedDataTypePerformanceData" }, + { "other_diagnostic_data", "NSPrivacyCollectedDataTypeOtherDiagnosticData" }, + { "environment_scanning", "NSPrivacyCollectedDataTypeEnvironmentScanning" }, + { "hands", "NSPrivacyCollectedDataTypeHands" }, + { "head", "NSPrivacyCollectedDataTypeHead" }, + { "other_data_types", "NSPrivacyCollectedDataTypeOtherDataTypes" }, +}; + +static const DataCollectionInfo data_collect_purpose_info[] = { + { "Analytics", "NSPrivacyCollectedDataTypePurposeAnalytics" }, + { "App Functionality", "NSPrivacyCollectedDataTypePurposeAppFunctionality" }, + { "Developer Advertising", "NSPrivacyCollectedDataTypePurposeDeveloperAdvertising" }, + { "Third-party Advertising", "NSPrivacyCollectedDataTypePurposeThirdPartyAdvertising" }, + { "Product Personalization", "NSPrivacyCollectedDataTypePurposeProductPersonalization" }, + { "Other", "NSPrivacyCollectedDataTypePurposeOther" }, +}; + String EditorExportPlatformIOS::get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const { if (p_preset) { if (p_name == "application/app_store_team_id") { @@ -119,6 +207,21 @@ String EditorExportPlatformIOS::get_export_option_warning(const EditorExportPres if (!is_package_name_valid(identifier, &pn_err)) { return TTR("Invalid Identifier:") + " " + pn_err; } + } else if (p_name == "privacy/file_timestamp_access_reasons") { + int access = p_preset->get("privacy/file_timestamp_access_reasons"); + if (access == 0) { + return TTR("At least one file timestamp access reason should be selected."); + } + } else if (p_name == "privacy/disk_space_access_reasons") { + int access = p_preset->get("privacy/disk_space_access_reasons"); + if (access == 0) { + return TTR("At least one disk space access reason should be selected."); + } + } else if (p_name == "privacy/system_boot_time_access_reasons") { + int access = p_preset->get("privacy/system_boot_time_access_reasons"); + if (access == 0) { + return TTR("At least one system boot time access reason should be selected."); + } } } return String(); @@ -140,6 +243,15 @@ bool EditorExportPlatformIOS::get_export_option_visibility(const EditorExportPre return false; } + if (p_preset == nullptr) { + return true; + } + + bool advanced_options_enabled = p_preset->are_advanced_options_enabled(); + if (p_option.begins_with("privacy")) { + return advanced_options_enabled; + } + return true; } @@ -220,6 +332,37 @@ void EditorExportPlatformIOS::get_export_options(List *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photolibrary_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need access to the photo library"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/photolibrary_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); + for (uint64_t i = 0; i < sizeof(api_info) / sizeof(api_info[0]); ++i) { + String prop_name = vformat("privacy/%s_access_reasons", api_info[i].prop_name); + String hint; + for (int j = 0; j < api_info[i].prop_flag_value.size(); j++) { + if (j != 0) { + hint += ","; + } + hint += vformat("%s - %s:%d", api_info[i].prop_flag_value[j], api_info[i].prop_flag_name[j], (1 << j)); + } + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, prop_name, PROPERTY_HINT_FLAGS, hint), api_info[i].default_value)); + } + + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "privacy/tracking_enabled"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "privacy/tracking_domains"), Vector())); + + { + String hint; + for (uint64_t i = 0; i < sizeof(data_collect_purpose_info) / sizeof(data_collect_purpose_info[0]); ++i) { + if (i != 0) { + hint += ","; + } + hint += vformat("%s:%d", data_collect_purpose_info[i].prop_name, (1 << i)); + } + for (uint64_t i = 0; i < sizeof(data_collect_type_info) / sizeof(data_collect_type_info[0]); ++i) { + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("privacy/collected_data/%s/collected", data_collect_type_info[i].prop_name)), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("privacy/collected_data/%s/linked_to_user", data_collect_type_info[i].prop_name)), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("privacy/collected_data/%s/used_for_tracking", data_collect_type_info[i].prop_name)), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, vformat("privacy/collected_data/%s/collection_purposes", data_collect_type_info[i].prop_name), PROPERTY_HINT_FLAGS, hint), 0)); + } + } + HashSet used_names; for (uint64_t i = 0; i < sizeof(icon_infos) / sizeof(icon_infos[0]); ++i) { if (!used_names.has(icon_infos[i].preset_key)) { @@ -522,6 +665,87 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref &p_ } else if (lines[i].find("$swift_runtime_build_phase") != -1) { String value = !p_config.use_swift_runtime ? "" : "90B4C2B62680C7E90039117A /* dummy.swift */,"; strnew += lines[i].replace("$swift_runtime_build_phase", value) + "\n"; + } else if (lines[i].find("$priv_collection") != -1) { + bool section_opened = false; + for (uint64_t j = 0; j < sizeof(data_collect_type_info) / sizeof(data_collect_type_info[0]); ++j) { + bool data_collected = p_preset->get(vformat("privacy/collected_data/%s/collected", data_collect_type_info[j].prop_name)); + bool linked = p_preset->get(vformat("privacy/collected_data/%s/linked_to_user", data_collect_type_info[j].prop_name)); + bool tracking = p_preset->get(vformat("privacy/collected_data/%s/used_for_tracking", data_collect_type_info[j].prop_name)); + int purposes = p_preset->get(vformat("privacy/collected_data/%s/collection_purposes", data_collect_type_info[j].prop_name)); + if (data_collected) { + if (!section_opened) { + section_opened = true; + strnew += "\tNSPrivacyCollectedDataTypes\n"; + strnew += "\t\n"; + } + strnew += "\t\t\n"; + strnew += "\t\t\tNSPrivacyCollectedDataType\n"; + strnew += vformat("\t\t\t%s\n", data_collect_type_info[j].type_name); + strnew += "\t\t\t\tNSPrivacyCollectedDataTypeLinked\n"; + if (linked) { + strnew += "\t\t\t\t\n"; + } else { + strnew += "\t\t\t\t\n"; + } + strnew += "\t\t\t\tNSPrivacyCollectedDataTypeTracking\n"; + if (tracking) { + strnew += "\t\t\t\t\n"; + } else { + strnew += "\t\t\t\t\n"; + } + if (purposes != 0) { + strnew += "\t\t\t\tNSPrivacyCollectedDataTypePurposes\n"; + strnew += "\t\t\t\t\n"; + for (uint64_t k = 0; k < sizeof(data_collect_purpose_info) / sizeof(data_collect_purpose_info[0]); ++k) { + if (purposes & (1 << k)) { + strnew += vformat("\t\t\t\t\t%s\n", data_collect_purpose_info[k].type_name); + } + } + strnew += "\t\t\t\t\n"; + } + strnew += "\t\t\t\n"; + } + } + if (section_opened) { + strnew += "\t\n"; + } + } else if (lines[i].find("$priv_tracking") != -1) { + bool tracking = p_preset->get("privacy/tracking_enabled"); + strnew += "\tNSPrivacyTracking\n"; + if (tracking) { + strnew += "\t\n"; + } else { + strnew += "\t\n"; + } + Vector tracking_domains = p_preset->get("privacy/tracking_domains"); + if (!tracking_domains.is_empty()) { + strnew += "\tNSPrivacyTrackingDomains\n"; + strnew += "\t\n"; + for (const String &E : tracking_domains) { + strnew += "\t\t" + E + "\n"; + } + strnew += "\t\n"; + } + } else if (lines[i].find("$priv_api_types") != -1) { + strnew += "\t\n"; + for (uint64_t j = 0; j < sizeof(api_info) / sizeof(api_info[0]); ++j) { + int api_access = p_preset->get(vformat("privacy/%s_access_reasons", api_info[j].prop_name)); + if (api_access != 0) { + strnew += "\t\t\n"; + strnew += "\t\t\tNSPrivacyAccessedAPITypeReasons\n"; + strnew += "\t\t\t\n"; + for (int k = 0; k < api_info[j].prop_flag_value.size(); k++) { + if (api_access & (1 << k)) { + strnew += vformat("\t\t\t\t%s\n", api_info[j].prop_flag_value[k]); + } + } + strnew += "\t\t\t\n"; + strnew += "\t\t\tNSPrivacyAccessedAPIType\n"; + strnew += vformat("\t\t\t%s\n", api_info[j].type_name); + strnew += "\t\t\n"; + } + } + strnew += "\t\n"; } else { strnew += lines[i] + "\n"; } @@ -1694,6 +1918,7 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref