Merge pull request #74644 from bruvzg/export_opt_warn

[Export] Add readable descriptions and validation warnings to the export options.
This commit is contained in:
Rémi Verschelde 2023-04-19 10:13:37 +02:00
commit 00bb482fcf
No known key found for this signature in database
GPG key ID: C3336907360768E1
49 changed files with 2215 additions and 391 deletions

View file

@ -0,0 +1,581 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorExportPlatformAndroid" inherits="EditorExportPlatform" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Exporter for Android.
</brief_description>
<description>
</description>
<tutorials>
<link title="Exporting for Android">$DOCS_URL/tutorials/export/exporting_for_android.html</link>
<link title="Custom builds for Android">$DOCS_URL/tutorials/export/android_custom_build.html</link>
</tutorials>
<members>
<member name="apk_expansion/SALT" type="String" setter="" getter="">
Array of random bytes that the licensing Policy uses to create an [url=https://developer.android.com/google/play/licensing/adding-licensing#impl-Obfuscator]Obfuscator[/url].
</member>
<member name="apk_expansion/enable" type="bool" setter="" getter="">
If [code]true[/code], project resources are stored in the separate APK expansion file, instead APK.
[b]Note:[/b] APK expansion should be enabled to use PCK encryption.
</member>
<member name="apk_expansion/public_key" type="String" setter="" getter="">
Base64 encoded RSA public key for your publisher account, available from the profile page on the "Play Console".
</member>
<member name="architectures/arm64-v8a" type="bool" setter="" getter="">
If [code]true[/code], [code]arm64[/code] binaries are included into exported project.
</member>
<member name="architectures/armeabi-v7a" type="bool" setter="" getter="">
If [code]true[/code], [code]arm32[/code] binaries are included into exported project.
</member>
<member name="architectures/x86" type="bool" setter="" getter="">
If [code]true[/code], [code]x86_32[/code] binaries are included into exported project.
</member>
<member name="architectures/x86_64" type="bool" setter="" getter="">
If [code]true[/code], [code]x86_64[/code] binaries are included into exported project.
</member>
<member name="command_line/extra_args" type="String" setter="" getter="">
A list of additional command line arguments, exported project will receive when started.
</member>
<member name="custom_template/debug" type="String" setter="" getter="">
Path to the custom export template. If left empty, default template is used.
</member>
<member name="custom_template/release" type="String" setter="" getter="">
Path to the custom export template. If left empty, default template is used.
</member>
<member name="gradle_build/export_format" type="int" setter="" getter="">
Export format for Gradle build.
</member>
<member name="gradle_build/min_sdk" type="String" setter="" getter="">
Minimal Android SDK version for Gradle build.
</member>
<member name="gradle_build/target_sdk" type="String" setter="" getter="">
Target Android SDK version for Gradle build.
</member>
<member name="gradle_build/use_gradle_build" type="bool" setter="" getter="">
If [code]true[/code], Gradle build is used instead of pre-built APK.
</member>
<member name="graphics/opengl_debug" type="bool" setter="" getter="">
If [code]true[/code], OpenGL ES debug context will be created (additional runtime checking, validation, and logging).
</member>
<member name="keystore/debug" type="String" setter="" getter="">
Path of the debug keystore file.
</member>
<member name="keystore/debug_password" type="String" setter="" getter="">
Password for the debug keystore file.
</member>
<member name="keystore/debug_user" type="String" setter="" getter="">
User name for the debug keystore file.
</member>
<member name="keystore/release" type="String" setter="" getter="">
Path of the release keystore file.
</member>
<member name="keystore/release_password" type="String" setter="" getter="">
Password for the release keystore file.
</member>
<member name="keystore/release_user" type="String" setter="" getter="">
User name for the release keystore file.
</member>
<member name="launcher_icons/adaptive_background_432x432" type="String" setter="" getter="">
Background layer of the application adaptive icon file.
</member>
<member name="launcher_icons/adaptive_foreground_432x432" type="String" setter="" getter="">
Foreground layer of the application adaptive icon file.
</member>
<member name="launcher_icons/main_192x192" type="String" setter="" getter="">
Application icon file. If left empty, project icon is used instead.
</member>
<member name="package/app_category" type="int" setter="" getter="">
Application category for the Play Store.
</member>
<member name="package/exclude_from_recents" type="bool" setter="" getter="">
If [code]true[/code], task initiated by main activity will be excluded from the list of recently used applications.
</member>
<member name="package/name" type="String" setter="" getter="">
Name of the application.
</member>
<member name="package/retain_data_on_uninstall" type="bool" setter="" getter="">
If [code]true[/code], when the user uninstalls an app, a prompt to keep the app's data will be shown.
</member>
<member name="package/signed" type="bool" setter="" getter="">
If [code]true[/code], package signing is enabled.
</member>
<member name="package/unique_name" type="String" setter="" getter="">
Unique application identifier in a reverse-DNS format, can only contain alphanumeric characters ([code]A-Z[/code], [code]a-z[/code], and [code]0-9[/code]), hyphens ([code]-[/code]), and periods ([code].[/code]).
</member>
<member name="permissions/access_checkin_properties" type="bool" setter="" getter="">
Allows read/write access to the "properties" table in the checkin database. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCESS_CHECKIN_PROPERTIES]ACCESS_CHECKIN_PROPERTIES[/url].
</member>
<member name="permissions/access_coarse_location" type="bool" setter="" getter="">
Allows access to the approximate location information. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCESS_COARSE_LOCATION]ACCESS_COARSE_LOCATION[/url].
</member>
<member name="permissions/access_fine_location" type="bool" setter="" getter="">
Allows access to the precise location information. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION]ACCESS_FINE_LOCATION[/url].
</member>
<member name="permissions/access_location_extra_commands" type="bool" setter="" getter="">
Allows access to the extra location provider commands. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCESS_LOCATION_EXTRA_COMMANDS]ACCESS_LOCATION_EXTRA_COMMANDS[/url].
</member>
<member name="permissions/access_mock_location" type="bool" setter="" getter="">
Allows an application to create mock location providers for testing.
</member>
<member name="permissions/access_network_state" type="bool" setter="" getter="">
Allows access to the information about networks. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCESS_NETWORK_STATE]ACCESS_NETWORK_STATE[/url].
</member>
<member name="permissions/access_surface_flinger" type="bool" setter="" getter="">
Allows an application to use SurfaceFlinger's low level features.
</member>
<member name="permissions/access_wifi_state" type="bool" setter="" getter="">
Allows access to the information about Wi-Fi networks. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCESS_WIFI_STATE]ACCESS_WIFI_STATE[/url].
</member>
<member name="permissions/account_manager" type="bool" setter="" getter="">
Allows applications to call into AccountAuthenticators. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCOUNT_MANAGER]ACCOUNT_MANAGER[/url].
</member>
<member name="permissions/add_voicemail" type="bool" setter="" getter="">
Allows an application to add voicemails into the system. See [url=https://developer.android.com/reference/android/Manifest.permission#ADD_VOICEMAIL]ADD_VOICEMAIL[/url].
</member>
<member name="permissions/authenticate_accounts" type="bool" setter="" getter="">
Allows an application to act as an AccountAuthenticator for the AccountManager.
</member>
<member name="permissions/battery_stats" type="bool" setter="" getter="">
Allows an application to collect battery statistics. Sett [url=https://developer.android.com/reference/android/Manifest.permission#BATTERY_STATS]BATTERY_STATS[/url].
</member>
<member name="permissions/bind_accessibility_service" type="bool" setter="" getter="">
Must be required by an AccessibilityService, to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_ACCESSIBILITY_SERVICE]BIND_ACCESSIBILITY_SERVICE[/url].
</member>
<member name="permissions/bind_appwidget" type="bool" setter="" getter="">
Allows an application to tell the AppWidget service which application can access AppWidget's data. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_APPWIDGET]BIND_APPWIDGET[/url].
</member>
<member name="permissions/bind_device_admin" type="bool" setter="" getter="">
Must be required by device administration receiver, to ensure that only the system can interact with it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_DEVICE_ADMIN]BIND_DEVICE_ADMIN[/url].
</member>
<member name="permissions/bind_input_method" type="bool" setter="" getter="">
Must be required by an InputMethodService, to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_INPUT_METHOD]BIND_INPUT_METHOD[/url].
</member>
<member name="permissions/bind_nfc_service" type="bool" setter="" getter="">
Must be required by a HostApduService or OffHostApduService to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_NFC_SERVICE]BIND_NFC_SERVICE[/url].
</member>
<member name="permissions/bind_notification_listener_service" type="bool" setter="" getter="">
Must be required by an NotificationListenerService, to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_NOTIFICATION_LISTENER_SERVICE]BIND_NOTIFICATION_LISTENER_SERVICE[/url].
</member>
<member name="permissions/bind_print_service" type="bool" setter="" getter="">
Must be required by a PrintService, to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_PRINT_SERVICE]BIND_PRINT_SERVICE[/url].
</member>
<member name="permissions/bind_remoteviews" type="bool" setter="" getter="">
Must be required by a RemoteViewsService, to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_REMOTEVIEWS]BIND_REMOTEVIEWS[/url].
</member>
<member name="permissions/bind_text_service" type="bool" setter="" getter="">
Must be required by a TextService (e.g. SpellCheckerService) to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_TEXT_SERVICE]BIND_TEXT_SERVICE[/url].
</member>
<member name="permissions/bind_vpn_service" type="bool" setter="" getter="">
Must be required by a VpnService, to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_VPN_SERVICE]BIND_VPN_SERVICE[/url].
</member>
<member name="permissions/bind_wallpaper" type="bool" setter="" getter="">
Must be required by a WallpaperService, to ensure that only the system can bind to it. See [url=https://developer.android.com/reference/android/Manifest.permission#BIND_WALLPAPER]BIND_WALLPAPER[/url].
</member>
<member name="permissions/bluetooth" type="bool" setter="" getter="">
Allows applications to connect to paired bluetooth devices. See [url=https://developer.android.com/reference/android/Manifest.permission#BLUETOOTH]BLUETOOTH[/url].
</member>
<member name="permissions/bluetooth_admin" type="bool" setter="" getter="">
Allows applications to discover and pair bluetooth devices. See [url=https://developer.android.com/reference/android/Manifest.permission#BLUETOOTH_ADMIN]BLUETOOTH_ADMIN[/url].
</member>
<member name="permissions/bluetooth_privileged" type="bool" setter="" getter="">
Allows applications to pair bluetooth devices without user interaction, and to allow or disallow phonebook access or message access. See [url=https://developer.android.com/reference/android/Manifest.permission#BLUETOOTH_PRIVILEGED]BLUETOOTH_PRIVILEGED[/url].
</member>
<member name="permissions/brick" type="bool" setter="" getter="">
Required to be able to disable the device (very dangerous!).
</member>
<member name="permissions/broadcast_package_removed" type="bool" setter="" getter="">
Allows an application to broadcast a notification that an application package has been removed. See [url=https://developer.android.com/reference/android/Manifest.permission#BROADCAST_PACKAGE_REMOVED]BROADCAST_PACKAGE_REMOVED[/url].
</member>
<member name="permissions/broadcast_sms" type="bool" setter="" getter="">
Allows an application to broadcast an SMS receipt notification. See [url=https://developer.android.com/reference/android/Manifest.permission#BROADCAST_SMS]BROADCAST_SMS[/url].
</member>
<member name="permissions/broadcast_sticky" type="bool" setter="" getter="">
Allows an application to broadcast sticky intents. See [url=https://developer.android.com/reference/android/Manifest.permission#BROADCAST_STICKY]BROADCAST_STICKY[/url].
</member>
<member name="permissions/broadcast_wap_push" type="bool" setter="" getter="">
Allows an application to broadcast a WAP PUSH receipt notification. See [url=https://developer.android.com/reference/android/Manifest.permission#BROADCAST_WAP_PUSH]BROADCAST_WAP_PUSH[/url].
</member>
<member name="permissions/call_phone" type="bool" setter="" getter="">
Allows an application to initiate a phone call without going through the Dialer user interface. See [url=https://developer.android.com/reference/android/Manifest.permission#CALL_PHONE]CALL_PHONE[/url].
</member>
<member name="permissions/call_privileged" type="bool" setter="" getter="">
Allows an application to call any phone number, including emergency numbers, without going through the Dialer user interface. See [url=https://developer.android.com/reference/android/Manifest.permission#CALL_PRIVILEGED]CALL_PRIVILEGED[/url].
</member>
<member name="permissions/camera" type="bool" setter="" getter="">
Required to be able to access the camera device. See [url=https://developer.android.com/reference/android/Manifest.permission#CAMERA]CAMERA[/url].
</member>
<member name="permissions/capture_audio_output" type="bool" setter="" getter="">
Allows an application to capture audio output. See [url=https://developer.android.com/reference/android/Manifest.permission#CAPTURE_AUDIO_OUTPUT]CAPTURE_AUDIO_OUTPUT[/url].
</member>
<member name="permissions/capture_secure_video_output" type="bool" setter="" getter="">
Allows an application to capture secure video output.
</member>
<member name="permissions/capture_video_output" type="bool" setter="" getter="">
Allows an application to capture video output.
</member>
<member name="permissions/change_component_enabled_state" type="bool" setter="" getter="">
Allows an application to change whether an application component (other than its own) is enabled or not. See [url=https://developer.android.com/reference/android/Manifest.permission#CHANGE_COMPONENT_ENABLED_STATE]CHANGE_COMPONENT_ENABLED_STATE[/url].
</member>
<member name="permissions/change_configuration" type="bool" setter="" getter="">
Allows an application to modify the current configuration, such as locale. See [url=https://developer.android.com/reference/android/Manifest.permission#CHANGE_CONFIGURATION]CHANGE_CONFIGURATION[/url].
</member>
<member name="permissions/change_network_state" type="bool" setter="" getter="">
Allows applications to change network connectivity state. See [url=https://developer.android.com/reference/android/Manifest.permission#CHANGE_NETWORK_STATE]CHANGE_NETWORK_STATE[/url].
</member>
<member name="permissions/change_wifi_multicast_state" type="bool" setter="" getter="">
Allows applications to enter Wi-Fi Multicast mode. See [url=https://developer.android.com/reference/android/Manifest.permission#CHANGE_WIFI_MULTICAST_STATE]CHANGE_WIFI_MULTICAST_STATE[/url].
</member>
<member name="permissions/change_wifi_state" type="bool" setter="" getter="">
Allows applications to change Wi-Fi connectivity state. See [url=https://developer.android.com/reference/android/Manifest.permission#CHANGE_WIFI_STATE]CHANGE_WIFI_STATE[/url].
</member>
<member name="permissions/clear_app_cache" type="bool" setter="" getter="">
Allows an application to clear the caches of all installed applications on the device. See [url=https://developer.android.com/reference/android/Manifest.permission#CLEAR_APP_CACHE]CLEAR_APP_CACHE[/url].
</member>
<member name="permissions/clear_app_user_data" type="bool" setter="" getter="">
Allows an application to clear user data.
</member>
<member name="permissions/control_location_updates" type="bool" setter="" getter="">
Allows enabling/disabling location update notifications from the radio. See [url=https://developer.android.com/reference/android/Manifest.permission#CONTROL_LOCATION_UPDATES]CONTROL_LOCATION_UPDATES[/url].
</member>
<member name="permissions/custom_permissions" type="PackedStringArray" setter="" getter="">
Array of custom permission strings.
</member>
<member name="permissions/delete_cache_files" type="bool" setter="" getter="">
Deprecated.
</member>
<member name="permissions/delete_packages" type="bool" setter="" getter="">
Allows an application to delete packages. See [url=https://developer.android.com/reference/android/Manifest.permission#DELETE_PACKAGES]DELETE_PACKAGES[/url].
</member>
<member name="permissions/device_power" type="bool" setter="" getter="">
Allows low-level access to power management.
</member>
<member name="permissions/diagnostic" type="bool" setter="" getter="">
Allows applications to RW to diagnostic resources. See [url=https://developer.android.com/reference/android/Manifest.permission#DIAGNOSTIC]DIAGNOSTIC[/url].
</member>
<member name="permissions/disable_keyguard" type="bool" setter="" getter="">
Allows applications to disable the keyguard if it is not secure. See [url=https://developer.android.com/reference/android/Manifest.permission#DISABLE_KEYGUARD]DISABLE_KEYGUARD[/url].
</member>
<member name="permissions/dump" type="bool" setter="" getter="">
Allows an application to retrieve state dump information from system services. See [url=https://developer.android.com/reference/android/Manifest.permission#DUMP]DUMP[/url].
</member>
<member name="permissions/expand_status_bar" type="bool" setter="" getter="">
Allows an application to expand or collapse the status bar. See [url=https://developer.android.com/reference/android/Manifest.permission#EXPAND_STATUS_BAR]EXPAND_STATUS_BAR[/url].
</member>
<member name="permissions/factory_test" type="bool" setter="" getter="">
Run as a manufacturer test application, running as the root user. See [url=https://developer.android.com/reference/android/Manifest.permission#FACTORY_TEST]FACTORY_TEST[/url].
</member>
<member name="permissions/flashlight" type="bool" setter="" getter="">
Allows access to the flashlight.
</member>
<member name="permissions/force_back" type="bool" setter="" getter="">
Allows an application to force a BACK operation on whatever is the top activity.
</member>
<member name="permissions/get_accounts" type="bool" setter="" getter="">
Allows access to the list of accounts in the Accounts Service. See [url=https://developer.android.com/reference/android/Manifest.permission#GET_ACCOUNTS]GET_ACCOUNTS[/url].
</member>
<member name="permissions/get_package_size" type="bool" setter="" getter="">
Allows an application to find out the space used by any package. See [url=https://developer.android.com/reference/android/Manifest.permission#GET_PACKAGE_SIZE]GET_PACKAGE_SIZE[/url].
</member>
<member name="permissions/get_tasks" type="bool" setter="" getter="">
Deprecated in API level 21.
</member>
<member name="permissions/get_top_activity_info" type="bool" setter="" getter="">
Allows an application to retrieve private information about the current top activity.
</member>
<member name="permissions/global_search" type="bool" setter="" getter="">
Used on content providers to allow the global search system to access their data. See [url=https://developer.android.com/reference/android/Manifest.permission#GLOBAL_SEARCH]GLOBAL_SEARCH[/url].
</member>
<member name="permissions/hardware_test" type="bool" setter="" getter="">
Allows access to hardware peripherals.
</member>
<member name="permissions/inject_events" type="bool" setter="" getter="">
Allows an application to inject user events (keys, touch, trackball) into the event stream and deliver them to ANY window.
</member>
<member name="permissions/install_location_provider" type="bool" setter="" getter="">
Allows an application to install a location provider into the Location Manager. See [url=https://developer.android.com/reference/android/Manifest.permission#INSTALL_LOCATION_PROVIDER]INSTALL_LOCATION_PROVIDER[/url].
</member>
<member name="permissions/install_packages" type="bool" setter="" getter="">
Allows an application to install packages. See [url=https://developer.android.com/reference/android/Manifest.permission#INSTALL_PACKAGES]INSTALL_PACKAGES[/url].
</member>
<member name="permissions/install_shortcut" type="bool" setter="" getter="">
Allows an application to install a shortcut in Launcher. See [url=https://developer.android.com/reference/android/Manifest.permission#INSTALL_SHORTCUT]INSTALL_SHORTCUT[/url].
</member>
<member name="permissions/internal_system_window" type="bool" setter="" getter="">
Allows an application to open windows that are for use by parts of the system user interface.
</member>
<member name="permissions/internet" type="bool" setter="" getter="">
Allows applications to open network sockets. See [url=https://developer.android.com/reference/android/Manifest.permission#INTERNET]INTERNET[/url].
</member>
<member name="permissions/kill_background_processes" type="bool" setter="" getter="">
Allows an application to call ActivityManager.killBackgroundProcesses(String). See [url=https://developer.android.com/reference/android/Manifest.permission#KILL_BACKGROUND_PROCESSES]KILL_BACKGROUND_PROCESSES[/url].
</member>
<member name="permissions/location_hardware" type="bool" setter="" getter="">
Allows an application to use location features in hardware, such as the geofencing api. See [url=https://developer.android.com/reference/android/Manifest.permission#LOCATION_HARDWARE]LOCATION_HARDWARE[/url].
</member>
<member name="permissions/manage_accounts" type="bool" setter="" getter="">
Allows an application to manage the list of accounts in the AccountManager.
</member>
<member name="permissions/manage_app_tokens" type="bool" setter="" getter="">
Allows an application to manage (create, destroy, Z-order) application tokens in the window manager.
</member>
<member name="permissions/manage_documents" type="bool" setter="" getter="">
Allows an application to manage access to documents, usually as part of a document picker. See [url=https://developer.android.com/reference/android/Manifest.permission#MANAGE_DOCUMENTS]MANAGE_DOCUMENTS[/url].
</member>
<member name="permissions/manage_external_storage" type="bool" setter="" getter="">
Allows an application a broad access to external storage in scoped storage. See [url=https://developer.android.com/reference/android/Manifest.permission#MANAGE_EXTERNAL_STORAGE]MANAGE_EXTERNAL_STORAGE[/url].
</member>
<member name="permissions/master_clear" type="bool" setter="" getter="">
See [url=https://developer.android.com/reference/android/Manifest.permission#MASTER_CLEAR]MASTER_CLEAR[/url].
</member>
<member name="permissions/media_content_control" type="bool" setter="" getter="">
Allows an application to know what content is playing and control its playback. See [url=https://developer.android.com/reference/android/Manifest.permission#MEDIA_CONTENT_CONTROL]MEDIA_CONTENT_CONTROL[/url].
</member>
<member name="permissions/modify_audio_settings" type="bool" setter="" getter="">
Allows an application to modify global audio settings. See [url=https://developer.android.com/reference/android/Manifest.permission#MODIFY_AUDIO_SETTINGS]MODIFY_AUDIO_SETTINGS[/url].
</member>
<member name="permissions/modify_phone_state" type="bool" setter="" getter="">
Allows modification of the telephony state - power on, mmi, etc. Does not include placing calls. See [url=https://developer.android.com/reference/android/Manifest.permission#MODIFY_PHONE_STATE]MODIFY_PHONE_STATE[/url].
</member>
<member name="permissions/mount_format_filesystems" type="bool" setter="" getter="">
Allows formatting file systems for removable storage. See [url=https://developer.android.com/reference/android/Manifest.permission#MOUNT_FORMAT_FILESYSTEMS]MOUNT_FORMAT_FILESYSTEMS[/url].
</member>
<member name="permissions/mount_unmount_filesystems" type="bool" setter="" getter="">
Allows mounting and unmounting file systems for removable storage. See [url=https://developer.android.com/reference/android/Manifest.permission#MOUNT_UNMOUNT_FILESYSTEMS]MOUNT_UNMOUNT_FILESYSTEMS[/url].
</member>
<member name="permissions/nfc" type="bool" setter="" getter="">
Allows applications to perform I/O operations over NFC. See [url=https://developer.android.com/reference/android/Manifest.permission#NFC]NFC[/url].
</member>
<member name="permissions/persistent_activity" type="bool" setter="" getter="">
Allow an application to make its activities persistent.
Deprecated in API level 15.
</member>
<member name="permissions/process_outgoing_calls" type="bool" setter="" getter="">
Allows an application to see the number being dialed during an outgoing call with the option to redirect the call to a different number or abort the call altogether. See [url=https://developer.android.com/reference/android/Manifest.permission#PROCESS_OUTGOING_CALLS]PROCESS_OUTGOING_CALLS[/url].
Deprecated in API level 29.
</member>
<member name="permissions/read_calendar" type="bool" setter="" getter="">
Allows an application to read the user's calendar data. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_CALENDAR]READ_CALENDAR[/url].
</member>
<member name="permissions/read_call_log" type="bool" setter="" getter="">
Allows an application to read the user's call log. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_CALL_LOG]READ_CALL_LOG[/url].
</member>
<member name="permissions/read_contacts" type="bool" setter="" getter="">
Allows an application to read the user's contacts data. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_CONTACTS]READ_CONTACTS[/url].
</member>
<member name="permissions/read_external_storage" type="bool" setter="" getter="">
Allows an application to read from external storage. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_EXTERNAL_STORAGE]READ_EXTERNAL_STORAGE[/url].
Deprecated in API level 33.
</member>
<member name="permissions/read_frame_buffer" type="bool" setter="" getter="">
Allows an application to take screen shots and more generally get access to the frame buffer data.
</member>
<member name="permissions/read_history_bookmarks" type="bool" setter="" getter="">
Allows an application to read (but not write) the user's browsing history and bookmarks.
</member>
<member name="permissions/read_input_state" type="bool" setter="" getter="">
Deprecated in API level 16.
</member>
<member name="permissions/read_logs" type="bool" setter="" getter="">
Allows an application to read the low-level system log files. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_LOGS]READ_LOGS[/url].
</member>
<member name="permissions/read_phone_state" type="bool" setter="" getter="">
Allows read only access to phone state. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_PHONE_STATE]READ_PHONE_STATE[/url].
</member>
<member name="permissions/read_profile" type="bool" setter="" getter="">
Allows an application to read the user's personal profile data.
</member>
<member name="permissions/read_sms" type="bool" setter="" getter="">
Allows an application to read SMS messages. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_SMS]READ_SMS[/url].
</member>
<member name="permissions/read_social_stream" type="bool" setter="" getter="">
Allows an application to read from the user's social stream.
</member>
<member name="permissions/read_sync_settings" type="bool" setter="" getter="">
Allows applications to read the sync settings. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_SYNC_SETTINGS]READ_SYNC_SETTINGS[/url].
</member>
<member name="permissions/read_sync_stats" type="bool" setter="" getter="">
Allows applications to read the sync stats. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_SYNC_STATS]READ_SYNC_STATS[/url].
</member>
<member name="permissions/read_user_dictionary" type="bool" setter="" getter="">
Allows an application to read the user dictionary.
</member>
<member name="permissions/reboot" type="bool" setter="" getter="">
Required to be able to reboot the device. See [url=https://developer.android.com/reference/android/Manifest.permission#REBOOT]REBOOT[/url].
</member>
<member name="permissions/receive_boot_completed" type="bool" setter="" getter="">
Allows an application to receive the Intent.ACTION_BOOT_COMPLETED that is broadcast after the system finishes booting. See [url=https://developer.android.com/reference/android/Manifest.permission#RECEIVE_BOOT_COMPLETED]RECEIVE_BOOT_COMPLETED[/url].
</member>
<member name="permissions/receive_mms" type="bool" setter="" getter="">
Allows an application to monitor incoming MMS messages. See [url=https://developer.android.com/reference/android/Manifest.permission#RECEIVE_MMS]RECEIVE_MMS[/url].
</member>
<member name="permissions/receive_sms" type="bool" setter="" getter="">
Allows an application to receive SMS messages. See [url=https://developer.android.com/reference/android/Manifest.permission#RECEIVE_SMS]RECEIVE_SMS[/url].
</member>
<member name="permissions/receive_wap_push" type="bool" setter="" getter="">
Allows an application to receive WAP push messages. See [url=https://developer.android.com/reference/android/Manifest.permission#RECEIVE_WAP_PUSH]RECEIVE_WAP_PUSH[/url].
</member>
<member name="permissions/record_audio" type="bool" setter="" getter="">
Allows an application to record audio. See [url=https://developer.android.com/reference/android/Manifest.permission#RECORD_AUDIO]RECORD_AUDIO[/url].
</member>
<member name="permissions/reorder_tasks" type="bool" setter="" getter="">
Allows an application to change the Z-order of tasks. See [url= https://developer.android.com/reference/android/Manifest.permission#REORDER_TASKS]REORDER_TASKS[/url].
</member>
<member name="permissions/restart_packages" type="bool" setter="" getter="">
Deprecated in API level 15.
</member>
<member name="permissions/send_respond_via_message" type="bool" setter="" getter="">
Allows an application (Phone) to send a request to other applications to handle the respond-via-message action during incoming calls. See [url=https://developer.android.com/reference/android/Manifest.permission#SEND_RESPOND_VIA_MESSAGE]SEND_RESPOND_VIA_MESSAGE[/url].
</member>
<member name="permissions/send_sms" type="bool" setter="" getter="">
Allows an application to send SMS messages. See [url=https://developer.android.com/reference/android/Manifest.permission#SEND_SMS]SEND_SMS[/url].
</member>
<member name="permissions/set_activity_watcher" type="bool" setter="" getter="">
Allows an application to watch and control how activities are started globally in the system.
</member>
<member name="permissions/set_alarm" type="bool" setter="" getter="">
Allows an application to broadcast an Intent to set an alarm for the user. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_ALARM]SET_ALARM[/url].
</member>
<member name="permissions/set_always_finish" type="bool" setter="" getter="">
Allows an application to control whether activities are immediately finished when put in the background. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_ALWAYS_FINISH]SET_ALWAYS_FINISH[/url].
</member>
<member name="permissions/set_animation_scale" type="bool" setter="" getter="">
Allows to modify the global animation scaling factor. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_ANIMATION_SCALE]SET_ANIMATION_SCALE[/url].
</member>
<member name="permissions/set_debug_app" type="bool" setter="" getter="">
Configure an application for debugging. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_DEBUG_APP]SET_DEBUG_APP[/url].
</member>
<member name="permissions/set_orientation" type="bool" setter="" getter="">
Allows low-level access to setting the orientation (actually rotation) of the screen.
</member>
<member name="permissions/set_pointer_speed" type="bool" setter="" getter="">
Allows low-level access to setting the pointer speed.
</member>
<member name="permissions/set_preferred_applications" type="bool" setter="" getter="">
Deprecated in API level 15.
</member>
<member name="permissions/set_process_limit" type="bool" setter="" getter="">
Allows an application to set the maximum number of (not needed) application processes that can be running. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_PROCESS_LIMIT]SET_PROCESS_LIMIT[/url].
</member>
<member name="permissions/set_time" type="bool" setter="" getter="">
Allows applications to set the system time directly. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_TIME]SET_TIME[/url].
</member>
<member name="permissions/set_time_zone" type="bool" setter="" getter="">
Allows applications to set the system time zone directly. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_TIME_ZONE]SET_TIME_ZONE[/url].
</member>
<member name="permissions/set_wallpaper" type="bool" setter="" getter="">
Allows applications to set the wallpaper. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_WALLPAPER]SET_WALLPAPER[/url].
</member>
<member name="permissions/set_wallpaper_hints" type="bool" setter="" getter="">
Allows applications to set the wallpaper hints. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_WALLPAPER_HINTS]SET_WALLPAPER_HINTS[/url].
</member>
<member name="permissions/signal_persistent_processes" type="bool" setter="" getter="">
Allow an application to request that a signal be sent to all persistent processes. See [url=https://developer.android.com/reference/android/Manifest.permission#SIGNAL_PERSISTENT_PROCESSES]SIGNAL_PERSISTENT_PROCESSES[/url].
</member>
<member name="permissions/status_bar" type="bool" setter="" getter="">
Allows an application to open, close, or disable the status bar and its icons. See [url=https://developer.android.com/reference/android/Manifest.permission#STATUS_BAR]STATUS_BAR[/url].
</member>
<member name="permissions/subscribed_feeds_read" type="bool" setter="" getter="">
Allows an application to allow access the subscribed feeds ContentProvider.
</member>
<member name="permissions/subscribed_feeds_write" type="bool" setter="" getter="">
Deprecated.
</member>
<member name="permissions/system_alert_window" type="bool" setter="" getter="">
Allows an app to create windows using the type WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, shown on top of all other apps. See [url=https://developer.android.com/reference/android/Manifest.permission#SYSTEM_ALERT_WINDOW]SYSTEM_ALERT_WINDOW[/url].
</member>
<member name="permissions/transmit_ir" type="bool" setter="" getter="">
Allows using the device's IR transmitter, if available. See [url=https://developer.android.com/reference/android/Manifest.permission#TRANSMIT_IR]TRANSMIT_IR[/url].
</member>
<member name="permissions/uninstall_shortcut" type="bool" setter="" getter="">
Deprecated.
</member>
<member name="permissions/update_device_stats" type="bool" setter="" getter="">
Allows an application to update device statistics. See [url=https://developer.android.com/reference/android/Manifest.permission#UPDATE_DEVICE_STATS]UPDATE_DEVICE_STATS[/url].
</member>
<member name="permissions/use_credentials" type="bool" setter="" getter="">
Allows an application to request authtokens from the AccountManager.
</member>
<member name="permissions/use_sip" type="bool" setter="" getter="">
Allows an application to use SIP service. See [url=https://developer.android.com/reference/android/Manifest.permission#USE_SIP]USE_SIP[/url].
</member>
<member name="permissions/vibrate" type="bool" setter="" getter="">
Allows access to the vibrator. See [url=https://developer.android.com/reference/android/Manifest.permission#VIBRATE]VIBRATE[/url].
</member>
<member name="permissions/wake_lock" type="bool" setter="" getter="">
Allows using PowerManager WakeLocks to keep processor from sleeping or screen from dimming. See [url=https://developer.android.com/reference/android/Manifest.permission#WAKE_LOCK]WAKE_LOCK[/url].
</member>
<member name="permissions/write_apn_settings" type="bool" setter="" getter="">
Allows applications to write the apn settings and read sensitive fields of an existing apn settings like user and password. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_APN_SETTINGS]WRITE_APN_SETTINGS[/url].
</member>
<member name="permissions/write_calendar" type="bool" setter="" getter="">
Allows an application to write the user's calendar data. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_CALENDAR]WRITE_CALENDAR[/url].
</member>
<member name="permissions/write_call_log" type="bool" setter="" getter="">
Allows an application to write (but not read) the user's call log data. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_CALL_LOG]WRITE_CALL_LOG[/url].
</member>
<member name="permissions/write_contacts" type="bool" setter="" getter="">
Allows an application to write the user's contacts data. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_CONTACTS]WRITE_CONTACTS[/url].
</member>
<member name="permissions/write_external_storage" type="bool" setter="" getter="">
Allows an application to write to external storage. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_EXTERNAL_STORAGE]WRITE_EXTERNAL_STORAGE[/url].
</member>
<member name="permissions/write_gservices" type="bool" setter="" getter="">
Allows an application to modify the Google service map. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_GSERVICES]WRITE_GSERVICES[/url].
</member>
<member name="permissions/write_history_bookmarks" type="bool" setter="" getter="">
Allows an application to write (but not read) the user's browsing history and bookmarks.
</member>
<member name="permissions/write_profile" type="bool" setter="" getter="">
Allows an application to write (but not read) the user's personal profile data.
</member>
<member name="permissions/write_secure_settings" type="bool" setter="" getter="">
Allows an application to read or write the secure system settings. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_SECURE_SETTINGS]WRITE_SECURE_SETTINGS[/url].
</member>
<member name="permissions/write_settings" type="bool" setter="" getter="">
Allows an application to read or write the system settings. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_SETTINGS]WRITE_SETTINGS[/url].
</member>
<member name="permissions/write_sms" type="bool" setter="" getter="">
Allows an application to write SMS messages.
</member>
<member name="permissions/write_social_stream" type="bool" setter="" getter="">
Allows an application to write (but not read) the user's social stream data.
</member>
<member name="permissions/write_sync_settings" type="bool" setter="" getter="">
Allows applications to write the sync settings. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_SYNC_SETTINGS]WRITE_SYNC_SETTINGS[/url].
</member>
<member name="permissions/write_user_dictionary" type="bool" setter="" getter="">
Allows an application to write to the user dictionary.
</member>
<member name="screen/immersive_mode" type="bool" setter="" getter="">
If [code]true[/code], hides navigation and status bar.
</member>
<member name="screen/support_large" type="bool" setter="" getter="">
Indicates whether the application supports larger screen form-factors.
</member>
<member name="screen/support_normal" type="bool" setter="" getter="">
Indicates whether an application supports the "normal" screen form-factors.
</member>
<member name="screen/support_small" type="bool" setter="" getter="">
Indicates whether the application supports smaller screen form-factors.
</member>
<member name="screen/support_xlarge" type="bool" setter="" getter="">
Indicates whether the application supports extra large screen form-factors.
</member>
<member name="user_data_backup/allow" type="bool" setter="" getter="">
If [code]true[/code], allows the application to participate in the backup and restore infrastructure.
</member>
<member name="version/code" type="int" setter="" getter="">
Machine-readable application version.
</member>
<member name="version/name" type="String" setter="" getter="">
Application version visible to the user.
</member>
<member name="xr_features/hand_tracking" type="int" setter="" getter="">
</member>
<member name="xr_features/hand_tracking_frequency" type="int" setter="" getter="">
</member>
<member name="xr_features/passthrough" type="int" setter="" getter="">
</member>
<member name="xr_features/xr_mode" type="int" setter="" getter="">
</member>
</members>
</class>

View file

@ -0,0 +1,181 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorExportPlatformIOS" inherits="EditorExportPlatform" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Exporter for iOS.
</brief_description>
<description>
</description>
<tutorials>
<link title="Exporting for iOS">$DOCS_URL/tutorials/export/exporting_for_ios.html</link>
</tutorials>
<members>
<member name="application/app_store_team_id" type="String" setter="" getter="">
Apple Team ID, unique 10-character string. To locate your Team ID check "Membership details" section in your Apple developer account dashboard, or "Organisational Unit" of your code signing certificate. See [url=https://developer.apple.com/help/account/manage-your-team/locate-your-team-id]Locate your Team ID[/url].
</member>
<member name="application/bundle_identifier" type="String" setter="" getter="">
Unique application identifier in a reverse-DNS format, can only contain alphanumeric characters ([code]A-Z[/code], [code]a-z[/code], and [code]0-9[/code]), hyphens ([code]-[/code]), and periods ([code].[/code]).
</member>
<member name="application/code_sign_identity_debug" type="String" setter="" getter="">
The "Full Name", "Common Name" or SHA-1 hash of the signing identity used for debug export.
</member>
<member name="application/code_sign_identity_release" type="String" setter="" getter="">
The "Full Name", "Common Name" or SHA-1 hash of the signing identity used for release export.
</member>
<member name="application/export_method_debug" type="int" setter="" getter="">
Application distribution target (debug export).
</member>
<member name="application/export_method_release" type="int" setter="" getter="">
Application distribution target (release export).
</member>
<member name="application/icon_interpolation" type="int" setter="" getter="">
Interpolation method used to resize application icon.
</member>
<member name="application/launch_screens_interpolation" type="int" setter="" getter="">
Interpolation method used to resize launch screen images.
</member>
<member name="application/provisioning_profile_uuid_debug" type="String" setter="" getter="">
UUID of the provisioning profile. If left empty, Xcode will download or create a provisioning profile automatically. See [url=https://developer.apple.com/help/account/manage-profiles/edit-download-or-delete-profiles]Edit, download, or delete provisioning profiles[/url].
</member>
<member name="application/provisioning_profile_uuid_release" type="String" setter="" getter="">
UUID of the provisioning profile. If left empty, Xcode will download or create a provisioning profile automatically. See [url=https://developer.apple.com/help/account/manage-profiles/edit-download-or-delete-profiles]Edit, download, or delete provisioning profiles[/url].
</member>
<member name="application/short_version" type="String" setter="" getter="">
Application version visible to the user, can only contain numeric characters ([code]0-9[/code]) and periods ([code].[/code]).
</member>
<member name="application/signature" type="String" setter="" getter="">
A four-character creator code that is specific to the bundle. Optional.
</member>
<member name="application/targeted_device_family" type="int" setter="" getter="">
Supported device family.
</member>
<member name="application/version" type="String" setter="" getter="">
Machine-readable application version, in the [code]major.minor.patch[/code] format, can only contain numeric characters ([code]0-9[/code]) and periods ([code].[/code]).
</member>
<member name="architectures/arm64" type="bool" setter="" getter="">
If [code]true[/code], [code]arm64[/code] binaries are included into exported project.
</member>
<member name="capabilities/access_wifi" type="bool" setter="" getter="">
If [code]true[/code], networking features related to Wi-Fi access are enabled. See [url=https://developer.apple.com/support/required-device-capabilities/]Required Device Capabilities[/url].
</member>
<member name="capabilities/push_notifications" type="bool" setter="" getter="">
If [code]true[/code], push notifications are enabled. See [url=https://developer.apple.com/support/required-device-capabilities/]Required Device Capabilities[/url].
</member>
<member name="custom_template/debug" type="String" setter="" getter="">
Path to the custom export template. If left empty, default template is used.
</member>
<member name="custom_template/release" type="String" setter="" getter="">
Path to the custom export template. If left empty, default template is used.
</member>
<member name="icons/app_store_1024x1024" type="String" setter="" getter="">
App Store application icon file. If left empty, project icon is used instead. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
<member name="icons/ipad_152x152" type="String" setter="" getter="">
Home screen application icon file on iPad (2x DPI). If left empty, project icon is used instead. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
<member name="icons/ipad_167x167" type="String" setter="" getter="">
Home screen application icon file on iPad (3x DPI). If left empty, project icon is used instead. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
<member name="icons/ipad_76x76" type="String" setter="" getter="">
Home screen application icon file on iPad (1x DPI). If left empty, project icon is used instead. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
<member name="icons/iphone_120x120" type="String" setter="" getter="">
Home screen application icon file on iPhone (2x DPI). If left empty, project icon is used instead. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
<member name="icons/iphone_180x180" type="String" setter="" getter="">
Home screen application icon file on iPhone (3x DPI). If left empty, project icon is used instead. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
<member name="icons/notification_40x40" type="String" setter="" getter="">
Notification icon file on iPad and iPhone (2x DPI). If left empty, project icon is used instead. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
<member name="icons/notification_60x60" type="String" setter="" getter="">
Notification icon file on iPhone (3x DPI). If left empty, project icon is used instead. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
<member name="icons/settings_58x58" type="String" setter="" getter="">
Application settings icon file on iPad and iPhone (2x DPI). If left empty, project icon is used instead. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
<member name="icons/settings_87x87" type="String" setter="" getter="">
Application settings icon file on iPhone (3x DPI). If left empty, project icon is used instead. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
<member name="icons/spotlight_40x40" type="String" setter="" getter="">
Spotlight icon file on iPad (1x DPI). If left empty, project icon is used instead. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
<member name="icons/spotlight_80x80" type="String" setter="" getter="">
Spotlight icon file on iPad and iPhone (2x DPI). If left empty, project icon is used instead. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
<member name="landscape_launch_screens/ipad_1024x768" type="String" setter="" getter="">
Application launch screen image file, if left empty project splash screen is used instead.
</member>
<member name="landscape_launch_screens/ipad_2048x1536" type="String" setter="" getter="">
Application launch screen image file, if left empty project splash screen is used instead.
</member>
<member name="landscape_launch_screens/iphone_2208x1242" type="String" setter="" getter="">
Application launch screen image file, if left empty project splash screen is used instead.
</member>
<member name="landscape_launch_screens/iphone_2436x1125" type="String" setter="" getter="">
Application launch screen image file, if left empty project splash screen is used instead.
</member>
<member name="portrait_launch_screens/ipad_1536x2048" type="String" setter="" getter="">
Application launch screen image file, if left empty project splash screen is used instead.
</member>
<member name="portrait_launch_screens/ipad_768x1024" type="String" setter="" getter="">
Application launch screen image file, if left empty project splash screen is used instead.
</member>
<member name="portrait_launch_screens/iphone_1125x2436" type="String" setter="" getter="">
Application launch screen image file, if left empty project splash screen is used instead.
</member>
<member name="portrait_launch_screens/iphone_1242x2208" type="String" setter="" getter="">
Application launch screen image file, if left empty project splash screen is used instead.
</member>
<member name="portrait_launch_screens/iphone_640x1136" type="String" setter="" getter="">
Application launch screen image file, if left empty project splash screen is used instead.
</member>
<member name="portrait_launch_screens/iphone_640x960" type="String" setter="" getter="">
Application launch screen image file, if left empty project splash screen is used instead.
</member>
<member name="portrait_launch_screens/iphone_750x1334" type="String" setter="" getter="">
Application launch screen image file, if left empty project splash screen is used instead.
</member>
<member name="privacy/camera_usage_description" type="String" setter="" getter="">
A message displayed when requesting access to the device's camera (in English).
</member>
<member name="privacy/camera_usage_description_localized" type="Dictionary" setter="" getter="">
A message displayed when requesting access to the device's camera (localized).
</member>
<member name="privacy/microphone_usage_description" type="String" setter="" getter="">
A message displayed when requesting access to the device's microphone (in English).
</member>
<member name="privacy/microphone_usage_description_localized" type="Dictionary" setter="" getter="">
A message displayed when requesting access to the device's microphone (localized).
</member>
<member name="privacy/photolibrary_usage_description" type="String" setter="" getter="">
A message displayed when requesting access to the user's photo library (in English).
</member>
<member name="privacy/photolibrary_usage_description_localized" type="Dictionary" setter="" getter="">
A message displayed when requesting access to the user's photo library (localized).
</member>
<member name="storyboard/custom_bg_color" type="Color" setter="" getter="">
A custom background color of the storyboard launch screen.
</member>
<member name="storyboard/custom_image@2x" type="String" setter="" getter="">
Application launch screen image file (2x DPI), if left empty project splash screen is used instead.
</member>
<member name="storyboard/custom_image@3x" type="String" setter="" getter="">
Application launch screen image file (3x DPI), if left empty project splash screen is used instead.
</member>
<member name="storyboard/image_scale_mode" type="int" setter="" getter="">
Launch screen image scaling mode.
</member>
<member name="storyboard/use_custom_bg_color" type="bool" setter="" getter="">
If [code]true[/code], [member storyboard/custom_bg_color] is used as a launch screen background color, otherwise [code]application/boot_splash/bg_color[/code] project setting is used.
</member>
<member name="storyboard/use_launch_screen_storyboard" type="bool" setter="" getter="">
If [code]true[/code], storyboard launch screen is used instead of launch screen images.
</member>
<member name="user_data/accessible_from_files_app" type="bool" setter="" getter="">
If [code]true[/code], the app "Documents" folder can be accessed via "Files" app. See [url=https://developer.apple.com/documentation/bundleresources/information_property_list/lssupportsopeningdocumentsinplace]LSSupportsOpeningDocumentsInPlace[/url].
</member>
<member name="user_data/accessible_from_itunes_sharing" type="bool" setter="" getter="">
If [code]true[/code], the app "Documents" folder can be accessed via iTunes file sharing. See [url=https://developer.apple.com/documentation/bundleresources/information_property_list/uifilesharingenabled]UIFileSharingEnabled[/url].
</member>
</members>
</class>

View file

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorExportPlatformLinuxBSD" inherits="EditorExportPlatformPC" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Exporter for Linux/BSD.
</brief_description>
<description>
</description>
<tutorials>
<link title="Exporting for Linux">$DOCS_URL/tutorials/export/exporting_for_linux.html</link>
</tutorials>
<members>
<member name="binary_format/architecture" type="String" setter="" getter="">
Application executable architecture.
Supported architectures: [code]x86_32[/code], [code]x86_64[/code], [code]arm64[/code], [code]arm32[/code], [code]rv64[/code], [code]ppc64[/code], and [code]ppc32[/code].
Official export templates include [code]x86_32[/code] and [code]x86_64[/code] binaries only.
</member>
<member name="binary_format/embed_pck" type="bool" setter="" getter="">
If [code]true[/code], project resources are embedded into the executable.
</member>
<member name="custom_template/debug" type="String" setter="" getter="">
Path to the custom export template. If left empty, default template is used.
</member>
<member name="custom_template/release" type="String" setter="" getter="">
Path to the custom export template. If left empty, default template is used.
</member>
<member name="debug/export_console_script" type="int" setter="" getter="">
If [code]true[/code], a console wrapper script is exported alongside the main executable, which allows running the project with enabled console output.
</member>
<member name="ssh_remote_deploy/cleanup_script" type="String" setter="" getter="">
Script code to execute on the remote host when app is finished.
The following variables can be used in the script:
- [code]{temp_dir}[/code] - Path of temporary folder on the remote, used to upload app and scripts to.
- [code]{archive_name}[/code] - Name of the ZIP containing uploaded application.
- [code]{exe_name}[/code] - Name of application executable.
- [code]{cmd_args}[/code] - Array of the command line argument for the application.
</member>
<member name="ssh_remote_deploy/enabled" type="bool" setter="" getter="">
Enables remote deploy using SSH/SCP.
</member>
<member name="ssh_remote_deploy/extra_args_scp" type="String" setter="" getter="">
Array of the additional command line arguments passed to the SCP.
</member>
<member name="ssh_remote_deploy/extra_args_ssh" type="String" setter="" getter="">
Array of the additional command line arguments passed to the SSH.
</member>
<member name="ssh_remote_deploy/host" type="String" setter="" getter="">
Remote host SSH user name and address, in [code]user@address[/code] format.
</member>
<member name="ssh_remote_deploy/port" type="String" setter="" getter="">
Remote host SSH port number.
</member>
<member name="ssh_remote_deploy/run_script" type="String" setter="" getter="">
Script code to execute on the remote host when running the app.
The following variables can be used in the script:
- [code]{temp_dir}[/code] - Path of temporary folder on the remote, used to upload app and scripts to.
- [code]{archive_name}[/code] - Name of the ZIP containing uploaded application.
- [code]{exe_name}[/code] - Name of application executable.
- [code]{cmd_args}[/code] - Array of the command line argument for the application.
</member>
<member name="texture_format/bptc" type="bool" setter="" getter="">
If [code]true[/code], project textures are exported in the BPTC format.
</member>
<member name="texture_format/etc" type="bool" setter="" getter="">
If [code]true[/code], project textures are exported in the ETC format.
</member>
<member name="texture_format/etc2" type="bool" setter="" getter="">
If [code]true[/code], project textures are exported in the ETC2 format.
</member>
<member name="texture_format/s3tc" type="bool" setter="" getter="">
If [code]true[/code], project textures are exported in the S3TC format.
</member>
</members>
</class>

View file

@ -0,0 +1,291 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorExportPlatformMacOS" inherits="EditorExportPlatform" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Exporter for macOS.
</brief_description>
<description>
</description>
<tutorials>
<link title="Exporting for macOS">$DOCS_URL/tutorials/export/exporting_for_macos.html</link>
<link title="Running Godot apps on macOS">$DOCS_URL/tutorials//export/running_on_macos.html</link>
</tutorials>
<members>
<member name="application/app_category" type="String" setter="" getter="">
Application category for the App Store.
</member>
<member name="application/bundle_identifier" type="String" setter="" getter="">
Unique application identifier in a reverse-DNS format, can only contain alphanumeric characters ([code]A-Z[/code], [code]a-z[/code], and [code]0-9[/code]), hyphens ([code]-[/code]), and periods ([code].[/code]).
</member>
<member name="application/copyright" type="String" setter="" getter="">
Copyright notice for the bundle visible to the user (in English).
</member>
<member name="application/copyright_localized" type="Dictionary" setter="" getter="">
Copyright notice for the bundle visible to the user (localized).
</member>
<member name="application/icon" type="String" setter="" getter="">
Application icon file. If left empty, project icon is used instead.
</member>
<member name="application/icon_interpolation" type="int" setter="" getter="">
Interpolation method used to resize application icon.
</member>
<member name="application/min_macos_version" type="String" setter="" getter="">
Minimum version of macOS required for this application to run in the [code]major.minor.patch[/code] or [code]major.minor[/code] format, can only contain numeric characters ([code]0-9[/code]) and periods ([code].[/code]).
</member>
<member name="application/short_version" type="String" setter="" getter="">
Application version visible to the user, can only contain numeric characters ([code]0-9[/code]) and periods ([code].[/code]).
</member>
<member name="application/signature" type="String" setter="" getter="">
A four-character creator code that is specific to the bundle. Optional.
</member>
<member name="application/version" type="String" setter="" getter="">
Machine-readable application version, in the [code]major.minor.patch[/code] format, can only contain numeric characters ([code]0-9[/code]) and periods ([code].[/code]).
</member>
<member name="binary_format/architecture" type="String" setter="" getter="">
Application executable architecture.
Supported architectures: [code]x86_64[/code], [code]arm64[/code], and [code]universal[/code] ([code]x86_64 + arm64[/code]).
Official export templates include [code]universal[/code] binaries only.
</member>
<member name="codesign/apple_team_id" type="String" setter="" getter="">
Apple Team ID, unique 10-character string. To locate your Team ID check "Membership details" section in your Apple developer account dashboard, or "Organisational Unit" of your code signing certificate. See [url=https://developer.apple.com/help/account/manage-your-team/locate-your-team-id]Locate your Team ID[/url].
</member>
<member name="codesign/certificate_file" type="String" setter="" getter="">
PKCS #12 certificate file used to sign [code].app[/code] bundle.
</member>
<member name="codesign/certificate_password" type="String" setter="" getter="">
Password for the certificate file used to sign [code].app[/code] bundle.
</member>
<member name="codesign/codesign" type="int" setter="" getter="">
Tool to use for code signing.
</member>
<member name="codesign/custom_options" type="PackedStringArray" setter="" getter="">
Array of the additional command line arguments passed to the code signing tool.
</member>
<member name="codesign/entitlements/address_book" type="bool" setter="" getter="">
Enable to allow access to contacts in the user's address book, if it's enabled you should also provide usage message in the [code]privacy/address_book_usage_description[/code] option. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_personal-information_addressbook]com.apple.security.personal-information.addressbook[/url].
</member>
<member name="codesign/entitlements/allow_dyld_environment_variables" type="bool" setter="" getter="">
Allows app to use dynamic linker environment variables to inject code. If you are using add-ons with dynamic or self-modifying native code, enable them according to the add-on documentation. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_cs_allow-dyld-environment-variables]com.apple.security.cs.allow-dyld-environment-variables[/url].
</member>
<member name="codesign/entitlements/allow_jit_code_execution" type="bool" setter="" getter="">
Allows creating writable and executable memory for JIT code. If you are using add-ons with dynamic or self-modifying native code, enable them according to the add-on documentation. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_cs_allow-jit]com.apple.security.cs.allow-jit[/url].
</member>
<member name="codesign/entitlements/allow_unsigned_executable_memory" type="bool" setter="" getter="">
Allows creating writable and executable memory without JIT restrictions. If you are using add-ons with dynamic or self-modifying native code, enable them according to the add-on documentation. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_cs_allow-unsigned-executable-memory]com.apple.security.cs.allow-unsigned-executable-memory[/url].
</member>
<member name="codesign/entitlements/app_sandbox/device_bluetooth" type="bool" setter="" getter="">
Enable to allow app to interact with Bluetooth devices. This entitlement is required to use wireless controllers. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_device_bluetooth]com.apple.security.device.bluetooth[/url].
</member>
<member name="codesign/entitlements/app_sandbox/device_usb" type="bool" setter="" getter="">
Enable to allow app to interact with USB devices. This entitlement is required to use wired controllers. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_device_usb]com.apple.security.device.usb[/url].
</member>
<member name="codesign/entitlements/app_sandbox/enabled" type="bool" setter="" getter="">
Enables App Sandbox. The App Sandbox restricts access to user data, networking, and devices. Sandboxed apps can't access most of the file system, can't use custom file dialogs and execute binaries outside the .app bundle. See [url=https://developer.apple.com/documentation/security/app_sandbox]App Sandbox[/url].
[b]Note:[/b] To distribute an app through the App Store, you must enable the App Sandbox.
</member>
<member name="codesign/entitlements/app_sandbox/files_downloads" type="int" setter="" getter="">
Allows read or write access to the user's "Downloads" folder. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_files_downloads_read-write]com.apple.security.files.downloads.read-write[/url].
</member>
<member name="codesign/entitlements/app_sandbox/files_movies" type="int" setter="" getter="">
Allows read or write access to the user's "Movies" folder. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_assets_movies_read-write]com.apple.security.files.movies.read-write[/url].
</member>
<member name="codesign/entitlements/app_sandbox/files_music" type="int" setter="" getter="">
Allows read or write access to the user's "Music" folder. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_assets_music_read-write]com.apple.security.files.music.read-write[/url].
</member>
<member name="codesign/entitlements/app_sandbox/files_pictures" type="int" setter="" getter="">
Allows read or write access to the user's "Pictures" folder. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_assets_pictures_read-write]com.apple.security.files.pictures.read-write[/url].
</member>
<member name="codesign/entitlements/app_sandbox/helper_executables" type="Array" setter="" getter="">
List of helper executables to embedded to the app bundle. Sandboxed app are limited to execute only these executable. See [url=https://developer.apple.com/documentation/xcode/embedding-a-helper-tool-in-a-sandboxed-app]Embedding a command-line tool in a sandboxed app[/url].
</member>
<member name="codesign/entitlements/app_sandbox/network_client" type="bool" setter="" getter="">
Enable to allow app to establish outgoing network connections. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_network_client]com.apple.security.network.client[/url].
</member>
<member name="codesign/entitlements/app_sandbox/network_server" type="bool" setter="" getter="">
Enable to allow app to listen for incoming network connections. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_network_server]com.apple.security.network.server[/url].
</member>
<member name="codesign/entitlements/apple_events" type="bool" setter="" getter="">
Enable to allow app to send Apple events to other apps. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_automation_apple-events]com.apple.security.automation.apple-events[/url].
</member>
<member name="codesign/entitlements/audio_input" type="bool" setter="" getter="">
Enable if you need to use the microphone or other audio input sources, if it's enabled you should also provide usage message in the [code]privacy/microphone_usage_description[/code] option. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_device_audio-input]com.apple.security.device.audio-input[/url].
</member>
<member name="codesign/entitlements/calendars" type="bool" setter="" getter="">
Enable to allow access to the user's calendar, if it's enabled you should also provide usage message in the [code]privacy/calendar_usage_description[/code] option. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_personal-information_calendars]com.apple.security.personal-information.calendars[/url].
</member>
<member name="codesign/entitlements/camera" type="bool" setter="" getter="">
Enable if you need to use the camera, if it's enabled you should also provide usage message in the [code]privacy/camera_usage_description[/code] option. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_device_camera]com.apple.security.device.camera[/url].
</member>
<member name="codesign/entitlements/custom_file" type="String" setter="" getter="">
Custom entitlements [code].plist[/code] file, if specified the rest of entitlements in the export config are ignored.
</member>
<member name="codesign/entitlements/debugging" type="bool" setter="" getter="">
You can temporarily enable this entitlement to use native debugger (GDB, LLDB) with the exported app. This entitlement should be disabled for production export. See [url=https://developer.apple.com/documentation/xcode/embedding-a-helper-tool-in-a-sandboxed-app]Embedding a command-line tool in a sandboxed app[/url].
</member>
<member name="codesign/entitlements/disable_library_validation" type="bool" setter="" getter="">
Allows app to load arbitrary libraries and frameworks (not signed with the same Team ID as the main executable or by Apple). Enable it if you are using GDExtension add-ons or ad-hoc signing, or want to support user-provided external add-ons. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_cs_disable-library-validation]com.apple.security.cs.disable-library-validation[/url].
</member>
<member name="codesign/entitlements/location" type="bool" setter="" getter="">
Enable if you need to use location information from Location Services, if it's enabled you should also provide usage message in the [code]privacy/location_usage_description[/code] option. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_personal-information_location]com.apple.security.personal-information.location[/url].
</member>
<member name="codesign/entitlements/photos_library" type="bool" setter="" getter="">
Enable to allow access to the user's Photos library, if it's enabled you should also provide usage message in the [code]privacy/photos_library_usage_description[/code] option. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_personal-information_photos-library]com.apple.security.personal-information.photos-library[/url].
</member>
<member name="codesign/identity" type="String" setter="" getter="">
The "Full Name", "Common Name" or SHA-1 hash of the signing identity used to sign [code].app[/code] bundle.
</member>
<member name="codesign/installer_identity" type="String" setter="" getter="">
The "Full Name", "Common Name" or SHA-1 hash of the signing identity used to sign [code].pkg[/code] installer package for App Store distribution, use [code]3rd Party Mac Developer Installer: Name.[/code] identity.
</member>
<member name="codesign/provisioning_profile" type="String" setter="" getter="">
Provisioning profile file downloaded from Apple developer account dashboard. See [url=https://developer.apple.com/help/account/manage-profiles/edit-download-or-delete-profiles]Edit, download, or delete provisioning profiles[/url].
</member>
<member name="custom_template/debug" type="String" setter="" getter="">
Path to the custom export template. If left empty, default template is used.
</member>
<member name="custom_template/release" type="String" setter="" getter="">
Path to the custom export template. If left empty, default template is used.
</member>
<member name="debug/export_console_script" type="int" setter="" getter="">
If enabled, a script file that can be used to run the application with console output is created alongside the exported application.
</member>
<member name="display/high_res" type="bool" setter="" getter="">
If [code]true[/code], the application is rendered at native display resolution, otherwise it is always rendered at loHPI resolution and upscaled by OS when required.
</member>
<member name="export/distribution_type" type="int" setter="" getter="">
Application distribution target.
</member>
<member name="notarization/api_key" type="String" setter="" getter="">
Apple App Store Connect API issuer key file.
</member>
<member name="notarization/api_key_id" type="String" setter="" getter="">
Apple App Store Connect API issuer key ID.
</member>
<member name="notarization/api_uuid" type="String" setter="" getter="">
Apple App Store Connect API issuer UUID.
</member>
<member name="notarization/apple_id_name" type="String" setter="" getter="">
Apple ID account name (email address).
</member>
<member name="notarization/apple_id_password" type="String" setter="" getter="">
Apple ID app-specific password.
</member>
<member name="notarization/notarization" type="int" setter="" getter="">
Tool to use for notarization.
</member>
<member name="privacy/address_book_usage_description" type="String" setter="" getter="">
A message displayed when requesting access to the user's contacts (in English).
</member>
<member name="privacy/address_book_usage_description_localized" type="Dictionary" setter="" getter="">
A message displayed when requesting access to the user's contacts (localized).
</member>
<member name="privacy/calendar_usage_description" type="String" setter="" getter="">
A message displayed when requesting access to the user's calendar data (in English).
</member>
<member name="privacy/calendar_usage_description_localized" type="Dictionary" setter="" getter="">
A message displayed when requesting access to the user's calendar data (localized).
</member>
<member name="privacy/camera_usage_description" type="String" setter="" getter="">
A message displayed when requesting access to the device's camera (in English).
</member>
<member name="privacy/camera_usage_description_localized" type="Dictionary" setter="" getter="">
A message displayed when requesting access to the device's camera (localized).
</member>
<member name="privacy/desktop_folder_usage_description" type="String" setter="" getter="">
A message displayed when requesting access to the user's "Desktop" folder (in English).
</member>
<member name="privacy/desktop_folder_usage_description_localized" type="Dictionary" setter="" getter="">
A message displayed when requesting access to the user's "Desktop" folder (localized).
</member>
<member name="privacy/documents_folder_usage_description" type="String" setter="" getter="">
A message displayed when requesting access to the user's "Documents" folder (in English).
</member>
<member name="privacy/documents_folder_usage_description_localized" type="Dictionary" setter="" getter="">
A message displayed when requesting access to the user's "Documents" folder (localized).
</member>
<member name="privacy/downloads_folder_usage_description" type="String" setter="" getter="">
A message displayed when requesting access to the user's "Downloads" folder (in English).
</member>
<member name="privacy/downloads_folder_usage_description_localized" type="Dictionary" setter="" getter="">
A message displayed when requesting access to the user's "Downloads" folder (localized).
</member>
<member name="privacy/location_usage_description" type="String" setter="" getter="">
A message displayed when requesting access to the user's location information (in English).
</member>
<member name="privacy/location_usage_description_localized" type="Dictionary" setter="" getter="">
A message displayed when requesting access to the user's location information (localized).
</member>
<member name="privacy/microphone_usage_description" type="String" setter="" getter="">
A message displayed when requesting access to the device's microphone (in English).
</member>
<member name="privacy/microphone_usage_description_localized" type="Dictionary" setter="" getter="">
A message displayed when requesting access to the device's microphone (localized).
</member>
<member name="privacy/network_volumes_usage_description" type="String" setter="" getter="">
A message displayed when requesting access to the user's network drives (in English).
</member>
<member name="privacy/network_volumes_usage_description_localized" type="Dictionary" setter="" getter="">
A message displayed when requesting access to the user's network drives (localized).
</member>
<member name="privacy/photos_library_usage_description" type="String" setter="" getter="">
A message displayed when requesting access to the user's photo library (in English).
</member>
<member name="privacy/photos_library_usage_description_localized" type="Dictionary" setter="" getter="">
A message displayed when requesting access to the user's photo library (localized).
</member>
<member name="privacy/removable_volumes_usage_description" type="String" setter="" getter="">
A message displayed when requesting access to the user's removable drives (in English).
</member>
<member name="privacy/removable_volumes_usage_description_localized" type="Dictionary" setter="" getter="">
A message displayed when requesting access to the user's removable drives (localized).
</member>
<member name="ssh_remote_deploy/cleanup_script" type="String" setter="" getter="">
Script code to execute on the remote host when app is finished.
The following variables can be used in the script:
- [code]{temp_dir}[/code] - Path of temporary folder on the remote, used to upload app and scripts to.
- [code]{archive_name}[/code] - Name of the ZIP containing uploaded application.
- [code]{exe_name}[/code] - Name of application executable.
- [code]{cmd_args}[/code] - Array of the command line argument for the application.
</member>
<member name="ssh_remote_deploy/enabled" type="bool" setter="" getter="">
Enables remote deploy using SSH/SCP.
</member>
<member name="ssh_remote_deploy/extra_args_scp" type="String" setter="" getter="">
Array of the additional command line arguments passed to the SCP.
</member>
<member name="ssh_remote_deploy/extra_args_ssh" type="String" setter="" getter="">
Array of the additional command line arguments passed to the SSH.
</member>
<member name="ssh_remote_deploy/host" type="String" setter="" getter="">
Remote host SSH user name and address, in [code]user@address[/code] format.
</member>
<member name="ssh_remote_deploy/port" type="String" setter="" getter="">
Remote host SSH port number.
</member>
<member name="ssh_remote_deploy/run_script" type="String" setter="" getter="">
Script code to execute on the remote host when running the app.
The following variables can be used in the script:
- [code]{temp_dir}[/code] - Path of temporary folder on the remote, used to upload app and scripts to.
- [code]{archive_name}[/code] - Name of the ZIP containing uploaded application.
- [code]{exe_name}[/code] - Name of application executable.
- [code]{cmd_args}[/code] - Array of the command line argument for the application.
</member>
<member name="xcode/platform_build" type="String" setter="" getter="">
macOS build number used to build application executable.
</member>
<member name="xcode/sdk_build" type="String" setter="" getter="">
macOS SDK build number used to build application executable.
</member>
<member name="xcode/sdk_name" type="String" setter="" getter="">
macOS SDK name used to build application executable.
</member>
<member name="xcode/sdk_version" type="String" setter="" getter="">
macOS SDK version used to build application executable in the [code]major.minor[/code] format.
</member>
<member name="xcode/xcode_build" type="String" setter="" getter="">
Xcode build number used to build application executable.
</member>
<member name="xcode/xcode_version" type="String" setter="" getter="">
Xcode version used to build application executable.
</member>
</members>
</class>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorExportPlatformPC" inherits="EditorExportPlatform" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for the desktop platform exporter (Windows and Linux/BSD).
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
</class>

View file

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorExportPlatformWeb" inherits="EditorExportPlatform" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Exporter for the Web.
</brief_description>
<description>
</description>
<tutorials>
<link title="Exporting for the Web">$DOCS_URL/tutorials/export/exporting_for_web.html</link>
</tutorials>
<members>
<member name="custom_template/debug" type="String" setter="" getter="">
Path to the custom export template. If left empty, default template is used.
</member>
<member name="custom_template/release" type="String" setter="" getter="">
Path to the custom export template. If left empty, default template is used.
</member>
<member name="html/canvas_resize_policy" type="int" setter="" getter="">
The canvas resize policy determines how the canvas should be resized by Godot.
</member>
<member name="html/custom_html_shell" type="String" setter="" getter="">
</member>
<member name="html/experimental_virtual_keyboard" type="bool" setter="" getter="">
</member>
<member name="html/export_icon" type="bool" setter="" getter="">
</member>
<member name="html/focus_canvas_on_start" type="bool" setter="" getter="">
</member>
<member name="html/head_include" type="String" setter="" getter="">
</member>
<member name="progressive_web_app/background_color" type="Color" setter="" getter="">
</member>
<member name="progressive_web_app/display" type="int" setter="" getter="">
</member>
<member name="progressive_web_app/enabled" type="bool" setter="" getter="">
</member>
<member name="progressive_web_app/icon_144x144" type="String" setter="" getter="">
</member>
<member name="progressive_web_app/icon_180x180" type="String" setter="" getter="">
</member>
<member name="progressive_web_app/icon_512x512" type="String" setter="" getter="">
</member>
<member name="progressive_web_app/offline_page" type="String" setter="" getter="">
</member>
<member name="progressive_web_app/orientation" type="int" setter="" getter="">
</member>
<member name="variant/extensions_support" type="bool" setter="" getter="">
</member>
<member name="vram_texture_compression/for_desktop" type="bool" setter="" getter="">
</member>
<member name="vram_texture_compression/for_mobile" type="bool" setter="" getter="">
</member>
</members>
</class>

View file

@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorExportPlatformWindows" inherits="EditorExportPlatformPC" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Exporter for Windows.
</brief_description>
<description>
</description>
<tutorials>
<link title="Exporting for Windows">$DOCS_URL/tutorials/export/exporting_for_windows.html</link>
</tutorials>
<members>
<member name="application/company_name" type="String" setter="" getter="">
Company that produced the application. Required. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url].
</member>
<member name="application/console_wrapper_icon" type="String" setter="" getter="">
Console wrapper icon file. If left empty, application icon is used instead.
</member>
<member name="application/copyright" type="String" setter="" getter="">
Copyright notice for the bundle visible to the user. Optional. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url].
</member>
<member name="application/file_description" type="String" setter="" getter="">
File description to be presented to users. Required. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url].
</member>
<member name="application/file_version" type="String" setter="" getter="">
Version number of the file. Required. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url].
</member>
<member name="application/icon" type="String" setter="" getter="">
Application icon file. If left empty, project icon is used instead.
</member>
<member name="application/icon_interpolation" type="int" setter="" getter="">
Interpolation method used to resize application icon.
</member>
<member name="application/modify_resources" type="bool" setter="" getter="">
If enabled, icon and metadata of the exported executable is set according to the other [code]application/*[/code] values.
</member>
<member name="application/product_name" type="String" setter="" getter="">
Name of the application. Required. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url].
</member>
<member name="application/product_version" type="String" setter="" getter="">
Application version visible to the user. Required. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url].
</member>
<member name="application/trademarks" type="String" setter="" getter="">
Trademarks and registered trademarks that apply to the file. Optional. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url].
</member>
<member name="binary_format/architecture" type="String" setter="" getter="">
Application executable architecture.
Supported architectures: [code]x86_32[/code], [code]x86_64[/code], and [code]arm64[/code].
Official export templates include [code]x86_32[/code] and [code]x86_64[/code] binaries only.
</member>
<member name="binary_format/embed_pck" type="bool" setter="" getter="">
If [code]true[/code], project resources are embedded into the executable.
</member>
<member name="codesign/custom_options" type="PackedStringArray" setter="" getter="">
Array of the additional command line arguments passed to the code signing tool. See [url=https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe]Sign Tool[/url].
</member>
<member name="codesign/description" type="String" setter="" getter="">
Description of the signed content. See [url=https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe]Sign Tool[/url].
</member>
<member name="codesign/digest_algorithm" type="int" setter="" getter="">
Digest algorithm to use for creating signature. See [url=https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe]Sign Tool[/url].
</member>
<member name="codesign/enable" type="bool" setter="" getter="">
If [code]true[/code], executable signing is enabled.
</member>
<member name="codesign/identity" type="String" setter="" getter="">
PKCS #12 certificate file used to sign executable or certificate SHA-1 hash (if [member codesign/identity_type] is set to "Use certificate store"). See [url=https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe]Sign Tool[/url].
</member>
<member name="codesign/identity_type" type="int" setter="" getter="">
Type of identity to use. See [url=https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe]Sign Tool[/url].
</member>
<member name="codesign/password" type="String" setter="" getter="">
Password for the certificate file used to sign executable. See [url=https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe]Sign Tool[/url].
</member>
<member name="codesign/timestamp" type="bool" setter="" getter="">
If [code]true[/code], time-stamp is added to the signature. See [url=https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe]Sign Tool[/url].
</member>
<member name="codesign/timestamp_server_url" type="String" setter="" getter="">
URL of the time stamp server. If left empty, the default server is used. See [url=https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe]Sign Tool[/url].
</member>
<member name="custom_template/debug" type="String" setter="" getter="">
Path to the custom export template. If left empty, default template is used.
</member>
<member name="custom_template/release" type="String" setter="" getter="">
Path to the custom export template. If left empty, default template is used.
</member>
<member name="debug/export_console_script" type="int" setter="" getter="">
If [code]true[/code], a console wrapper executable is exported alongside the main executable, which allows running the project with enabled console output.
</member>
<member name="ssh_remote_deploy/cleanup_script" type="String" setter="" getter="">
Script code to execute on the remote host when app is finished.
The following variables can be used in the script:
- [code]{temp_dir}[/code] - Path of temporary folder on the remote, used to upload app and scripts to.
- [code]{archive_name}[/code] - Name of the ZIP containing uploaded application.
- [code]{exe_name}[/code] - Name of application executable.
- [code]{cmd_args}[/code] - Array of the command line argument for the application.
</member>
<member name="ssh_remote_deploy/enabled" type="bool" setter="" getter="">
Enables remote deploy using SSH/SCP.
</member>
<member name="ssh_remote_deploy/extra_args_scp" type="String" setter="" getter="">
Array of the additional command line arguments passed to the SCP.
</member>
<member name="ssh_remote_deploy/extra_args_ssh" type="String" setter="" getter="">
Array of the additional command line arguments passed to the SSH.
</member>
<member name="ssh_remote_deploy/host" type="String" setter="" getter="">
Remote host SSH user name and address, in [code]user@address[/code] format.
</member>
<member name="ssh_remote_deploy/port" type="String" setter="" getter="">
Remote host SSH port number.
</member>
<member name="ssh_remote_deploy/run_script" type="String" setter="" getter="">
Script code to execute on the remote host when running the app.
The following variables can be used in the script:
- [code]{temp_dir}[/code] - Path of temporary folder on the remote, used to upload app and scripts to.
- [code]{archive_name}[/code] - Name of the ZIP containing uploaded application.
- [code]{exe_name}[/code] - Name of application executable.
- [code]{cmd_args}[/code] - Array of the command line argument for the application.
</member>
<member name="texture_format/bptc" type="bool" setter="" getter="">
If [code]true[/code], project textures are exported in the BPTC format.
</member>
<member name="texture_format/etc" type="bool" setter="" getter="">
If [code]true[/code], project textures are exported in the ETC format.
</member>
<member name="texture_format/etc2" type="bool" setter="" getter="">
If [code]true[/code], project textures are exported in the ETC2 format.
</member>
<member name="texture_format/s3tc" type="bool" setter="" getter="">
If [code]true[/code], project textures are exported in the S3TC format.
</member>
</members>
</class>

View file

@ -26,7 +26,7 @@ def _make_doc_data_class_path(to_path):
if env.editor_build: if env.editor_build:
# Register exporters # Register exporters
reg_exporters_inc = '#include "register_exporters.h"\n' reg_exporters_inc = '#include "register_exporters.h"\n\n'
reg_exporters = "void register_exporters() {\n" reg_exporters = "void register_exporters() {\n"
for e in env.platform_exporters: for e in env.platform_exporters:
# Glob all .cpp files in export folder # Glob all .cpp files in export folder
@ -35,6 +35,10 @@ if env.editor_build:
reg_exporters += "\tregister_" + e + "_exporter();\n" reg_exporters += "\tregister_" + e + "_exporter();\n"
reg_exporters_inc += '#include "platform/' + e + '/export/export.h"\n' reg_exporters_inc += '#include "platform/' + e + '/export/export.h"\n'
reg_exporters += "}\n\n"
reg_exporters += "void register_exporter_types() {\n"
for e in env.platform_exporters:
reg_exporters += "\tregister_" + e + "_exporter_types();\n"
reg_exporters += "}\n" reg_exporters += "}\n"
# NOTE: It is safe to generate this file here, since this is still executed serially # NOTE: It is safe to generate this file here, since this is still executed serially

View file

@ -40,6 +40,7 @@
#include "core/string/translation.h" #include "core/string/translation.h"
#include "core/version.h" #include "core/version.h"
#include "editor/editor_settings.h" #include "editor/editor_settings.h"
#include "editor/export/editor_export.h"
#include "scene/resources/theme.h" #include "scene/resources/theme.h"
#include "scene/theme/theme_db.h" #include "scene/theme/theme_db.h"
@ -396,6 +397,16 @@ void DocTools::generate(bool p_basic_types) {
} else if (name == "ProjectSettings") { } else if (name == "ProjectSettings") {
ProjectSettings::get_singleton()->get_property_list(&properties); ProjectSettings::get_singleton()->get_property_list(&properties);
own_properties = properties; own_properties = properties;
} else if (name.begins_with("EditorExportPlatform") && ClassDB::can_instantiate(name)) {
Ref<EditorExportPlatform> platform = Object::cast_to<EditorExportPlatform>(ClassDB::instantiate(name));
if (platform.is_valid()) {
List<EditorExportPlatform::ExportOption> options;
platform->get_export_options(&options);
for (const EditorExportPlatform::ExportOption &E : options) {
properties.push_back(E.option);
}
own_properties = properties;
}
} else { } else {
ClassDB::get_property_list(name, &properties); ClassDB::get_property_list(name, &properties);
ClassDB::get_property_list(name, &own_properties, true); ClassDB::get_property_list(name, &own_properties, true);
@ -438,6 +449,12 @@ void DocTools::generate(bool p_basic_types) {
} }
} }
if (name.begins_with("EditorExportPlatform")) {
if (E.name == "script") {
continue;
}
}
if (name == "ProjectSettings") { if (name == "ProjectSettings") {
// Special case for project settings, so that settings are not taken from the current project's settings // Special case for project settings, so that settings are not taken from the current project's settings
if (E.name == "script" || !ProjectSettings::get_singleton()->is_builtin_setting(E.name)) { if (E.name == "script" || !ProjectSettings::get_singleton()->is_builtin_setting(E.name)) {

View file

@ -259,7 +259,7 @@ void EditorProperty::_notification(int p_what) {
} }
Color color; Color color;
if (draw_warning) { if (draw_warning || draw_prop_warning) {
color = get_theme_color(is_read_only() ? SNAME("readonly_warning_color") : SNAME("warning_color")); color = get_theme_color(is_read_only() ? SNAME("readonly_warning_color") : SNAME("warning_color"));
} else { } else {
color = get_theme_color(is_read_only() ? SNAME("readonly_color") : SNAME("property_color")); color = get_theme_color(is_read_only() ? SNAME("readonly_color") : SNAME("property_color"));
@ -486,6 +486,11 @@ void EditorProperty::update_editor_property_status() {
new_pinned = node->is_property_pinned(property); new_pinned = node->is_property_pinned(property);
} }
bool new_warning = false;
if (object->has_method("_get_property_warning")) {
new_warning = !String(object->call("_get_property_warning", property)).is_empty();
}
Variant current = object->get(_get_revert_property()); Variant current = object->get(_get_revert_property());
bool new_can_revert = EditorPropertyRevert::can_property_revert(object, property, &current) && !is_read_only(); bool new_can_revert = EditorPropertyRevert::can_property_revert(object, property, &current) && !is_read_only();
@ -498,10 +503,11 @@ void EditorProperty::update_editor_property_status() {
} }
} }
if (new_can_revert != can_revert || new_pinned != pinned || new_checked != checked) { if (new_can_revert != can_revert || new_pinned != pinned || new_checked != checked || new_warning != draw_prop_warning) {
if (new_can_revert != can_revert) { if (new_can_revert != can_revert) {
emit_signal(SNAME("property_can_revert_changed"), property, new_can_revert); emit_signal(SNAME("property_can_revert_changed"), property, new_can_revert);
} }
draw_prop_warning = new_warning;
can_revert = new_can_revert; can_revert = new_can_revert;
pinned = new_pinned; pinned = new_pinned;
checked = new_checked; checked = new_checked;
@ -897,7 +903,7 @@ void EditorProperty::_update_pin_flags() {
} }
} }
static Control *make_help_bit(const String &p_text, bool p_property) { static Control *make_help_bit(const String &p_text, const String &p_warning, const Color &p_warn_color, bool p_property) {
EditorHelpBit *help_bit = memnew(EditorHelpBit); EditorHelpBit *help_bit = memnew(EditorHelpBit);
help_bit->get_rich_text()->set_custom_minimum_size(Size2(360 * EDSCALE, 1)); help_bit->get_rich_text()->set_custom_minimum_size(Size2(360 * EDSCALE, 1));
@ -923,13 +929,23 @@ static Control *make_help_bit(const String &p_text, bool p_property) {
} else { } else {
text += "\n[i]" + TTR("No description.") + "[/i]"; text += "\n[i]" + TTR("No description.") + "[/i]";
} }
if (!p_warning.is_empty()) {
text += "\n[b][color=" + p_warn_color.to_html(false) + "]" + p_warning + "[/color][/b]";
}
help_bit->set_text(text); help_bit->set_text(text);
return help_bit; return help_bit;
} }
Control *EditorProperty::make_custom_tooltip(const String &p_text) const { Control *EditorProperty::make_custom_tooltip(const String &p_text) const {
return make_help_bit(p_text, true); String warn;
Color warn_color;
if (object->has_method("_get_property_warning")) {
warn = object->call("_get_property_warning", property);
warn_color = get_theme_color(SNAME("warning_color"));
}
return make_help_bit(p_text, warn, warn_color, true);
} }
void EditorProperty::menu_option(int p_option) { void EditorProperty::menu_option(int p_option) {
@ -1158,7 +1174,7 @@ void EditorInspectorCategory::_notification(int p_what) {
} }
Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) const { Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) const {
return make_help_bit(p_text, false); return make_help_bit(p_text, String(), Color(), false);
} }
Size2 EditorInspectorCategory::get_minimum_size() const { Size2 EditorInspectorCategory::get_minimum_size() const {

View file

@ -79,6 +79,7 @@ private:
bool checkable = false; bool checkable = false;
bool checked = false; bool checked = false;
bool draw_warning = false; bool draw_warning = false;
bool draw_prop_warning = false;
bool keying = false; bool keying = false;
bool deletable = false; bool deletable = false;

View file

@ -125,6 +125,8 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["ao"] = "AO"; capitalize_string_remaps["ao"] = "AO";
capitalize_string_remaps["api"] = "API"; capitalize_string_remaps["api"] = "API";
capitalize_string_remaps["apk"] = "APK"; capitalize_string_remaps["apk"] = "APK";
capitalize_string_remaps["arm32"] = "arm32";
capitalize_string_remaps["arm64"] = "arm64";
capitalize_string_remaps["arm64-v8a"] = "arm64-v8a"; capitalize_string_remaps["arm64-v8a"] = "arm64-v8a";
capitalize_string_remaps["armeabi-v7a"] = "armeabi-v7a"; capitalize_string_remaps["armeabi-v7a"] = "armeabi-v7a";
capitalize_string_remaps["arvr"] = "ARVR"; capitalize_string_remaps["arvr"] = "ARVR";
@ -221,6 +223,8 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["pck"] = "PCK"; capitalize_string_remaps["pck"] = "PCK";
capitalize_string_remaps["png"] = "PNG"; capitalize_string_remaps["png"] = "PNG";
capitalize_string_remaps["po2"] = "(Power of 2)"; // Unit. capitalize_string_remaps["po2"] = "(Power of 2)"; // Unit.
capitalize_string_remaps["ppc32"] = "ppc32";
capitalize_string_remaps["ppc64"] = "ppc64";
capitalize_string_remaps["pvrtc"] = "PVRTC"; capitalize_string_remaps["pvrtc"] = "PVRTC";
capitalize_string_remaps["pvs"] = "PVS"; capitalize_string_remaps["pvs"] = "PVS";
capitalize_string_remaps["rcedit"] = "rcedit"; capitalize_string_remaps["rcedit"] = "rcedit";
@ -229,6 +233,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["rid"] = "RID"; capitalize_string_remaps["rid"] = "RID";
capitalize_string_remaps["rmb"] = "RMB"; capitalize_string_remaps["rmb"] = "RMB";
capitalize_string_remaps["rpc"] = "RPC"; capitalize_string_remaps["rpc"] = "RPC";
capitalize_string_remaps["rv64"] = "rv64";
capitalize_string_remaps["s3tc"] = "S3TC"; capitalize_string_remaps["s3tc"] = "S3TC";
capitalize_string_remaps["scp"] = "SCP"; capitalize_string_remaps["scp"] = "SCP";
capitalize_string_remaps["sdf"] = "SDF"; capitalize_string_remaps["sdf"] = "SDF";
@ -274,6 +279,8 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["wine"] = "wine"; capitalize_string_remaps["wine"] = "wine";
capitalize_string_remaps["wifi"] = "Wi-Fi"; capitalize_string_remaps["wifi"] = "Wi-Fi";
capitalize_string_remaps["x86"] = "x86"; capitalize_string_remaps["x86"] = "x86";
capitalize_string_remaps["x86_32"] = "x86_32";
capitalize_string_remaps["x86_64"] = "x86_64";
capitalize_string_remaps["xr"] = "XR"; capitalize_string_remaps["xr"] = "XR";
capitalize_string_remaps["xray"] = "X-Ray"; capitalize_string_remaps["xray"] = "X-Ray";
capitalize_string_remaps["xy"] = "XY"; capitalize_string_remaps["xy"] = "XY";

View file

@ -143,11 +143,13 @@ public:
PropertyInfo option; PropertyInfo option;
Variant default_value; Variant default_value;
bool update_visibility = false; bool update_visibility = false;
bool required = false;
ExportOption(const PropertyInfo &p_info, const Variant &p_default, bool p_update_visibility = false) : ExportOption(const PropertyInfo &p_info, const Variant &p_default, bool p_update_visibility = false, bool p_required = false) :
option(p_info), option(p_info),
default_value(p_default), default_value(p_default),
update_visibility(p_update_visibility) { update_visibility(p_update_visibility),
required(p_required) {
} }
ExportOption() {} ExportOption() {}
}; };
@ -196,9 +198,10 @@ public:
virtual bool fill_log_messages(RichTextLabel *p_log, Error p_err); virtual bool fill_log_messages(RichTextLabel *p_log, Error p_err);
virtual void get_export_options(List<ExportOption> *r_options) = 0; virtual void get_export_options(List<ExportOption> *r_options) const = 0;
virtual bool should_update_export_options() { return false; } virtual bool should_update_export_options() { return false; }
virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const { return true; } virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const { return true; }
virtual String get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const { return String(); }
virtual String get_os_name() const = 0; virtual String get_os_name() const = 0;
virtual String get_name() const = 0; virtual String get_name() const = 0;

View file

@ -50,7 +50,7 @@ void EditorExportPlatformPC::get_preset_features(const Ref<EditorExportPreset> &
r_features->push_back(p_preset->get("binary_format/architecture")); r_features->push_back(p_preset->get("binary_format/architecture"));
} }
void EditorExportPlatformPC::get_export_options(List<ExportOption> *r_options) { void EditorExportPlatformPC::get_export_options(List<ExportOption> *r_options) const {
String ext_filter = (get_os_name() == "Windows") ? "*.exe" : ""; String ext_filter = (get_os_name() == "Windows") ? "*.exe" : "";
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, ext_filter), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, ext_filter), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, ext_filter), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, ext_filter), ""));

View file

@ -46,7 +46,7 @@ private:
public: public:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override; virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
virtual void get_export_options(List<ExportOption> *r_options) override; virtual void get_export_options(List<ExportOption> *r_options) const override;
virtual String get_name() const override; virtual String get_name() const override;
virtual String get_os_name() const override; virtual String get_os_name() const override;

View file

@ -52,9 +52,17 @@ bool EditorExportPreset::_get(const StringName &p_name, Variant &r_ret) const {
return false; return false;
} }
void EditorExportPreset::_bind_methods() {
ClassDB::bind_method(D_METHOD("_get_property_warning", "name"), &EditorExportPreset::_get_property_warning);
}
String EditorExportPreset::_get_property_warning(const StringName &p_name) const {
return platform->get_export_option_warning(this, p_name);
}
void EditorExportPreset::_get_property_list(List<PropertyInfo> *p_list) const { void EditorExportPreset::_get_property_list(List<PropertyInfo> *p_list) const {
for (const PropertyInfo &E : properties) { for (const PropertyInfo &E : properties) {
if (platform->get_export_option_visibility(this, E.name, values)) { if (platform->get_export_option_visibility(this, E.name)) {
p_list->push_back(E); p_list->push_back(E);
} }
} }

View file

@ -90,6 +90,10 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const; bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const; void _get_property_list(List<PropertyInfo> *p_list) const;
String _get_property_warning(const StringName &p_name) const;
static void _bind_methods();
public: public:
Ref<EditorExportPlatform> get_platform() const; Ref<EditorExportPlatform> get_platform() const;

View file

@ -241,6 +241,7 @@ void ProjectExportDialog::_edit_preset(int p_index) {
export_path->update_property(); export_path->update_property();
runnable->set_disabled(false); runnable->set_disabled(false);
runnable->set_pressed(current->is_runnable()); runnable->set_pressed(current->is_runnable());
parameters->set_object_class(current->get_platform()->get_class_name());
parameters->edit(current.ptr()); parameters->edit(current.ptr());
export_filter->select(current->get_export_filter()); export_filter->select(current->get_export_filter());
@ -1161,6 +1162,7 @@ ProjectExportDialog::ProjectExportDialog() {
parameters->set_name(TTR("Options")); parameters->set_name(TTR("Options"));
parameters->set_v_size_flags(Control::SIZE_EXPAND_FILL); parameters->set_v_size_flags(Control::SIZE_EXPAND_FILL);
parameters->set_property_name_style(EditorPropertyNameProcessor::get_settings_style()); parameters->set_property_name_style(EditorPropertyNameProcessor::get_settings_style());
parameters->set_use_doc_hints(true);
parameters->connect("property_edited", callable_mp(this, &ProjectExportDialog::_update_parameters)); parameters->connect("property_edited", callable_mp(this, &ProjectExportDialog::_update_parameters));
EditorExport::get_singleton()->connect("export_presets_updated", callable_mp(this, &ProjectExportDialog::_force_update_current_preset_parameters)); EditorExport::get_singleton()->connect("export_presets_updated", callable_mp(this, &ProjectExportDialog::_force_update_current_preset_parameters));

View file

@ -44,6 +44,7 @@
#include "editor/editor_settings.h" #include "editor/editor_settings.h"
#include "editor/editor_translation_parser.h" #include "editor/editor_translation_parser.h"
#include "editor/editor_undo_redo_manager.h" #include "editor/editor_undo_redo_manager.h"
#include "editor/export/editor_export_platform_pc.h"
#include "editor/filesystem_dock.h" #include "editor/filesystem_dock.h"
#include "editor/gui/editor_file_dialog.h" #include "editor/gui/editor_file_dialog.h"
#include "editor/gui/editor_spin_slider.h" #include "editor/gui/editor_spin_slider.h"
@ -108,6 +109,7 @@
#include "editor/plugins/version_control_editor_plugin.h" #include "editor/plugins/version_control_editor_plugin.h"
#include "editor/plugins/visual_shader_editor_plugin.h" #include "editor/plugins/visual_shader_editor_plugin.h"
#include "editor/plugins/voxel_gi_editor_plugin.h" #include "editor/plugins/voxel_gi_editor_plugin.h"
#include "editor/register_exporters.h"
void register_editor_types() { void register_editor_types() {
ResourceLoader::set_timestamp_on_load(true); ResourceLoader::set_timestamp_on_load(true);
@ -134,6 +136,8 @@ void register_editor_types() {
GDREGISTER_ABSTRACT_CLASS(EditorInterface); GDREGISTER_ABSTRACT_CLASS(EditorInterface);
GDREGISTER_CLASS(EditorExportPlugin); GDREGISTER_CLASS(EditorExportPlugin);
GDREGISTER_ABSTRACT_CLASS(EditorExportPlatform); GDREGISTER_ABSTRACT_CLASS(EditorExportPlatform);
GDREGISTER_ABSTRACT_CLASS(EditorExportPlatformPC);
register_exporter_types();
GDREGISTER_CLASS(EditorResourceConversionPlugin); GDREGISTER_CLASS(EditorResourceConversionPlugin);
GDREGISTER_CLASS(EditorSceneFormatImporter); GDREGISTER_CLASS(EditorSceneFormatImporter);
GDREGISTER_CLASS(EditorScenePostImportPlugin); GDREGISTER_CLASS(EditorScenePostImportPlugin);

View file

@ -31,6 +31,7 @@
#ifndef REGISTER_EXPORTERS_H #ifndef REGISTER_EXPORTERS_H
#define REGISTER_EXPORTERS_H #define REGISTER_EXPORTERS_H
void register_exporter_types();
void register_exporters(); void register_exporters();
#endif // REGISTER_EXPORTERS_H #endif // REGISTER_EXPORTERS_H

View file

@ -24,6 +24,20 @@
<string>$signature</string> <string>$signature</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$version</string> <string>$version</string>
<key>DTPlatformBuild</key>
<string>$platfbuild</string>
<key>DTPlatformName</key>
<string>macosx</string>
<key>DTPlatformVersion</key>
<string>$sdkver</string>
<key>DTSDKBuild</key>
<string>$sdkbuild</string>
<key>DTSDKName</key>
<string>$sdkname</string>
<key>DTXcode</key>
<string>$xcodever</string>
<key>DTXcodeBuild</key>
<string>$xcodebuild</string>
$usage_descriptions $usage_descriptions
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>$copyright</string> <string>$copyright</string>
@ -36,11 +50,11 @@ $usage_descriptions
<key>LSApplicationCategoryType</key> <key>LSApplicationCategoryType</key>
<string>public.app-category.$app_category</string> <string>public.app-category.$app_category</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>10.12</string> <string>$min_version</string>
<key>LSMinimumSystemVersionByArchitecture</key> <key>LSMinimumSystemVersionByArchitecture</key>
<dict> <dict>
<key>x86_64</key> <key>x86_64</key>
<string>10.12</string> <string>$min_version</string>
</dict> </dict>
<key>NSHighResolutionCapable</key> <key>NSHighResolutionCapable</key>
$highres $highres

View file

@ -35,6 +35,10 @@
#include "editor/export/editor_export.h" #include "editor/export/editor_export.h"
#include "export_plugin.h" #include "export_plugin.h"
void register_android_exporter_types() {
GDREGISTER_VIRTUAL_CLASS(EditorExportPlatformAndroid);
}
void register_android_exporter() { void register_android_exporter() {
#ifndef ANDROID_ENABLED #ifndef ANDROID_ENABLED
EDITOR_DEF("export/android/android_sdk_path", ""); EDITOR_DEF("export/android/android_sdk_path", "");

View file

@ -31,6 +31,7 @@
#ifndef ANDROID_EXPORT_H #ifndef ANDROID_EXPORT_H
#define ANDROID_EXPORT_H #define ANDROID_EXPORT_H
void register_android_exporter_types();
void register_android_exporter(); void register_android_exporter();
#endif // ANDROID_EXPORT_H #endif // ANDROID_EXPORT_H

View file

@ -1703,16 +1703,109 @@ void EditorExportPlatformAndroid::get_preset_features(const Ref<EditorExportPres
} }
} }
void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_options) { String EditorExportPlatformAndroid::get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const {
if (p_preset) {
if (p_name == ("apk_expansion/public_key")) {
bool apk_expansion = p_preset->get("apk_expansion/enable");
String apk_expansion_pkey = p_preset->get("apk_expansion/public_key");
if (apk_expansion && apk_expansion_pkey.is_empty()) {
return TTR("Invalid public key for APK expansion.");
}
} else if (p_name == "package/unique_name") {
String pn = p_preset->get("package/unique_name");
String pn_err;
if (!is_package_name_valid(pn, &pn_err)) {
return TTR("Invalid package name:") + " " + pn_err;
}
} else if (p_name == "gradle_build/use_gradle_build") {
bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build");
String enabled_plugins_names = PluginConfigAndroid::get_plugins_names(get_enabled_plugins(Ref<EditorExportPreset>(p_preset)));
if (!enabled_plugins_names.is_empty() && !gradle_build_enabled) {
return TTR("\"Use Gradle Build\" must be enabled to use the plugins.");
}
} else if (p_name == "xr_features/xr_mode") {
bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build");
int xr_mode_index = p_preset->get("xr_features/xr_mode");
if (xr_mode_index == XR_MODE_OPENXR && !gradle_build_enabled) {
return TTR("OpenXR requires \"Use Gradle Build\" to be enabled");
}
} else if (p_name == "xr_features/hand_tracking") {
int xr_mode_index = p_preset->get("xr_features/xr_mode");
int hand_tracking = p_preset->get("xr_features/hand_tracking");
if (xr_mode_index != XR_MODE_OPENXR) {
if (hand_tracking > XR_HAND_TRACKING_NONE) {
return TTR("\"Hand Tracking\" is only valid when \"XR Mode\" is \"OpenXR\".");
}
}
} else if (p_name == "xr_features/passthrough") {
int xr_mode_index = p_preset->get("xr_features/xr_mode");
int passthrough_mode = p_preset->get("xr_features/passthrough");
if (xr_mode_index != XR_MODE_OPENXR) {
if (passthrough_mode > XR_PASSTHROUGH_NONE) {
return TTR("\"Passthrough\" is only valid when \"XR Mode\" is \"OpenXR\".");
}
}
} else if (p_name == "gradle_build/export_format") {
bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build");
if (int(p_preset->get("gradle_build/export_format")) == EXPORT_FORMAT_AAB && !gradle_build_enabled) {
return TTR("\"Export AAB\" is only valid when \"Use Gradle Build\" is enabled.");
}
} else if (p_name == "gradle_build/min_sdk") {
String min_sdk_str = p_preset->get("gradle_build/min_sdk");
int min_sdk_int = VULKAN_MIN_SDK_VERSION;
bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build");
if (!min_sdk_str.is_empty()) { // Empty means no override, nothing to do.
if (!gradle_build_enabled) {
return TTR("\"Min SDK\" can only be overridden when \"Use Gradle Build\" is enabled.");
}
if (!min_sdk_str.is_valid_int()) {
return vformat(TTR("\"Min SDK\" should be a valid integer, but got \"%s\" which is invalid."), min_sdk_str);
} else {
min_sdk_int = min_sdk_str.to_int();
if (min_sdk_int < OPENGL_MIN_SDK_VERSION) {
return vformat(TTR("\"Min SDK\" cannot be lower than %d, which is the version needed by the Godot library."), OPENGL_MIN_SDK_VERSION);
}
}
}
} else if (p_name == "gradle_build/target_sdk") {
String target_sdk_str = p_preset->get("gradle_build/target_sdk");
int target_sdk_int = DEFAULT_TARGET_SDK_VERSION;
String min_sdk_str = p_preset->get("gradle_build/min_sdk");
int min_sdk_int = VULKAN_MIN_SDK_VERSION;
if (min_sdk_str.is_valid_int()) {
min_sdk_int = min_sdk_str.to_int();
}
bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build");
if (!target_sdk_str.is_empty()) { // Empty means no override, nothing to do.
if (!gradle_build_enabled) {
return TTR("\"Target SDK\" can only be overridden when \"Use Gradle Build\" is enabled.");
}
if (!target_sdk_str.is_valid_int()) {
return vformat(TTR("\"Target SDK\" should be a valid integer, but got \"%s\" which is invalid."), target_sdk_str);
} else {
target_sdk_int = target_sdk_str.to_int();
if (target_sdk_int < min_sdk_int) {
return TTR("\"Target SDK\" version must be greater or equal to \"Min SDK\" version.");
}
}
}
}
}
return String();
}
void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_options) const {
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "gradle_build/use_gradle_build"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "gradle_build/use_gradle_build"), false, false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "gradle_build/export_format", PROPERTY_HINT_ENUM, "Export APK,Export AAB"), EXPORT_FORMAT_APK)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "gradle_build/export_format", PROPERTY_HINT_ENUM, "Export APK,Export AAB"), EXPORT_FORMAT_APK, false, true));
// Using String instead of int to default to an empty string (no override) with placeholder for instructions (see GH-62465). // Using String instead of int to default to an empty string (no override) with placeholder for instructions (see GH-62465).
// This implies doing validation that the string is a proper int. // This implies doing validation that the string is a proper int.
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "gradle_build/min_sdk", PROPERTY_HINT_PLACEHOLDER_TEXT, vformat("%d (default)", VULKAN_MIN_SDK_VERSION)), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "gradle_build/min_sdk", PROPERTY_HINT_PLACEHOLDER_TEXT, vformat("%d (default)", VULKAN_MIN_SDK_VERSION)), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "gradle_build/target_sdk", PROPERTY_HINT_PLACEHOLDER_TEXT, vformat("%d (default)", DEFAULT_TARGET_SDK_VERSION)), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "gradle_build/target_sdk", PROPERTY_HINT_PLACEHOLDER_TEXT, vformat("%d (default)", DEFAULT_TARGET_SDK_VERSION)), "", false, true));
Vector<PluginConfigAndroid> plugins_configs = get_plugins(); Vector<PluginConfigAndroid> plugins_configs = get_plugins();
for (int i = 0; i < plugins_configs.size(); i++) { for (int i = 0; i < plugins_configs.size(); i++) {
@ -1742,7 +1835,7 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "ext.domain.name"), "org.godotengine.$genname")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "ext.domain.name"), "org.godotengine.$genname", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name [default if blank]"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name [default if blank]"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/signed"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/signed"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "package/app_category", PROPERTY_HINT_ENUM, "Accessibility,Audio,Game,Image,Maps,News,Productivity,Social,Video"), APP_CATEGORY_GAME)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "package/app_category", PROPERTY_HINT_ENUM, "Accessibility,Audio,Game,Image,Maps,News,Productivity,Social,Video"), APP_CATEGORY_GAME));
@ -1755,10 +1848,10 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/opengl_debug"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/opengl_debug"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/xr_mode", PROPERTY_HINT_ENUM, "Regular,OpenXR"), XR_MODE_REGULAR)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/xr_mode", PROPERTY_HINT_ENUM, "Regular,OpenXR"), XR_MODE_REGULAR, false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/hand_tracking", PROPERTY_HINT_ENUM, "None,Optional,Required"), XR_HAND_TRACKING_NONE)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/hand_tracking", PROPERTY_HINT_ENUM, "None,Optional,Required"), XR_HAND_TRACKING_NONE, false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/hand_tracking_frequency", PROPERTY_HINT_ENUM, "Low,High"), XR_HAND_TRACKING_FREQUENCY_LOW)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/hand_tracking_frequency", PROPERTY_HINT_ENUM, "Low,High"), XR_HAND_TRACKING_FREQUENCY_LOW));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/passthrough", PROPERTY_HINT_ENUM, "None,Optional,Required"), XR_PASSTHROUGH_NONE)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/passthrough", PROPERTY_HINT_ENUM, "None,Optional,Required"), XR_PASSTHROUGH_NONE, false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/immersive_mode"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/immersive_mode"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_small"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_small"), true));
@ -1770,9 +1863,9 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "apk_expansion/enable"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "apk_expansion/enable"), false, false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "apk_expansion/SALT"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "apk_expansion/SALT"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "apk_expansion/public_key", PROPERTY_HINT_MULTILINE_TEXT), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "apk_expansion/public_key", PROPERTY_HINT_MULTILINE_TEXT), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "permissions/custom_permissions"), PackedStringArray())); r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "permissions/custom_permissions"), PackedStringArray()));
@ -2272,111 +2365,39 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const { bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
String err; String err;
bool valid = true; bool valid = true;
const bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build");
// Validate the project configuration. List<ExportOption> options;
bool apk_expansion = p_preset->get("apk_expansion/enable"); get_export_options(&options);
for (const EditorExportPlatform::ExportOption &E : options) {
if (apk_expansion) { if (get_export_option_visibility(p_preset.ptr(), E.option.name)) {
String apk_expansion_pkey = p_preset->get("apk_expansion/public_key"); String warn = get_export_option_warning(p_preset.ptr(), E.option.name);
if (!warn.is_empty()) {
if (apk_expansion_pkey.is_empty()) { err += warn + "\n";
valid = false; if (E.required) {
valid = false;
err += TTR("Invalid public key for APK expansion.") + "\n"; }
}
} }
} }
String pn = p_preset->get("package/unique_name");
String pn_err;
if (!is_package_name_valid(pn, &pn_err)) {
valid = false;
err += TTR("Invalid package name:") + " " + pn_err + "\n";
}
String etc_error = test_etc2(); String etc_error = test_etc2();
if (!etc_error.is_empty()) { if (!etc_error.is_empty()) {
valid = false; valid = false;
err += etc_error; err += etc_error;
} }
// Ensure that `Use Gradle Build` is enabled if a plugin is selected.
String enabled_plugins_names = PluginConfigAndroid::get_plugins_names(get_enabled_plugins(p_preset));
if (!enabled_plugins_names.is_empty() && !gradle_build_enabled) {
valid = false;
err += TTR("\"Use Gradle Build\" must be enabled to use the plugins.");
err += "\n";
}
// Validate the Xr features are properly populated
int xr_mode_index = p_preset->get("xr_features/xr_mode");
int hand_tracking = p_preset->get("xr_features/hand_tracking");
int passthrough_mode = p_preset->get("xr_features/passthrough");
if (xr_mode_index == XR_MODE_OPENXR && !gradle_build_enabled) {
valid = false;
err += TTR("OpenXR requires \"Use Gradle Build\" to be enabled");
err += "\n";
}
if (xr_mode_index != XR_MODE_OPENXR) {
if (hand_tracking > XR_HAND_TRACKING_NONE) {
valid = false;
err += TTR("\"Hand Tracking\" is only valid when \"XR Mode\" is \"OpenXR\".");
err += "\n";
}
if (passthrough_mode > XR_PASSTHROUGH_NONE) {
valid = false;
err += TTR("\"Passthrough\" is only valid when \"XR Mode\" is \"OpenXR\".");
err += "\n";
}
}
if (int(p_preset->get("gradle_build/export_format")) == EXPORT_FORMAT_AAB &&
!gradle_build_enabled) {
valid = false;
err += TTR("\"Export AAB\" is only valid when \"Use Gradle Build\" is enabled.");
err += "\n";
}
// Check the min sdk version.
String min_sdk_str = p_preset->get("gradle_build/min_sdk"); String min_sdk_str = p_preset->get("gradle_build/min_sdk");
int min_sdk_int = VULKAN_MIN_SDK_VERSION; int min_sdk_int = VULKAN_MIN_SDK_VERSION;
if (!min_sdk_str.is_empty()) { // Empty means no override, nothing to do. if (!min_sdk_str.is_empty()) { // Empty means no override, nothing to do.
if (!gradle_build_enabled) { if (min_sdk_str.is_valid_int()) {
valid = false;
err += TTR("\"Min SDK\" can only be overridden when \"Use Gradle Build\" is enabled.");
err += "\n";
}
if (!min_sdk_str.is_valid_int()) {
valid = false;
err += vformat(TTR("\"Min SDK\" should be a valid integer, but got \"%s\" which is invalid."), min_sdk_str);
err += "\n";
} else {
min_sdk_int = min_sdk_str.to_int(); min_sdk_int = min_sdk_str.to_int();
if (min_sdk_int < OPENGL_MIN_SDK_VERSION) {
valid = false;
err += vformat(TTR("\"Min SDK\" cannot be lower than %d, which is the version needed by the Godot library."), OPENGL_MIN_SDK_VERSION);
err += "\n";
}
} }
} }
// Check the target sdk version.
String target_sdk_str = p_preset->get("gradle_build/target_sdk"); String target_sdk_str = p_preset->get("gradle_build/target_sdk");
int target_sdk_int = DEFAULT_TARGET_SDK_VERSION; int target_sdk_int = DEFAULT_TARGET_SDK_VERSION;
if (!target_sdk_str.is_empty()) { // Empty means no override, nothing to do. if (!target_sdk_str.is_empty()) { // Empty means no override, nothing to do.
if (!gradle_build_enabled) { if (target_sdk_str.is_valid_int()) {
valid = false;
err += TTR("\"Target SDK\" can only be overridden when \"Use Gradle Build\" is enabled.");
err += "\n";
}
if (!target_sdk_str.is_valid_int()) {
valid = false;
err += vformat(TTR("\"Target SDK\" should be a valid integer, but got \"%s\" which is invalid."), target_sdk_str);
err += "\n";
} else {
target_sdk_int = target_sdk_str.to_int(); target_sdk_int = target_sdk_str.to_int();
if (target_sdk_int > DEFAULT_TARGET_SDK_VERSION) { if (target_sdk_int > DEFAULT_TARGET_SDK_VERSION) {
// Warning only, so don't override `valid`. // Warning only, so don't override `valid`.
@ -2386,18 +2407,13 @@ bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<Edit
} }
} }
if (target_sdk_int < min_sdk_int) {
valid = false;
err += TTR("\"Target SDK\" version must be greater or equal to \"Min SDK\" version.");
err += "\n";
}
String current_renderer = GLOBAL_GET("rendering/renderer/rendering_method.mobile"); String current_renderer = GLOBAL_GET("rendering/renderer/rendering_method.mobile");
if (current_renderer == "forward_plus") { if (current_renderer == "forward_plus") {
// Warning only, so don't override `valid`. // Warning only, so don't override `valid`.
err += vformat(TTR("The \"%s\" renderer is designed for Desktop devices, and is not suitable for Android devices."), current_renderer); err += vformat(TTR("The \"%s\" renderer is designed for Desktop devices, and is not suitable for Android devices."), current_renderer);
err += "\n"; err += "\n";
} }
if (_uses_vulkan() && min_sdk_int < VULKAN_MIN_SDK_VERSION) { if (_uses_vulkan() && min_sdk_int < VULKAN_MIN_SDK_VERSION) {
// Warning only, so don't override `valid`. // Warning only, so don't override `valid`.
err += vformat(TTR("\"Min SDK\" should be greater or equal to %d for the \"%s\" renderer."), VULKAN_MIN_SDK_VERSION, current_renderer); err += vformat(TTR("\"Min SDK\" should be greater or equal to %d for the \"%s\" renderer."), VULKAN_MIN_SDK_VERSION, current_renderer);
@ -3266,23 +3282,25 @@ void EditorExportPlatformAndroid::resolve_platform_feature_priorities(const Ref<
} }
EditorExportPlatformAndroid::EditorExportPlatformAndroid() { EditorExportPlatformAndroid::EditorExportPlatformAndroid() {
if (EditorNode::get_singleton()) {
#ifdef MODULE_SVG_ENABLED #ifdef MODULE_SVG_ENABLED
Ref<Image> img = memnew(Image); Ref<Image> img = memnew(Image);
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
ImageLoaderSVG img_loader; ImageLoaderSVG img_loader;
img_loader.create_image_from_string(img, _android_logo_svg, EDSCALE, upsample, false); img_loader.create_image_from_string(img, _android_logo_svg, EDSCALE, upsample, false);
logo = ImageTexture::create_from_image(img); logo = ImageTexture::create_from_image(img);
img_loader.create_image_from_string(img, _android_run_icon_svg, EDSCALE, upsample, false); img_loader.create_image_from_string(img, _android_run_icon_svg, EDSCALE, upsample, false);
run_icon = ImageTexture::create_from_image(img); run_icon = ImageTexture::create_from_image(img);
#endif #endif
devices_changed.set(); devices_changed.set();
plugins_changed.set(); plugins_changed.set();
#ifndef ANDROID_ENABLED #ifndef ANDROID_ENABLED
check_for_changes_thread.start(_check_for_changes_poll_thread, this); check_for_changes_thread.start(_check_for_changes_poll_thread, this);
#endif #endif
}
} }
EditorExportPlatformAndroid::~EditorExportPlatformAndroid() { EditorExportPlatformAndroid::~EditorExportPlatformAndroid() {

View file

@ -72,10 +72,10 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
EditorProgress *ep = nullptr; EditorProgress *ep = nullptr;
}; };
Vector<PluginConfigAndroid> plugins; mutable Vector<PluginConfigAndroid> plugins;
String last_plugin_names; String last_plugin_names;
uint64_t last_gradle_build_time = 0; uint64_t last_gradle_build_time = 0;
SafeFlag plugins_changed; mutable SafeFlag plugins_changed;
Mutex plugins_lock; Mutex plugins_lock;
Vector<Device> devices; Vector<Device> devices;
SafeFlag devices_changed; SafeFlag devices_changed;
@ -180,7 +180,9 @@ public:
public: public:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override; virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
virtual void get_export_options(List<ExportOption> *r_options) override; virtual void get_export_options(List<ExportOption> *r_options) const override;
virtual String get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const override;
virtual String get_name() const override; virtual String get_name() const override;

View file

@ -33,6 +33,10 @@
#include "editor/export/editor_export.h" #include "editor/export/editor_export.h"
#include "export_plugin.h" #include "export_plugin.h"
void register_ios_exporter_types() {
GDREGISTER_VIRTUAL_CLASS(EditorExportPlatformIOS);
}
void register_ios_exporter() { void register_ios_exporter() {
Ref<EditorExportPlatformIOS> platform; Ref<EditorExportPlatformIOS> platform;
platform.instantiate(); platform.instantiate();

View file

@ -31,6 +31,7 @@
#ifndef IOS_EXPORT_H #ifndef IOS_EXPORT_H
#define IOS_EXPORT_H #define IOS_EXPORT_H
void register_ios_exporter_types();
void register_ios_exporter(); void register_ios_exporter();
#endif // IOS_EXPORT_H #endif // IOS_EXPORT_H

View file

@ -120,7 +120,35 @@ static const LoadingScreenInfo loading_screen_infos[] = {
{ PNAME("portrait_launch_screens/iphone_1242x2208"), "Default-Portrait-736h@3x.png", 1242, 2208, true } { PNAME("portrait_launch_screens/iphone_1242x2208"), "Default-Portrait-736h@3x.png", 1242, 2208, true }
}; };
void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) { 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") {
String team_id = p_preset->get("application/app_store_team_id");
if (team_id.is_empty()) {
return TTR("App Store Team ID not specified.") + "\n";
}
} else if (p_name == "application/bundle_identifier") {
String identifier = p_preset->get("application/bundle_identifier");
String pn_err;
if (!is_package_name_valid(identifier, &pn_err)) {
return TTR("Invalid Identifier:") + " " + pn_err;
}
}
}
return String();
}
bool EditorExportPlatformIOS::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const {
if (p_preset) {
bool sb = p_preset->get("storyboard/use_launch_screen_storyboard");
if (!sb && p_option != "storyboard/use_launch_screen_storyboard" && p_option.begins_with("storyboard/")) {
return false;
}
}
return true;
}
void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) const {
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
@ -129,7 +157,7 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("architectures"), architectures[i].name)), architectures[i].is_default)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, vformat("%s/%s", PNAME("architectures"), architectures[i].name)), architectures[i].is_default));
} }
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_store_team_id"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_store_team_id"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/provisioning_profile_uuid_debug"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/provisioning_profile_uuid_debug"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/code_sign_identity_debug", PROPERTY_HINT_PLACEHOLDER_TEXT, "iPhone Developer"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/code_sign_identity_debug", PROPERTY_HINT_PLACEHOLDER_TEXT, "iPhone Developer"), ""));
@ -140,7 +168,7 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/targeted_device_family", PROPERTY_HINT_ENUM, "iPhone,iPad,iPhone & iPad"), 2)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/targeted_device_family", PROPERTY_HINT_ENUM, "iPhone,iPad,iPhone & iPad"), 2));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0"));
@ -197,7 +225,7 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, icon_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, icon_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), ""));
} }
} }
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_launch_screen_storyboard"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_launch_screen_storyboard"), false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "storyboard/image_scale_mode", PROPERTY_HINT_ENUM, "Same as Logo,Center,Scale to Fit,Scale to Fill,Scale"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "storyboard/image_scale_mode", PROPERTY_HINT_ENUM, "Same as Logo,Center,Scale to Fit,Scale to Fill,Scale"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@3x", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@3x", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), ""));
@ -1907,17 +1935,18 @@ bool EditorExportPlatformIOS::has_valid_project_configuration(const Ref<EditorEx
// Validate the project configuration. // Validate the project configuration.
String team_id = p_preset->get("application/app_store_team_id"); List<ExportOption> options;
if (team_id.length() == 0) { get_export_options(&options);
err += TTR("App Store Team ID not specified - cannot configure the project.") + "\n"; for (const EditorExportPlatform::ExportOption &E : options) {
valid = false; if (get_export_option_visibility(p_preset.ptr(), E.option.name)) {
} String warn = get_export_option_warning(p_preset.ptr(), E.option.name);
if (!warn.is_empty()) {
String identifier = p_preset->get("application/bundle_identifier"); err += warn + "\n";
String pn_err; if (E.required) {
if (!is_package_name_valid(identifier, &pn_err)) { valid = false;
err += TTR("Invalid Identifier:") + " " + pn_err + "\n"; }
valid = false; }
}
} }
const String etc_error = test_etc2(); const String etc_error = test_etc2();
@ -1934,19 +1963,21 @@ bool EditorExportPlatformIOS::has_valid_project_configuration(const Ref<EditorEx
} }
EditorExportPlatformIOS::EditorExportPlatformIOS() { EditorExportPlatformIOS::EditorExportPlatformIOS() {
if (EditorNode::get_singleton()) {
#ifdef MODULE_SVG_ENABLED #ifdef MODULE_SVG_ENABLED
Ref<Image> img = memnew(Image); Ref<Image> img = memnew(Image);
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
ImageLoaderSVG img_loader; ImageLoaderSVG img_loader;
img_loader.create_image_from_string(img, _ios_logo_svg, EDSCALE, upsample, false); img_loader.create_image_from_string(img, _ios_logo_svg, EDSCALE, upsample, false);
logo = ImageTexture::create_from_image(img); logo = ImageTexture::create_from_image(img);
#endif #endif
plugins_changed.set(); plugins_changed.set();
#ifndef ANDROID_ENABLED #ifndef ANDROID_ENABLED
check_for_changes_thread.start(_check_for_changes_poll_thread, this); check_for_changes_thread.start(_check_for_changes_poll_thread, this);
#endif #endif
}
} }
EditorExportPlatformIOS::~EditorExportPlatformIOS() { EditorExportPlatformIOS::~EditorExportPlatformIOS() {

View file

@ -55,13 +55,13 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
Ref<ImageTexture> logo; Ref<ImageTexture> logo;
// Plugins // Plugins
SafeFlag plugins_changed; mutable SafeFlag plugins_changed;
#ifndef ANDROID_ENABLED #ifndef ANDROID_ENABLED
Thread check_for_changes_thread; Thread check_for_changes_thread;
SafeFlag quit_request; SafeFlag quit_request;
#endif #endif
Mutex plugins_lock; Mutex plugins_lock;
Vector<PluginConfigIOS> plugins; mutable Vector<PluginConfigIOS> plugins;
typedef Error (*FileHandler)(String p_file, void *p_userdata); typedef Error (*FileHandler)(String p_file, void *p_userdata);
static Error _walk_dir_recursive(Ref<DirAccess> &p_da, FileHandler p_handler, void *p_userdata); static Error _walk_dir_recursive(Ref<DirAccess> &p_da, FileHandler p_handler, void *p_userdata);
@ -178,7 +178,9 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
protected: protected:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override; virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
virtual void get_export_options(List<ExportOption> *r_options) override; virtual void get_export_options(List<ExportOption> *r_options) const override;
virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const override;
virtual String get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const override;
public: public:
virtual String get_name() const override { return "iOS"; } virtual String get_name() const override { return "iOS"; }

View file

@ -33,6 +33,10 @@
#include "editor/export/editor_export.h" #include "editor/export/editor_export.h"
#include "export_plugin.h" #include "export_plugin.h"
void register_linuxbsd_exporter_types() {
GDREGISTER_VIRTUAL_CLASS(EditorExportPlatformLinuxBSD);
}
void register_linuxbsd_exporter() { void register_linuxbsd_exporter() {
Ref<EditorExportPlatformLinuxBSD> platform; Ref<EditorExportPlatformLinuxBSD> platform;
platform.instantiate(); platform.instantiate();

View file

@ -31,6 +31,7 @@
#ifndef LINUXBSD_EXPORT_H #ifndef LINUXBSD_EXPORT_H
#define LINUXBSD_EXPORT_H #define LINUXBSD_EXPORT_H
void register_linuxbsd_exporter_types();
void register_linuxbsd_exporter(); void register_linuxbsd_exporter();
#endif // LINUXBSD_EXPORT_H #endif // LINUXBSD_EXPORT_H

View file

@ -142,7 +142,18 @@ List<String> EditorExportPlatformLinuxBSD::get_binary_extensions(const Ref<Edito
return list; return list;
} }
void EditorExportPlatformLinuxBSD::get_export_options(List<ExportOption> *r_options) { bool EditorExportPlatformLinuxBSD::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const {
if (p_preset) {
// Hide SSH options.
bool ssh = p_preset->get("ssh_remote_deploy/enabled");
if (!ssh && p_option != "ssh_remote_deploy/enabled" && p_option.begins_with("ssh_remote_deploy/")) {
return false;
}
}
return true;
}
void EditorExportPlatformLinuxBSD::get_export_options(List<ExportOption> *r_options) const {
EditorExportPlatformPC::get_export_options(r_options); EditorExportPlatformPC::get_export_options(r_options);
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64,arm32,rv64,ppc64,ppc32"), "x86_64")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64,arm32,rv64,ppc64,ppc32"), "x86_64"));
@ -156,7 +167,7 @@ void EditorExportPlatformLinuxBSD::get_export_options(List<ExportOption> *r_opti
"kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\")\n" "kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\")\n"
"rm -rf \"{temp_dir}\""; "rm -rf \"{temp_dir}\"";
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "ssh_remote_deploy/enabled"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "ssh_remote_deploy/enabled"), false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/host"), "user@host_ip")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/host"), "user@host_ip"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/port"), "22")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/port"), "22"));
@ -503,22 +514,24 @@ Error EditorExportPlatformLinuxBSD::run(const Ref<EditorExportPreset> &p_preset,
} }
EditorExportPlatformLinuxBSD::EditorExportPlatformLinuxBSD() { EditorExportPlatformLinuxBSD::EditorExportPlatformLinuxBSD() {
if (EditorNode::get_singleton()) {
#ifdef MODULE_SVG_ENABLED #ifdef MODULE_SVG_ENABLED
Ref<Image> img = memnew(Image); Ref<Image> img = memnew(Image);
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
ImageLoaderSVG img_loader; ImageLoaderSVG img_loader;
img_loader.create_image_from_string(img, _linuxbsd_logo_svg, EDSCALE, upsample, false); img_loader.create_image_from_string(img, _linuxbsd_logo_svg, EDSCALE, upsample, false);
set_logo(ImageTexture::create_from_image(img)); set_logo(ImageTexture::create_from_image(img));
img_loader.create_image_from_string(img, _linuxbsd_run_icon_svg, EDSCALE, upsample, false); img_loader.create_image_from_string(img, _linuxbsd_run_icon_svg, EDSCALE, upsample, false);
run_icon = ImageTexture::create_from_image(img); run_icon = ImageTexture::create_from_image(img);
#endif #endif
Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme(); Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
if (theme.is_valid()) { if (theme.is_valid()) {
stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons")); stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons"));
} else { } else {
stop_icon.instantiate(); stop_icon.instantiate();
}
} }
} }

View file

@ -37,6 +37,8 @@
#include "scene/resources/texture.h" #include "scene/resources/texture.h"
class EditorExportPlatformLinuxBSD : public EditorExportPlatformPC { class EditorExportPlatformLinuxBSD : public EditorExportPlatformPC {
GDCLASS(EditorExportPlatformLinuxBSD, EditorExportPlatformPC);
HashMap<String, String> extensions; HashMap<String, String> extensions;
struct SSHCleanupCommand { struct SSHCleanupCommand {
@ -69,8 +71,9 @@ class EditorExportPlatformLinuxBSD : public EditorExportPlatformPC {
Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path); Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path);
public: public:
virtual void get_export_options(List<ExportOption> *r_options) override; virtual void get_export_options(List<ExportOption> *r_options) const override;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override; virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const override;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override; virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
virtual String get_template_file_name(const String &p_target, const String &p_arch) const override; virtual String get_template_file_name(const String &p_target, const String &p_arch) const override;
virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override; virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override;

View file

@ -32,6 +32,10 @@
#include "export_plugin.h" #include "export_plugin.h"
void register_macos_exporter_types() {
GDREGISTER_VIRTUAL_CLASS(EditorExportPlatformMacOS);
}
void register_macos_exporter() { void register_macos_exporter() {
#ifndef ANDROID_ENABLED #ifndef ANDROID_ENABLED
EDITOR_DEF("export/macos/rcodesign", ""); EDITOR_DEF("export/macos/rcodesign", "");

View file

@ -31,6 +31,7 @@
#ifndef MACOS_EXPORT_H #ifndef MACOS_EXPORT_H
#define MACOS_EXPORT_H #define MACOS_EXPORT_H
void register_macos_exporter_types();
void register_macos_exporter(); void register_macos_exporter();
#endif // MACOS_EXPORT_H #endif // MACOS_EXPORT_H

View file

@ -62,13 +62,191 @@ void EditorExportPlatformMacOS::get_preset_features(const Ref<EditorExportPreset
} }
} }
bool EditorExportPlatformMacOS::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const { String EditorExportPlatformMacOS::get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const {
if (p_preset) {
int dist_type = p_preset->get("export/distribution_type");
bool ad_hoc = false;
int codesign_tool = p_preset->get("codesign/codesign");
int notary_tool = p_preset->get("notarization/notarization");
switch (codesign_tool) {
case 1: { // built-in ad-hoc
ad_hoc = true;
} break;
case 2: { // "rcodesign"
ad_hoc = p_preset->get("codesign/certificate_file").operator String().is_empty() || p_preset->get("codesign/certificate_password").operator String().is_empty();
} break;
#ifdef MACOS_ENABLED
case 3: { // "codesign"
ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-");
} break;
#endif
default: {
};
}
if (p_name == "application/bundle_identifier") {
String identifier = p_preset->get("application/bundle_identifier");
String pn_err;
if (!is_package_name_valid(identifier, &pn_err)) {
return TTR("Invalid bundle identifier:") + " " + pn_err;
}
}
if (p_name == "codesign/certificate_file" || p_name == "codesign/certificate_password" || p_name == "codesign/identity") {
if (dist_type == 2) {
if (ad_hoc) {
return TTR("App Store distribution with ad-hoc code signing is not supported.");
}
} else if (notary_tool > 0 && ad_hoc) {
return TTR("Notarization with an ad-hoc signature is not supported.");
}
}
if (p_name == "codesign/apple_team_id") {
String team_id = p_preset->get("codesign/apple_team_id");
if (team_id.is_empty()) {
if (dist_type == 2) {
return TTR("Apple Team ID is required for App Store distribution.");
} else if (notary_tool > 0) {
return TTR("Apple Team ID is required for notarization.");
}
}
}
if (p_name == "codesign/provisioning_profile" && dist_type == 2) {
String pprof = p_preset->get("codesign/provisioning_profile");
if (pprof.is_empty()) {
return TTR("Provisioning profile is required for App Store distribution.");
}
}
if (p_name == "codesign/installer_identity" && dist_type == 2) {
String ident = p_preset->get("codesign/installer_identity");
if (ident.is_empty()) {
return TTR("Installer signing identity is required for App Store distribution.");
}
}
if (p_name == "codesign/entitlements/app_sandbox/enabled" && dist_type == 2) {
bool sandbox = p_preset->get("codesign/entitlements/app_sandbox/enabled");
if (!sandbox) {
return TTR("App sandbox is required for App Store distribution.");
}
}
if (p_name == "codesign/codesign") {
if (dist_type == 2) {
if (codesign_tool == 0) {
return TTR("Code signing is required for App Store distribution.");
}
if (codesign_tool == 1) {
return TTR("App Store distribution with ad-hoc code signing is not supported.");
}
} else if (notary_tool > 0) {
if (codesign_tool == 0) {
return TTR("Code signing is required for notarization.");
}
if (codesign_tool == 1) {
return TTR("Notarization with an ad-hoc signature is not supported.");
}
}
}
if (notary_tool == 2 || notary_tool == 3) {
if (p_name == "notarization/apple_id_name" || p_name == "notarization/api_uuid") {
String apple_id = p_preset->get("notarization/apple_id_name");
String api_uuid = p_preset->get("notarization/api_uuid");
if (apple_id.is_empty() && api_uuid.is_empty()) {
return TTR("Neither Apple ID name nor App Store Connect issuer ID name not specified.");
}
if (!apple_id.is_empty() && !api_uuid.is_empty()) {
return TTR("Both Apple ID name and App Store Connect issuer ID name are specified, only one should be set at the same time.");
}
}
if (p_name == "notarization/apple_id_password") {
String apple_id = p_preset->get("notarization/apple_id_name");
String apple_pass = p_preset->get("notarization/apple_id_password");
if (!apple_id.is_empty() && apple_pass.is_empty()) {
return TTR("Apple ID password not specified.");
}
}
if (p_name == "notarization/api_key_id") {
String api_uuid = p_preset->get("notarization/api_uuid");
String api_key = p_preset->get("notarization/api_key_id");
if (!api_uuid.is_empty() && api_key.is_empty()) {
return TTR("App Store Connect API key ID not specified.");
}
}
} else if (notary_tool == 1) {
if (p_name == "notarization/api_uuid") {
String api_uuid = p_preset->get("notarization/api_uuid");
if (api_uuid.is_empty()) {
return TTR("App Store Connect issuer ID name not specified.");
}
}
if (p_name == "notarization/api_key_id") {
String api_key = p_preset->get("notarization/api_key_id");
if (api_key.is_empty()) {
return TTR("App Store Connect API key ID not specified.");
}
}
}
if (codesign_tool > 0) {
if (p_name == "privacy/microphone_usage_description") {
String discr = p_preset->get("privacy/microphone_usage_description");
bool enabled = p_preset->get("codesign/entitlements/audio_input");
if (enabled && discr.is_empty()) {
return TTR("Microphone access is enabled, but usage description is not specified.");
}
}
if (p_name == "privacy/camera_usage_description") {
String discr = p_preset->get("privacy/camera_usage_description");
bool enabled = p_preset->get("codesign/entitlements/camera");
if (enabled && discr.is_empty()) {
return TTR("Camera access is enabled, but usage description is not specified.");
}
}
if (p_name == "privacy/location_usage_description") {
String discr = p_preset->get("privacy/location_usage_description");
bool enabled = p_preset->get("codesign/entitlements/location");
if (enabled && discr.is_empty()) {
return TTR("Location information access is enabled, but usage description is not specified.");
}
}
if (p_name == "privacy/address_book_usage_description") {
String discr = p_preset->get("privacy/address_book_usage_description");
bool enabled = p_preset->get("codesign/entitlements/address_book");
if (enabled && discr.is_empty()) {
return TTR("Address book access is enabled, but usage description is not specified.");
}
}
if (p_name == "privacy/calendar_usage_description") {
String discr = p_preset->get("privacy/calendar_usage_description");
bool enabled = p_preset->get("codesign/entitlements/calendars");
if (enabled && discr.is_empty()) {
return TTR("Calendar access is enabled, but usage description is not specified.");
}
}
if (p_name == "privacy/photos_library_usage_description") {
String discr = p_preset->get("privacy/photos_library_usage_description");
bool enabled = p_preset->get("codesign/entitlements/photos_library");
if (enabled && discr.is_empty()) {
return TTR("Photo library access is enabled, but usage description is not specified.");
}
}
}
}
return String();
}
bool EditorExportPlatformMacOS::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const {
// Hide irrelevant code signing options. // Hide irrelevant code signing options.
if (p_preset) { if (p_preset) {
int codesign_tool = p_preset->get("codesign/codesign"); int codesign_tool = p_preset->get("codesign/codesign");
switch (codesign_tool) { switch (codesign_tool) {
case 1: { // built-in ad-hoc case 1: { // built-in ad-hoc
if (p_option == "codesign/identity" || p_option == "codesign/certificate_file" || p_option == "codesign/certificate_password" || p_option == "codesign/custom_options") { if (p_option == "codesign/identity" || p_option == "codesign/certificate_file" || p_option == "codesign/certificate_password" || p_option == "codesign/custom_options" || p_option == "codesign/team_id") {
return false; return false;
} }
} break; } break;
@ -85,17 +263,48 @@ bool EditorExportPlatformMacOS::get_export_option_visibility(const EditorExportP
} break; } break;
#endif #endif
default: { // disabled default: { // disabled
if (p_option == "codesign/identity" || p_option == "codesign/certificate_file" || p_option == "codesign/certificate_password" || p_option == "codesign/custom_options" || p_option.begins_with("codesign/entitlements")) { if (p_option == "codesign/identity" || p_option == "codesign/certificate_file" || p_option == "codesign/certificate_password" || p_option == "codesign/custom_options" || p_option.begins_with("codesign/entitlements") || p_option == "codesign/team_id") {
return false; return false;
} }
} break; } break;
} }
// Distribution type.
int dist_type = p_preset->get("export/distribution_type");
if (dist_type != 2 && p_option == "codesign/installer_identity") {
return false;
}
if (dist_type == 2 && p_option.begins_with("notarization/")) {
return false;
}
if (dist_type != 2 && p_option == "codesign/provisioning_profile") {
return false;
}
String custom_prof = p_preset->get("codesign/entitlements/custom_file");
if (!custom_prof.is_empty() && p_option != "codesign/entitlements/custom_file" && p_option.begins_with("codesign/entitlements/")) {
return false;
}
// Hide sandbox entitlements.
bool sandbox = p_preset->get("codesign/entitlements/app_sandbox/enabled");
if (!sandbox && p_option != "codesign/entitlements/app_sandbox/enabled" && p_option.begins_with("codesign/entitlements/app_sandbox/")) {
return false;
}
// Hide SSH options.
bool ssh = p_preset->get("ssh_remote_deploy/enabled");
if (!ssh && p_option != "ssh_remote_deploy/enabled" && p_option.begins_with("ssh_remote_deploy/")) {
return false;
}
// Hide irrelevant notarization options. // Hide irrelevant notarization options.
int notary_tool = p_preset->get("notarization/notarization"); int notary_tool = p_preset->get("notarization/notarization");
switch (notary_tool) { switch (notary_tool) {
case 1: { // "rcodesign" case 1: { // "rcodesign"
if (p_option == "notarization/apple_id_name" || p_option == "notarization/apple_id_password" || p_option == "notarization/apple_team_id") { if (p_option == "notarization/apple_id_name" || p_option == "notarization/apple_id_password") {
return false; return false;
} }
} break; } break;
@ -106,7 +315,7 @@ bool EditorExportPlatformMacOS::get_export_option_visibility(const EditorExportP
// All options are visible. // All options are visible.
} break; } break;
default: { // disabled default: { // disabled
if (p_option == "notarization/apple_id_name" || p_option == "notarization/apple_id_password" || p_option == "notarization/apple_team_id" || p_option == "notarization/api_uuid" || p_option == "notarization/api_key" || p_option == "notarization/api_key_id") { if (p_option == "notarization/apple_id_name" || p_option == "notarization/apple_id_password" || p_option == "notarization/api_uuid" || p_option == "notarization/api_key" || p_option == "notarization/api_key_id") {
return false; return false;
} }
} break; } break;
@ -122,7 +331,39 @@ bool EditorExportPlatformMacOS::get_export_option_visibility(const EditorExportP
return true; return true;
} }
void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options) { List<String> EditorExportPlatformMacOS::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
List<String> list;
if (p_preset.is_valid()) {
int dist_type = p_preset->get("export/distribution_type");
if (dist_type == 0) {
#ifdef MACOS_ENABLED
list.push_back("dmg");
#endif
list.push_back("zip");
list.push_back("app");
} else if (dist_type == 1) {
#ifdef MACOS_ENABLED
list.push_back("dmg");
#endif
list.push_back("zip");
} else if (dist_type == 2) {
#ifdef MACOS_ENABLED
list.push_back("pkg");
#endif
}
}
return list;
}
void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options) const {
#ifdef MACOS_ENABLED
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "export/distribution_type", PROPERTY_HINT_ENUM, "Testing,Distribution,App Store"), 1, true));
#else
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "export/distribution_type", PROPERTY_HINT_ENUM, "Testing,Distribution"), 1, true));
#endif
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "universal,x86_64,arm64", PROPERTY_USAGE_STORAGE), "universal")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "universal,x86_64,arm64", PROPERTY_USAGE_STORAGE), "universal"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
@ -130,27 +371,39 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "debug/export_console_script", PROPERTY_HINT_ENUM, "No,Debug Only,Debug and Release"), 1)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "debug/export_console_script", PROPERTY_HINT_ENUM, "No,Debug Only,Debug and Release"), 1));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.icns,*.png,*.webp,*.svg"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.icns,*.png,*.webp,*.svg"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_category", PROPERTY_HINT_ENUM, "Business,Developer-tools,Education,Entertainment,Finance,Games,Action-games,Adventure-games,Arcade-games,Board-games,Card-games,Casino-games,Dice-games,Educational-games,Family-games,Kids-games,Music-games,Puzzle-games,Racing-games,Role-playing-games,Simulation-games,Sports-games,Strategy-games,Trivia-games,Word-games,Graphics-design,Healthcare-fitness,Lifestyle,Medical,Music,News,Photography,Productivity,Reference,Social-networking,Sports,Travel,Utilities,Video,Weather"), "Games")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_category", PROPERTY_HINT_ENUM, "Business,Developer-tools,Education,Entertainment,Finance,Games,Action-games,Adventure-games,Arcade-games,Board-games,Card-games,Casino-games,Dice-games,Educational-games,Family-games,Kids-games,Music-games,Puzzle-games,Racing-games,Role-playing-games,Simulation-games,Sports-games,Strategy-games,Trivia-games,Word-games,Graphics-design,Healthcare-fitness,Lifestyle,Medical,Music,News,Photography,Productivity,Reference,Social-networking,Sports,Travel,Utilities,Video,Weather"), "Games"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "application/copyright_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "application/copyright_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/min_macos_version"), "10.12"));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "xcode/platform_build"), "14C18"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "xcode/sdk_version"), "13.1"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "xcode/sdk_build"), "22C55"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "xcode/sdk_name"), "macosx13.1"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "xcode/xcode_version"), "1420"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "xcode/xcode_build"), "14C18"));
#ifdef MACOS_ENABLED #ifdef MACOS_ENABLED
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/codesign", PROPERTY_HINT_ENUM, "Disabled,Built-in (ad-hoc only),rcodesign,Xcode codesign"), 3, true)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/codesign", PROPERTY_HINT_ENUM, "Disabled,Built-in (ad-hoc only),rcodesign,Xcode codesign"), 3, true));
#else #else
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/codesign", PROPERTY_HINT_ENUM, "Disabled,Built-in (ad-hoc only),rcodesign"), 1, true)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/codesign", PROPERTY_HINT_ENUM, "Disabled,Built-in (ad-hoc only),rcodesign"), 1, true, true));
#endif #endif
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/installer_identity", PROPERTY_HINT_PLACEHOLDER_TEXT, "3rd Party Mac Developer Installer: (ID)"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/apple_team_id", PROPERTY_HINT_PLACEHOLDER_TEXT, "ID"), "", false, true));
// "codesign" only options: // "codesign" only options:
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_PLACEHOLDER_TEXT, "Type: Name (ID)"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_PLACEHOLDER_TEXT, "Type: Name (ID)"), ""));
// "rcodesign" only options: // "rcodesign" only options:
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/certificate_file", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/certificate_file", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/certificate_password", PROPERTY_HINT_PASSWORD), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/certificate_password", PROPERTY_HINT_PASSWORD), ""));
// "codesign" and "rcodesign" only options: // "codesign" and "rcodesign" only options:
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements/custom_file", PROPERTY_HINT_GLOBAL_FILE, "*.plist"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/provisioning_profile", PROPERTY_HINT_GLOBAL_FILE, "*.provisionprofile"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements/custom_file", PROPERTY_HINT_GLOBAL_FILE, "*.plist"), "", true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_jit_code_execution"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_jit_code_execution"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_unsigned_executable_memory"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_unsigned_executable_memory"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_dyld_environment_variables"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_dyld_environment_variables"), false));
@ -163,7 +416,7 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/photos_library"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/photos_library"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/apple_events"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/apple_events"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/debugging"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/debugging"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/enabled"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/enabled"), false, true, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/network_server"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/network_server"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/network_client"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/network_client"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/device_usb"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/device_usb"), false));
@ -181,35 +434,34 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "notarization/notarization", PROPERTY_HINT_ENUM, "Disabled,rcodesign"), 0, true)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "notarization/notarization", PROPERTY_HINT_ENUM, "Disabled,rcodesign"), 0, true));
#endif #endif
// "altool" and "notarytool" only options: // "altool" and "notarytool" only options:
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Apple ID email"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Apple ID email"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_password", PROPERTY_HINT_PASSWORD, "Enable two-factor authentication and provide app-specific password"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_password", PROPERTY_HINT_PASSWORD, "Enable two-factor authentication and provide app-specific password"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_team_id", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide team ID if your Apple ID belongs to multiple teams"), ""));
// "altool", "notarytool" and "rcodesign" only options: // "altool", "notarytool" and "rcodesign" only options:
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_uuid", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect issuer ID UUID"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_uuid", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect issuer ID UUID"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key", PROPERTY_HINT_GLOBAL_FILE, "*.p8"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key", PROPERTY_HINT_GLOBAL_FILE, "*.p8"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key_id", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect API key ID"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key_id", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect API key ID"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/microphone_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/microphone_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/camera_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the camera"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/camera_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the camera"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/camera_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/camera_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/location_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the location information"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/location_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the location information"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/location_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/location_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/address_book_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the address book"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/address_book_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the address book"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/address_book_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/address_book_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/calendar_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the calendar"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/calendar_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the calendar"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/calendar_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/calendar_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photos_library_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the photo library"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photos_library_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the photo library"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/photos_library_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/photos_library_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/desktop_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Desktop folder"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/desktop_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Desktop folder"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/desktop_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/desktop_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/documents_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Documents folder"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/documents_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Documents folder"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/documents_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/documents_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/downloads_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Downloads folder"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/downloads_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Downloads folder"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/downloads_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/downloads_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/network_volumes_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use network volumes"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/network_volumes_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use network volumes"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/network_volumes_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/network_volumes_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/removable_volumes_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use removable volumes"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/removable_volumes_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use removable volumes"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/removable_volumes_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary())); r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/removable_volumes_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
String run_script = "#!/usr/bin/env bash\n" String run_script = "#!/usr/bin/env bash\n"
@ -220,7 +472,7 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
"kill $(pgrep -x -f \"{temp_dir}/{exe_name}.app/Contents/MacOS/{exe_name} {cmd_args}\")\n" "kill $(pgrep -x -f \"{temp_dir}/{exe_name}.app/Contents/MacOS/{exe_name} {cmd_args}\")\n"
"rm -rf \"{temp_dir}\""; "rm -rf \"{temp_dir}\"";
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "ssh_remote_deploy/enabled"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "ssh_remote_deploy/enabled"), false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/host"), "user@host_ip")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/host"), "user@host_ip"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/port"), "22")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/port"), "22"));
@ -424,8 +676,22 @@ void EditorExportPlatformMacOS::_fix_plist(const Ref<EditorExportPreset> &p_pres
strnew += lines[i].replace("$app_category", cat.to_lower()) + "\n"; strnew += lines[i].replace("$app_category", cat.to_lower()) + "\n";
} else if (lines[i].find("$copyright") != -1) { } else if (lines[i].find("$copyright") != -1) {
strnew += lines[i].replace("$copyright", p_preset->get("application/copyright")) + "\n"; strnew += lines[i].replace("$copyright", p_preset->get("application/copyright")) + "\n";
} else if (lines[i].find("$min_version") != -1) {
strnew += lines[i].replace("$min_version", p_preset->get("application/min_macos_version")) + "\n";
} else if (lines[i].find("$highres") != -1) { } else if (lines[i].find("$highres") != -1) {
strnew += lines[i].replace("$highres", p_preset->get("display/high_res") ? "\t<true/>" : "\t<false/>") + "\n"; strnew += lines[i].replace("$highres", p_preset->get("display/high_res") ? "\t<true/>" : "\t<false/>") + "\n";
} else if (lines[i].find("$platfbuild") != -1) {
strnew += lines[i].replace("$platfbuild", p_preset->get("xcode/platform_build")) + "\n";
} else if (lines[i].find("$sdkver") != -1) {
strnew += lines[i].replace("$sdkver", p_preset->get("xcode/sdk_version")) + "\n";
} else if (lines[i].find("$sdkname") != -1) {
strnew += lines[i].replace("$sdkname", p_preset->get("xcode/sdk_name")) + "\n";
} else if (lines[i].find("$sdkbuild") != -1) {
strnew += lines[i].replace("$sdkbuild", p_preset->get("xcode/sdk_build")) + "\n";
} else if (lines[i].find("$xcodever") != -1) {
strnew += lines[i].replace("$xcodever", p_preset->get("xcode/xcode_version")) + "\n";
} else if (lines[i].find("$xcodebuild") != -1) {
strnew += lines[i].replace("$xcodebuild", p_preset->get("xcode/xcode_build")) + "\n";
} else if (lines[i].find("$usage_descriptions") != -1) { } else if (lines[i].find("$usage_descriptions") != -1) {
String descriptions; String descriptions;
if (!((String)p_preset->get("privacy/microphone_usage_description")).is_empty()) { if (!((String)p_preset->get("privacy/microphone_usage_description")).is_empty()) {
@ -612,9 +878,9 @@ Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_pres
args.push_back("--no-progress"); args.push_back("--no-progress");
if (p_preset->get("notarization/apple_team_id")) { if (p_preset->get("codesign/apple_team_id")) {
args.push_back("--team-id"); args.push_back("--team-id");
args.push_back(p_preset->get("notarization/apple_team_id")); args.push_back(p_preset->get("codesign/apple_team_id"));
} }
String str; String str;
@ -693,9 +959,9 @@ Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_pres
args.push_back("--type"); args.push_back("--type");
args.push_back("osx"); args.push_back("osx");
if (p_preset->get("notarization/apple_team_id")) { if (p_preset->get("codesign/apple_team_id")) {
args.push_back("--asc-provider"); args.push_back("--asc-provider");
args.push_back(p_preset->get("notarization/apple_team_id")); args.push_back(p_preset->get("codesign/apple_team_id"));
} }
args.push_back("--file"); args.push_back("--file");
@ -978,6 +1244,42 @@ Error EditorExportPlatformMacOS::_export_macos_plugins_for(Ref<EditorExportPlugi
return error; return error;
} }
Error EditorExportPlatformMacOS::_create_pkg(const Ref<EditorExportPreset> &p_preset, const String &p_pkg_path, const String &p_app_path_name) {
List<String> args;
if (FileAccess::exists(p_pkg_path)) {
OS::get_singleton()->move_to_trash(p_pkg_path);
}
args.push_back("productbuild");
args.push_back("--component");
args.push_back(p_app_path_name);
args.push_back("/Applications");
String ident = p_preset->get("codesign/installer_identity");
if (!ident.is_empty()) {
args.push_back("--timestamp");
args.push_back("--sign");
args.push_back(ident);
}
args.push_back("--quiet");
args.push_back(p_pkg_path);
String str;
Error err = OS::get_singleton()->execute("xcrun", args, &str, nullptr, true);
if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("PKG Creation"), TTR("Could not start productbuild executable."));
return err;
}
print_verbose("productbuild returned: " + str);
if (str.find("productbuild: error:") != -1) {
add_message(EXPORT_MESSAGE_ERROR, TTR("PKG Creation"), TTR("`productbuild` failed."));
return FAILED;
}
return OK;
}
Error EditorExportPlatformMacOS::_create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name) { Error EditorExportPlatformMacOS::_create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name) {
List<String> args; List<String> args;
@ -1106,12 +1408,16 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
pkg_name = OS::get_singleton()->get_safe_dir_name(pkg_name); pkg_name = OS::get_singleton()->get_safe_dir_name(pkg_name);
String export_format; String export_format;
if (use_dmg() && p_path.ends_with("dmg")) { if (p_path.ends_with("zip")) {
export_format = "dmg";
} else if (p_path.ends_with("zip")) {
export_format = "zip"; export_format = "zip";
} else if (p_path.ends_with("app")) { } else if (p_path.ends_with("app")) {
export_format = "app"; export_format = "app";
#ifdef MACOS_ENABLED
} else if (p_path.ends_with("dmg")) {
export_format = "dmg";
} else if (p_path.ends_with("pkg")) {
export_format = "pkg";
#endif
} else { } else {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Invalid export format.")); add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Invalid export format."));
return ERR_CANT_CREATE; return ERR_CANT_CREATE;
@ -1549,6 +1855,19 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
ent_f->store_line("<true/>"); ent_f->store_line("<true/>");
} }
int dist_type = p_preset->get("export/distribution_type");
if (dist_type == 2) {
String pprof = p_preset->get("codesign/provisioning_profile");
String teamid = p_preset->get("codesign/apple_team_id");
String bid = p_preset->get("application/bundle_identifier");
if (!pprof.is_empty() && !teamid.is_empty()) {
ent_f->store_line("<key>com.apple.developer.team-identifier</key>");
ent_f->store_line("<string>" + teamid + "</string>");
ent_f->store_line("<key>com.apple.application-identifier</key>");
ent_f->store_line("<string>" + teamid + "." + bid + "</string>");
}
}
if ((bool)p_preset->get("codesign/entitlements/app_sandbox/enabled")) { if ((bool)p_preset->get("codesign/entitlements/app_sandbox/enabled")) {
ent_f->store_line("<key>com.apple.security.app-sandbox</key>"); ent_f->store_line("<key>com.apple.security.app-sandbox</key>");
ent_f->store_line("<true/>"); ent_f->store_line("<true/>");
@ -1669,6 +1988,15 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
} }
if (err == OK && sign_enabled) { if (err == OK && sign_enabled) {
int dist_type = p_preset->get("export/distribution_type");
if (dist_type == 2) {
String pprof = p_preset->get("codesign/provisioning_profile").operator String();
if (!pprof.is_empty()) {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
err = da->copy(pprof, tmp_app_path_name + "/Contents/embedded.provisionprofile");
}
}
if (ep.step(TTR("Code signing bundle"), 2)) { if (ep.step(TTR("Code signing bundle"), 2)) {
return ERR_SKIP; return ERR_SKIP;
} }
@ -1690,6 +2018,14 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
} }
err = _code_sign(p_preset, p_path, ent_path, false); err = _code_sign(p_preset, p_path, ent_path, false);
} }
} else if (export_format == "pkg") {
// Create a Installer.
if (err == OK) {
if (ep.step(TTR("Making PKG installer"), 3)) {
return ERR_SKIP;
}
err = _create_pkg(p_preset, p_path, tmp_app_path_name);
}
} else if (export_format == "zip") { } else if (export_format == "zip") {
// Create ZIP. // Create ZIP.
if (err == OK) { if (err == OK) {
@ -1712,7 +2048,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
bool noto_enabled = (p_preset->get("notarization/notarization").operator int() > 0); bool noto_enabled = (p_preset->get("notarization/notarization").operator int() > 0);
if (err == OK && noto_enabled) { if (err == OK && noto_enabled) {
if (export_format == "app") { if (export_format == "app" || export_format == "pkg") {
add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("Notarization requires the app to be archived first, select the DMG or ZIP export format instead.")); add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("Notarization requires the app to be archived first, select the DMG or ZIP export format instead."));
} else { } else {
if (ep.step(TTR("Sending archive for notarization"), 4)) { if (ep.step(TTR("Sending archive for notarization"), 4)) {
@ -1802,15 +2138,10 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor
String err; String err;
bool valid = true; bool valid = true;
String identifier = p_preset->get("application/bundle_identifier"); int dist_type = p_preset->get("export/distribution_type");
String pn_err;
if (!is_package_name_valid(identifier, &pn_err)) {
err += TTR("Invalid bundle identifier:") + " " + pn_err + "\n";
valid = false;
}
bool ad_hoc = false; bool ad_hoc = false;
int codesign_tool = p_preset->get("codesign/codesign"); int codesign_tool = p_preset->get("codesign/codesign");
int notary_tool = p_preset->get("notarization/notarization");
switch (codesign_tool) { switch (codesign_tool) {
case 1: { // built-in ad-hoc case 1: { // built-in ad-hoc
ad_hoc = true; ad_hoc = true;
@ -1826,66 +2157,40 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor
default: { default: {
}; };
} }
int notary_tool = p_preset->get("notarization/notarization");
if (notary_tool > 0) { List<ExportOption> options;
if (ad_hoc) { get_export_options(&options);
err += TTR("Notarization: Notarization with an ad-hoc signature is not supported.") + "\n"; for (const EditorExportPlatform::ExportOption &E : options) {
valid = false; if (get_export_option_visibility(p_preset.ptr(), E.option.name)) {
} String warn = get_export_option_warning(p_preset.ptr(), E.option.name);
if (codesign_tool == 0) { if (!warn.is_empty()) {
err += TTR("Notarization: Code signing is required for notarization.") + "\n"; err += warn + "\n";
valid = false; if (E.required) {
} valid = false;
if (notary_tool == 2 || notary_tool == 3) {
if (!FileAccess::exists("/usr/bin/xcrun") && !FileAccess::exists("/bin/xcrun")) {
err += TTR("Notarization: Xcode command line tools are not installed.") + "\n";
valid = false;
}
if (p_preset->get("notarization/apple_id_name") == "" && p_preset->get("notarization/api_uuid") == "") {
err += TTR("Notarization: Neither Apple ID name nor App Store Connect issuer ID name not specified.") + "\n";
valid = false;
} else if (p_preset->get("notarization/apple_id_name") != "" && p_preset->get("notarization/api_uuid") != "") {
err += TTR("Notarization: Both Apple ID name and App Store Connect issuer ID name are specified, only one should be set at the same time.") + "\n";
valid = false;
} else {
if (p_preset->get("notarization/apple_id_name") != "") {
if (p_preset->get("notarization/apple_id_password") == "") {
err += TTR("Notarization: Apple ID password not specified.") + "\n";
valid = false;
}
}
if (p_preset->get("notarization/api_uuid") != "") {
if (p_preset->get("notarization/api_key_id") == "") {
err += TTR("Notarization: App Store Connect API key ID not specified.") + "\n";
valid = false;
}
} }
} }
if (notary_tool == 2 && p_preset->get("notarization/apple_team_id") == "") {
err += TTR("Notarization: Apple Team ID not specified.") + "\n";
valid = false;
}
} else if (notary_tool == 1) {
if (p_preset->get("notarization/api_uuid") == "") {
err += TTR("Notarization: App Store Connect issuer ID name not specified.") + "\n";
valid = false;
}
if (p_preset->get("notarization/api_key_id") == "") {
err += TTR("Notarization: App Store Connect API key ID not specified.") + "\n";
valid = false;
}
String rcodesign = EDITOR_GET("export/macos/rcodesign").operator String();
if (rcodesign.is_empty()) {
err += TTR("Notarization: rcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign).") + "\n";
valid = false;
}
} }
} else { }
err += TTR("Warning: Notarization is disabled. The exported project will be blocked by Gatekeeper if it's downloaded from an unknown source.") + "\n";
if (codesign_tool == 0) { if (dist_type != 2) {
err += TTR("Code signing is disabled. The exported project will not run on Macs with enabled Gatekeeper and Apple Silicon powered Macs.") + "\n"; if (notary_tool > 0) {
if (notary_tool == 2 || notary_tool == 3) {
if (!FileAccess::exists("/usr/bin/xcrun") && !FileAccess::exists("/bin/xcrun")) {
err += TTR("Notarization: Xcode command line tools are not installed.") + "\n";
valid = false;
}
} else if (notary_tool == 1) {
String rcodesign = EDITOR_GET("export/macos/rcodesign").operator String();
if (rcodesign.is_empty()) {
err += TTR("Notarization: rcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign).") + "\n";
valid = false;
}
}
} else {
err += TTR("Warning: Notarization is disabled. The exported project will be blocked by Gatekeeper if it's downloaded from an unknown source.") + "\n";
if (codesign_tool == 0) {
err += TTR("Code signing is disabled. The exported project will not run on Macs with enabled Gatekeeper and Apple Silicon powered Macs.") + "\n";
}
} }
} }
@ -1905,30 +2210,6 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<Editor
valid = false; valid = false;
} }
} }
if ((bool)p_preset->get("codesign/entitlements/audio_input") && ((String)p_preset->get("privacy/microphone_usage_description")).is_empty()) {
err += TTR("Privacy: Microphone access is enabled, but usage description is not specified.") + "\n";
valid = false;
}
if ((bool)p_preset->get("codesign/entitlements/camera") && ((String)p_preset->get("privacy/camera_usage_description")).is_empty()) {
err += TTR("Privacy: Camera access is enabled, but usage description is not specified.") + "\n";
valid = false;
}
if ((bool)p_preset->get("codesign/entitlements/location") && ((String)p_preset->get("privacy/location_usage_description")).is_empty()) {
err += TTR("Privacy: Location information access is enabled, but usage description is not specified.") + "\n";
valid = false;
}
if ((bool)p_preset->get("codesign/entitlements/address_book") && ((String)p_preset->get("privacy/address_book_usage_description")).is_empty()) {
err += TTR("Privacy: Address book access is enabled, but usage description is not specified.") + "\n";
valid = false;
}
if ((bool)p_preset->get("codesign/entitlements/calendars") && ((String)p_preset->get("privacy/calendar_usage_description")).is_empty()) {
err += TTR("Privacy: Calendar access is enabled, but usage description is not specified.") + "\n";
valid = false;
}
if ((bool)p_preset->get("codesign/entitlements/photos_library") && ((String)p_preset->get("privacy/photos_library_usage_description")).is_empty()) {
err += TTR("Privacy: Photo library access is enabled, but usage description is not specified.") + "\n";
valid = false;
}
} }
if (!err.is_empty()) { if (!err.is_empty()) {
@ -2157,22 +2438,24 @@ Error EditorExportPlatformMacOS::run(const Ref<EditorExportPreset> &p_preset, in
} }
EditorExportPlatformMacOS::EditorExportPlatformMacOS() { EditorExportPlatformMacOS::EditorExportPlatformMacOS() {
if (EditorNode::get_singleton()) {
#ifdef MODULE_SVG_ENABLED #ifdef MODULE_SVG_ENABLED
Ref<Image> img = memnew(Image); Ref<Image> img = memnew(Image);
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
ImageLoaderSVG img_loader; ImageLoaderSVG img_loader;
img_loader.create_image_from_string(img, _macos_logo_svg, EDSCALE, upsample, false); img_loader.create_image_from_string(img, _macos_logo_svg, EDSCALE, upsample, false);
logo = ImageTexture::create_from_image(img); logo = ImageTexture::create_from_image(img);
img_loader.create_image_from_string(img, _macos_run_icon_svg, EDSCALE, upsample, false); img_loader.create_image_from_string(img, _macos_run_icon_svg, EDSCALE, upsample, false);
run_icon = ImageTexture::create_from_image(img); run_icon = ImageTexture::create_from_image(img);
#endif #endif
Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme(); Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
if (theme.is_valid()) { if (theme.is_valid()) {
stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons")); stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons"));
} else { } else {
stop_icon.instantiate(); stop_icon.instantiate();
}
} }
} }

View file

@ -87,18 +87,10 @@ class EditorExportPlatformMacOS : public EditorExportPlatform {
Ref<DirAccess> &dir_access, bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, Ref<DirAccess> &dir_access, bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset,
const String &p_ent_path); const String &p_ent_path);
Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name); Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name);
Error _create_pkg(const Ref<EditorExportPreset> &p_preset, const String &p_pkg_path, const String &p_app_path_name);
Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path); Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path);
bool use_codesign() const { return true; } bool use_codesign() const { return true; }
#ifdef MACOS_ENABLED
bool use_dmg() const {
return true;
}
#else
bool use_dmg() const {
return false;
}
#endif
bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const { bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const {
String pname = p_package; String pname = p_package;
@ -126,8 +118,9 @@ class EditorExportPlatformMacOS : public EditorExportPlatform {
protected: protected:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override; virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
virtual void get_export_options(List<ExportOption> *r_options) override; virtual void get_export_options(List<ExportOption> *r_options) const override;
virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const override; virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const override;
virtual String get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const override;
public: public:
virtual String get_name() const override { virtual String get_name() const override {
@ -141,15 +134,7 @@ public:
} }
virtual bool is_executable(const String &p_path) const override; virtual bool is_executable(const String &p_path) const override;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override { virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
List<String> list;
if (use_dmg()) {
list.push_back("dmg");
}
list.push_back("zip");
list.push_back("app");
return list;
}
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override; virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override; virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;

View file

@ -33,6 +33,10 @@
#include "editor/editor_settings.h" #include "editor/editor_settings.h"
#include "export_plugin.h" #include "export_plugin.h"
void register_uwp_exporter_types() {
// GDREGISTER_VIRTUAL_CLASS(EditorExportPlatformUWP);
}
void register_uwp_exporter() { void register_uwp_exporter() {
#ifdef WINDOWS_ENABLED #ifdef WINDOWS_ENABLED
EDITOR_DEF("export/uwp/signtool", ""); EDITOR_DEF("export/uwp/signtool", "");

View file

@ -31,6 +31,7 @@
#ifndef UWP_EXPORT_H #ifndef UWP_EXPORT_H
#define UWP_EXPORT_H #define UWP_EXPORT_H
void register_uwp_exporter_types();
void register_uwp_exporter(); void register_uwp_exporter();
#endif // UWP_EXPORT_H #endif // UWP_EXPORT_H

View file

@ -62,7 +62,7 @@ void EditorExportPlatformUWP::get_preset_features(const Ref<EditorExportPreset>
r_features->push_back(p_preset->get("binary_format/architecture")); r_features->push_back(p_preset->get("binary_format/architecture"));
} }
void EditorExportPlatformUWP::get_export_options(List<ExportOption> *r_options) { void EditorExportPlatformUWP::get_export_options(List<ExportOption> *r_options) const {
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));

View file

@ -427,7 +427,7 @@ public:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override; virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
virtual void get_export_options(List<ExportOption> *r_options) override; virtual void get_export_options(List<ExportOption> *r_options) const override;
virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override; virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override; virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;

View file

@ -33,6 +33,10 @@
#include "editor/editor_settings.h" #include "editor/editor_settings.h"
#include "export_plugin.h" #include "export_plugin.h"
void register_web_exporter_types() {
GDREGISTER_VIRTUAL_CLASS(EditorExportPlatformWeb);
}
void register_web_exporter() { void register_web_exporter() {
#ifndef ANDROID_ENABLED #ifndef ANDROID_ENABLED
EDITOR_DEF("export/web/http_host", "localhost"); EDITOR_DEF("export/web/http_host", "localhost");

View file

@ -31,6 +31,7 @@
#ifndef WEB_EXPORT_H #ifndef WEB_EXPORT_H
#define WEB_EXPORT_H #define WEB_EXPORT_H
void register_web_exporter_types();
void register_web_exporter(); void register_web_exporter();
#endif // WEB_EXPORT_H #endif // WEB_EXPORT_H

View file

@ -320,7 +320,7 @@ void EditorExportPlatformWeb::get_preset_features(const Ref<EditorExportPreset>
r_features->push_back("wasm32"); r_features->push_back("wasm32");
} }
void EditorExportPlatformWeb::get_export_options(List<ExportOption> *r_options) { void EditorExportPlatformWeb::get_export_options(List<ExportOption> *r_options) const {
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
@ -656,31 +656,35 @@ void EditorExportPlatformWeb::_server_thread_poll(void *data) {
} }
EditorExportPlatformWeb::EditorExportPlatformWeb() { EditorExportPlatformWeb::EditorExportPlatformWeb() {
server.instantiate(); if (EditorNode::get_singleton()) {
server_thread.start(_server_thread_poll, this); server.instantiate();
server_thread.start(_server_thread_poll, this);
#ifdef MODULE_SVG_ENABLED #ifdef MODULE_SVG_ENABLED
Ref<Image> img = memnew(Image); Ref<Image> img = memnew(Image);
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
ImageLoaderSVG img_loader; ImageLoaderSVG img_loader;
img_loader.create_image_from_string(img, _web_logo_svg, EDSCALE, upsample, false); img_loader.create_image_from_string(img, _web_logo_svg, EDSCALE, upsample, false);
logo = ImageTexture::create_from_image(img); logo = ImageTexture::create_from_image(img);
img_loader.create_image_from_string(img, _web_run_icon_svg, EDSCALE, upsample, false); img_loader.create_image_from_string(img, _web_run_icon_svg, EDSCALE, upsample, false);
run_icon = ImageTexture::create_from_image(img); run_icon = ImageTexture::create_from_image(img);
#endif #endif
Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme(); Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
if (theme.is_valid()) { if (theme.is_valid()) {
stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons")); stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons"));
} else { } else {
stop_icon.instantiate(); stop_icon.instantiate();
}
} }
} }
EditorExportPlatformWeb::~EditorExportPlatformWeb() { EditorExportPlatformWeb::~EditorExportPlatformWeb() {
server->stop(); if (server.is_valid()) {
server->stop();
}
server_quit = true; server_quit = true;
server_thread.wait_to_finish(); server_thread.wait_to_finish();
} }

View file

@ -99,7 +99,7 @@ class EditorExportPlatformWeb : public EditorExportPlatform {
public: public:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override; virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
virtual void get_export_options(List<ExportOption> *r_options) override; virtual void get_export_options(List<ExportOption> *r_options) const override;
virtual String get_name() const override; virtual String get_name() const override;
virtual String get_os_name() const override; virtual String get_os_name() const override;

View file

@ -33,6 +33,10 @@
#include "editor/export/editor_export.h" #include "editor/export/editor_export.h"
#include "export_plugin.h" #include "export_plugin.h"
void register_windows_exporter_types() {
GDREGISTER_VIRTUAL_CLASS(EditorExportPlatformWindows);
}
void register_windows_exporter() { void register_windows_exporter() {
#ifndef ANDROID_ENABLED #ifndef ANDROID_ENABLED
EDITOR_DEF("export/windows/rcedit", ""); EDITOR_DEF("export/windows/rcedit", "");

View file

@ -31,6 +31,7 @@
#ifndef WINDOWS_EXPORT_H #ifndef WINDOWS_EXPORT_H
#define WINDOWS_EXPORT_H #define WINDOWS_EXPORT_H
void register_windows_exporter_types();
void register_windows_exporter(); void register_windows_exporter();
#endif // WINDOWS_EXPORT_H #endif // WINDOWS_EXPORT_H

View file

@ -262,21 +262,72 @@ List<String> EditorExportPlatformWindows::get_binary_extensions(const Ref<Editor
return list; return list;
} }
bool EditorExportPlatformWindows::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const { String EditorExportPlatformWindows::get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const {
if (p_preset) {
if (p_name == "application/icon") {
String icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/icon"));
if (!icon_path.is_empty() && !FileAccess::exists(icon_path)) {
return TTR("Invalid icon path.");
}
} else if (p_name == "application/file_version") {
String file_version = p_preset->get("application/file_version");
if (!file_version.is_empty()) {
PackedStringArray version_array = file_version.split(".", false);
if (version_array.size() != 4 || !version_array[0].is_valid_int() ||
!version_array[1].is_valid_int() || !version_array[2].is_valid_int() ||
!version_array[3].is_valid_int() || file_version.find("-") > -1) {
return TTR("Invalid file version.");
}
}
} else if (p_name == "application/product_version") {
String product_version = p_preset->get("application/product_version");
if (!product_version.is_empty()) {
PackedStringArray version_array = product_version.split(".", false);
if (version_array.size() != 4 || !version_array[0].is_valid_int() ||
!version_array[1].is_valid_int() || !version_array[2].is_valid_int() ||
!version_array[3].is_valid_int() || product_version.find("-") > -1) {
return TTR("Invalid product version.");
}
}
}
}
return EditorExportPlatformPC::get_export_option_warning(p_preset, p_name);
}
bool EditorExportPlatformWindows::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const {
// This option is not supported by "osslsigncode", used on non-Windows host. // This option is not supported by "osslsigncode", used on non-Windows host.
if (!OS::get_singleton()->has_feature("windows") && p_option == "codesign/identity_type") { if (!OS::get_singleton()->has_feature("windows") && p_option == "codesign/identity_type") {
return false; return false;
} }
// Hide codesign.
bool codesign = p_preset->get("codesign/enable");
if (!codesign && p_option != "codesign/enable" && p_option.begins_with("codesign/")) {
return false;
}
// Hide resources.
bool mod_res = p_preset->get("application/modify_resources");
if (!mod_res && p_option != "application/modify_resources" && p_option.begins_with("application/")) {
return false;
}
// Hide SSH options.
bool ssh = p_preset->get("ssh_remote_deploy/enabled");
if (!ssh && p_option != "ssh_remote_deploy/enabled" && p_option.begins_with("ssh_remote_deploy/")) {
return false;
}
return true; return true;
} }
void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_options) { void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_options) const {
EditorExportPlatformPC::get_export_options(r_options); EditorExportPlatformPC::get_export_options(r_options);
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64"), "x86_64")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64"), "x86_64"));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/identity_type", PROPERTY_HINT_ENUM, "Select automatically,Use PKCS12 file (specify *.PFX/*.P12 file),Use certificate store (specify SHA1 hash)"), 0)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/identity_type", PROPERTY_HINT_ENUM, "Select automatically,Use PKCS12 file (specify *.PFX/*.P12 file),Use certificate store (specify SHA-1 hash)"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/password", PROPERTY_HINT_PASSWORD), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/password", PROPERTY_HINT_PASSWORD), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true));
@ -285,12 +336,12 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/description"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/description"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray())); r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/modify_resources"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/modify_resources"), true, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico,*.png,*.webp,*.svg"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico,*.png,*.webp,*.svg"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/console_wrapper_icon", PROPERTY_HINT_FILE, "*.ico,*.png,*.webp,*.svg"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/console_wrapper_icon", PROPERTY_HINT_FILE, "*.ico,*.png,*.webp,*.svg"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), "", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/company_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Company Name"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/company_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Company Name"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_description"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_description"), ""));
@ -311,7 +362,7 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
"Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue\n" "Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue\n"
"Remove-Item -Recurse -Force '{temp_dir}'"; "Remove-Item -Recurse -Force '{temp_dir}'";
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "ssh_remote_deploy/enabled"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "ssh_remote_deploy/enabled"), false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/host"), "user@host_ip")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/host"), "user@host_ip"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/port"), "22")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/port"), "22"));
@ -632,30 +683,17 @@ bool EditorExportPlatformWindows::has_valid_project_configuration(const Ref<Edit
String err = ""; String err = "";
bool valid = true; bool valid = true;
String icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/icon")); List<ExportOption> options;
if (!icon_path.is_empty() && !FileAccess::exists(icon_path)) { get_export_options(&options);
err += TTR("Invalid icon path:") + " " + icon_path + "\n"; for (const EditorExportPlatform::ExportOption &E : options) {
} if (get_export_option_visibility(p_preset.ptr(), E.option.name)) {
String warn = get_export_option_warning(p_preset.ptr(), E.option.name);
// Only non-negative integers can exist in the version string. if (!warn.is_empty()) {
err += warn + "\n";
String file_version = p_preset->get("application/file_version"); if (E.required) {
if (!file_version.is_empty()) { valid = false;
PackedStringArray version_array = file_version.split(".", false); }
if (version_array.size() != 4 || !version_array[0].is_valid_int() || }
!version_array[1].is_valid_int() || !version_array[2].is_valid_int() ||
!version_array[3].is_valid_int() || file_version.find("-") > -1) {
err += TTR("Invalid file version:") + " " + file_version + "\n";
}
}
String product_version = p_preset->get("application/product_version");
if (!product_version.is_empty()) {
PackedStringArray version_array = product_version.split(".", false);
if (version_array.size() != 4 || !version_array[0].is_valid_int() ||
!version_array[1].is_valid_int() || !version_array[2].is_valid_int() ||
!version_array[3].is_valid_int() || product_version.find("-") > -1) {
err += TTR("Invalid product version:") + " " + product_version + "\n";
} }
} }
@ -957,22 +995,24 @@ Error EditorExportPlatformWindows::run(const Ref<EditorExportPreset> &p_preset,
} }
EditorExportPlatformWindows::EditorExportPlatformWindows() { EditorExportPlatformWindows::EditorExportPlatformWindows() {
if (EditorNode::get_singleton()) {
#ifdef MODULE_SVG_ENABLED #ifdef MODULE_SVG_ENABLED
Ref<Image> img = memnew(Image); Ref<Image> img = memnew(Image);
const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
ImageLoaderSVG img_loader; ImageLoaderSVG img_loader;
img_loader.create_image_from_string(img, _windows_logo_svg, EDSCALE, upsample, false); img_loader.create_image_from_string(img, _windows_logo_svg, EDSCALE, upsample, false);
set_logo(ImageTexture::create_from_image(img)); set_logo(ImageTexture::create_from_image(img));
img_loader.create_image_from_string(img, _windows_run_icon_svg, EDSCALE, upsample, false); img_loader.create_image_from_string(img, _windows_run_icon_svg, EDSCALE, upsample, false);
run_icon = ImageTexture::create_from_image(img); run_icon = ImageTexture::create_from_image(img);
#endif #endif
Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme(); Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
if (theme.is_valid()) { if (theme.is_valid()) {
stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons")); stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons"));
} else { } else {
stop_icon.instantiate(); stop_icon.instantiate();
}
} }
} }

View file

@ -37,6 +37,8 @@
#include "editor/export/editor_export_platform_pc.h" #include "editor/export/editor_export_platform_pc.h"
class EditorExportPlatformWindows : public EditorExportPlatformPC { class EditorExportPlatformWindows : public EditorExportPlatformPC {
GDCLASS(EditorExportPlatformWindows, EditorExportPlatformPC);
struct SSHCleanupCommand { struct SSHCleanupCommand {
String host; String host;
String port; String port;
@ -70,10 +72,12 @@ public:
virtual Error modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) override; virtual Error modify_template(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) override;
virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) override; virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) override;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override; virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
virtual void get_export_options(List<ExportOption> *r_options) override; virtual void get_export_options(List<ExportOption> *r_options) const override;
virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override; virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override; virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const override; virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const override;
virtual String get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const override;
virtual String get_template_file_name(const String &p_target, const String &p_arch) const override; virtual String get_template_file_name(const String &p_target, const String &p_arch) const override;
virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override; virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override;