diff --git a/doc/classes/EditorExportPlatformAndroid.xml b/doc/classes/EditorExportPlatformAndroid.xml new file mode 100644 index 000000000000..570e8f01f166 --- /dev/null +++ b/doc/classes/EditorExportPlatformAndroid.xml @@ -0,0 +1,581 @@ + + + + Exporter for Android. + + + + + $DOCS_URL/tutorials/export/exporting_for_android.html + $DOCS_URL/tutorials/export/android_custom_build.html + + + + 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]. + + + 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. + + + Base64 encoded RSA public key for your publisher account, available from the profile page on the "Play Console". + + + If [code]true[/code], [code]arm64[/code] binaries are included into exported project. + + + If [code]true[/code], [code]arm32[/code] binaries are included into exported project. + + + If [code]true[/code], [code]x86_32[/code] binaries are included into exported project. + + + If [code]true[/code], [code]x86_64[/code] binaries are included into exported project. + + + A list of additional command line arguments, exported project will receive when started. + + + Path to the custom export template. If left empty, default template is used. + + + Path to the custom export template. If left empty, default template is used. + + + Export format for Gradle build. + + + Minimal Android SDK version for Gradle build. + + + Target Android SDK version for Gradle build. + + + If [code]true[/code], Gradle build is used instead of pre-built APK. + + + If [code]true[/code], OpenGL ES debug context will be created (additional runtime checking, validation, and logging). + + + Path of the debug keystore file. + + + Password for the debug keystore file. + + + User name for the debug keystore file. + + + Path of the release keystore file. + + + Password for the release keystore file. + + + User name for the release keystore file. + + + Background layer of the application adaptive icon file. + + + Foreground layer of the application adaptive icon file. + + + Application icon file. If left empty, project icon is used instead. + + + Application category for the Play Store. + + + If [code]true[/code], task initiated by main activity will be excluded from the list of recently used applications. + + + Name of the application. + + + If [code]true[/code], when the user uninstalls an app, a prompt to keep the app's data will be shown. + + + If [code]true[/code], package signing is enabled. + + + 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]). + + + 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]. + + + Allows access to the approximate location information. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCESS_COARSE_LOCATION]ACCESS_COARSE_LOCATION[/url]. + + + Allows access to the precise location information. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCESS_FINE_LOCATION]ACCESS_FINE_LOCATION[/url]. + + + 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]. + + + Allows an application to create mock location providers for testing. + + + Allows access to the information about networks. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCESS_NETWORK_STATE]ACCESS_NETWORK_STATE[/url]. + + + Allows an application to use SurfaceFlinger's low level features. + + + 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]. + + + Allows applications to call into AccountAuthenticators. See [url=https://developer.android.com/reference/android/Manifest.permission#ACCOUNT_MANAGER]ACCOUNT_MANAGER[/url]. + + + Allows an application to add voicemails into the system. See [url=https://developer.android.com/reference/android/Manifest.permission#ADD_VOICEMAIL]ADD_VOICEMAIL[/url]. + + + Allows an application to act as an AccountAuthenticator for the AccountManager. + + + Allows an application to collect battery statistics. Sett [url=https://developer.android.com/reference/android/Manifest.permission#BATTERY_STATS]BATTERY_STATS[/url]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + Allows applications to connect to paired bluetooth devices. See [url=https://developer.android.com/reference/android/Manifest.permission#BLUETOOTH]BLUETOOTH[/url]. + + + Allows applications to discover and pair bluetooth devices. See [url=https://developer.android.com/reference/android/Manifest.permission#BLUETOOTH_ADMIN]BLUETOOTH_ADMIN[/url]. + + + 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]. + + + Required to be able to disable the device (very dangerous!). + + + 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]. + + + Allows an application to broadcast an SMS receipt notification. See [url=https://developer.android.com/reference/android/Manifest.permission#BROADCAST_SMS]BROADCAST_SMS[/url]. + + + Allows an application to broadcast sticky intents. See [url=https://developer.android.com/reference/android/Manifest.permission#BROADCAST_STICKY]BROADCAST_STICKY[/url]. + + + 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]. + + + 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]. + + + 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]. + + + Required to be able to access the camera device. See [url=https://developer.android.com/reference/android/Manifest.permission#CAMERA]CAMERA[/url]. + + + Allows an application to capture audio output. See [url=https://developer.android.com/reference/android/Manifest.permission#CAPTURE_AUDIO_OUTPUT]CAPTURE_AUDIO_OUTPUT[/url]. + + + Allows an application to capture secure video output. + + + Allows an application to capture video output. + + + 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]. + + + 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]. + + + Allows applications to change network connectivity state. See [url=https://developer.android.com/reference/android/Manifest.permission#CHANGE_NETWORK_STATE]CHANGE_NETWORK_STATE[/url]. + + + 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]. + + + 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]. + + + 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]. + + + Allows an application to clear user data. + + + 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]. + + + Array of custom permission strings. + + + Deprecated. + + + Allows an application to delete packages. See [url=https://developer.android.com/reference/android/Manifest.permission#DELETE_PACKAGES]DELETE_PACKAGES[/url]. + + + Allows low-level access to power management. + + + Allows applications to RW to diagnostic resources. See [url=https://developer.android.com/reference/android/Manifest.permission#DIAGNOSTIC]DIAGNOSTIC[/url]. + + + 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]. + + + Allows an application to retrieve state dump information from system services. See [url=https://developer.android.com/reference/android/Manifest.permission#DUMP]DUMP[/url]. + + + 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]. + + + 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]. + + + Allows access to the flashlight. + + + Allows an application to force a BACK operation on whatever is the top activity. + + + 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]. + + + 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]. + + + Deprecated in API level 21. + + + Allows an application to retrieve private information about the current top activity. + + + 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]. + + + Allows access to hardware peripherals. + + + Allows an application to inject user events (keys, touch, trackball) into the event stream and deliver them to ANY window. + + + 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]. + + + Allows an application to install packages. See [url=https://developer.android.com/reference/android/Manifest.permission#INSTALL_PACKAGES]INSTALL_PACKAGES[/url]. + + + Allows an application to install a shortcut in Launcher. See [url=https://developer.android.com/reference/android/Manifest.permission#INSTALL_SHORTCUT]INSTALL_SHORTCUT[/url]. + + + Allows an application to open windows that are for use by parts of the system user interface. + + + Allows applications to open network sockets. See [url=https://developer.android.com/reference/android/Manifest.permission#INTERNET]INTERNET[/url]. + + + 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]. + + + 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]. + + + Allows an application to manage the list of accounts in the AccountManager. + + + Allows an application to manage (create, destroy, Z-order) application tokens in the window manager. + + + 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]. + + + 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]. + + + See [url=https://developer.android.com/reference/android/Manifest.permission#MASTER_CLEAR]MASTER_CLEAR[/url]. + + + 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]. + + + 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]. + + + 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]. + + + Allows formatting file systems for removable storage. See [url=https://developer.android.com/reference/android/Manifest.permission#MOUNT_FORMAT_FILESYSTEMS]MOUNT_FORMAT_FILESYSTEMS[/url]. + + + 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]. + + + Allows applications to perform I/O operations over NFC. See [url=https://developer.android.com/reference/android/Manifest.permission#NFC]NFC[/url]. + + + Allow an application to make its activities persistent. + Deprecated in API level 15. + + + 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. + + + 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]. + + + 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]. + + + 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]. + + + 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. + + + Allows an application to take screen shots and more generally get access to the frame buffer data. + + + Allows an application to read (but not write) the user's browsing history and bookmarks. + + + Deprecated in API level 16. + + + 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]. + + + Allows read only access to phone state. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_PHONE_STATE]READ_PHONE_STATE[/url]. + + + Allows an application to read the user's personal profile data. + + + Allows an application to read SMS messages. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_SMS]READ_SMS[/url]. + + + Allows an application to read from the user's social stream. + + + Allows applications to read the sync settings. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_SYNC_SETTINGS]READ_SYNC_SETTINGS[/url]. + + + Allows applications to read the sync stats. See [url=https://developer.android.com/reference/android/Manifest.permission#READ_SYNC_STATS]READ_SYNC_STATS[/url]. + + + Allows an application to read the user dictionary. + + + Required to be able to reboot the device. See [url=https://developer.android.com/reference/android/Manifest.permission#REBOOT]REBOOT[/url]. + + + 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]. + + + Allows an application to monitor incoming MMS messages. See [url=https://developer.android.com/reference/android/Manifest.permission#RECEIVE_MMS]RECEIVE_MMS[/url]. + + + Allows an application to receive SMS messages. See [url=https://developer.android.com/reference/android/Manifest.permission#RECEIVE_SMS]RECEIVE_SMS[/url]. + + + 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]. + + + Allows an application to record audio. See [url=https://developer.android.com/reference/android/Manifest.permission#RECORD_AUDIO]RECORD_AUDIO[/url]. + + + 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]. + + + Deprecated in API level 15. + + + 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]. + + + Allows an application to send SMS messages. See [url=https://developer.android.com/reference/android/Manifest.permission#SEND_SMS]SEND_SMS[/url]. + + + Allows an application to watch and control how activities are started globally in the system. + + + 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]. + + + 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]. + + + 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]. + + + Configure an application for debugging. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_DEBUG_APP]SET_DEBUG_APP[/url]. + + + Allows low-level access to setting the orientation (actually rotation) of the screen. + + + Allows low-level access to setting the pointer speed. + + + Deprecated in API level 15. + + + 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]. + + + Allows applications to set the system time directly. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_TIME]SET_TIME[/url]. + + + 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]. + + + Allows applications to set the wallpaper. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_WALLPAPER]SET_WALLPAPER[/url]. + + + Allows applications to set the wallpaper hints. See [url=https://developer.android.com/reference/android/Manifest.permission#SET_WALLPAPER_HINTS]SET_WALLPAPER_HINTS[/url]. + + + 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]. + + + 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]. + + + Allows an application to allow access the subscribed feeds ContentProvider. + + + Deprecated. + + + 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]. + + + Allows using the device's IR transmitter, if available. See [url=https://developer.android.com/reference/android/Manifest.permission#TRANSMIT_IR]TRANSMIT_IR[/url]. + + + Deprecated. + + + Allows an application to update device statistics. See [url=https://developer.android.com/reference/android/Manifest.permission#UPDATE_DEVICE_STATS]UPDATE_DEVICE_STATS[/url]. + + + Allows an application to request authtokens from the AccountManager. + + + Allows an application to use SIP service. See [url=https://developer.android.com/reference/android/Manifest.permission#USE_SIP]USE_SIP[/url]. + + + Allows access to the vibrator. See [url=https://developer.android.com/reference/android/Manifest.permission#VIBRATE]VIBRATE[/url]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + Allows an application to modify the Google service map. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_GSERVICES]WRITE_GSERVICES[/url]. + + + Allows an application to write (but not read) the user's browsing history and bookmarks. + + + Allows an application to write (but not read) the user's personal profile data. + + + 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]. + + + 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]. + + + Allows an application to write SMS messages. + + + Allows an application to write (but not read) the user's social stream data. + + + Allows applications to write the sync settings. See [url=https://developer.android.com/reference/android/Manifest.permission#WRITE_SYNC_SETTINGS]WRITE_SYNC_SETTINGS[/url]. + + + Allows an application to write to the user dictionary. + + + If [code]true[/code], hides navigation and status bar. + + + Indicates whether the application supports larger screen form-factors. + + + Indicates whether an application supports the "normal" screen form-factors. + + + Indicates whether the application supports smaller screen form-factors. + + + Indicates whether the application supports extra large screen form-factors. + + + If [code]true[/code], allows the application to participate in the backup and restore infrastructure. + + + Machine-readable application version. + + + Application version visible to the user. + + + + + + + + + + + diff --git a/doc/classes/EditorExportPlatformIOS.xml b/doc/classes/EditorExportPlatformIOS.xml new file mode 100644 index 000000000000..249ee4323c7b --- /dev/null +++ b/doc/classes/EditorExportPlatformIOS.xml @@ -0,0 +1,181 @@ + + + + Exporter for iOS. + + + + + $DOCS_URL/tutorials/export/exporting_for_ios.html + + + + 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]. + + + 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]). + + + The "Full Name", "Common Name" or SHA-1 hash of the signing identity used for debug export. + + + The "Full Name", "Common Name" or SHA-1 hash of the signing identity used for release export. + + + Application distribution target (debug export). + + + Application distribution target (release export). + + + Interpolation method used to resize application icon. + + + Interpolation method used to resize launch screen images. + + + 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]. + + + 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]. + + + Application version visible to the user, can only contain numeric characters ([code]0-9[/code]) and periods ([code].[/code]). + + + A four-character creator code that is specific to the bundle. Optional. + + + Supported device family. + + + 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]). + + + If [code]true[/code], [code]arm64[/code] binaries are included into exported project. + + + 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]. + + + If [code]true[/code], push notifications are enabled. See [url=https://developer.apple.com/support/required-device-capabilities/]Required Device Capabilities[/url]. + + + Path to the custom export template. If left empty, default template is used. + + + Path to the custom export template. If left empty, default template is used. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + Application launch screen image file, if left empty project splash screen is used instead. + + + Application launch screen image file, if left empty project splash screen is used instead. + + + Application launch screen image file, if left empty project splash screen is used instead. + + + Application launch screen image file, if left empty project splash screen is used instead. + + + Application launch screen image file, if left empty project splash screen is used instead. + + + Application launch screen image file, if left empty project splash screen is used instead. + + + Application launch screen image file, if left empty project splash screen is used instead. + + + Application launch screen image file, if left empty project splash screen is used instead. + + + Application launch screen image file, if left empty project splash screen is used instead. + + + Application launch screen image file, if left empty project splash screen is used instead. + + + Application launch screen image file, if left empty project splash screen is used instead. + + + A message displayed when requesting access to the device's camera (in English). + + + A message displayed when requesting access to the device's camera (localized). + + + A message displayed when requesting access to the device's microphone (in English). + + + A message displayed when requesting access to the device's microphone (localized). + + + A message displayed when requesting access to the user's photo library (in English). + + + A message displayed when requesting access to the user's photo library (localized). + + + A custom background color of the storyboard launch screen. + + + Application launch screen image file (2x DPI), if left empty project splash screen is used instead. + + + Application launch screen image file (3x DPI), if left empty project splash screen is used instead. + + + Launch screen image scaling mode. + + + 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. + + + If [code]true[/code], storyboard launch screen is used instead of launch screen images. + + + 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]. + + + 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]. + + + diff --git a/doc/classes/EditorExportPlatformLinuxBSD.xml b/doc/classes/EditorExportPlatformLinuxBSD.xml new file mode 100644 index 000000000000..4ab24649297b --- /dev/null +++ b/doc/classes/EditorExportPlatformLinuxBSD.xml @@ -0,0 +1,73 @@ + + + + Exporter for Linux/BSD. + + + + + $DOCS_URL/tutorials/export/exporting_for_linux.html + + + + 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. + + + If [code]true[/code], project resources are embedded into the executable. + + + Path to the custom export template. If left empty, default template is used. + + + Path to the custom export template. If left empty, default template is used. + + + If [code]true[/code], a console wrapper script is exported alongside the main executable, which allows running the project with enabled console output. + + + 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. + + + Enables remote deploy using SSH/SCP. + + + Array of the additional command line arguments passed to the SCP. + + + Array of the additional command line arguments passed to the SSH. + + + Remote host SSH user name and address, in [code]user@address[/code] format. + + + Remote host SSH port number. + + + 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. + + + If [code]true[/code], project textures are exported in the BPTC format. + + + If [code]true[/code], project textures are exported in the ETC format. + + + If [code]true[/code], project textures are exported in the ETC2 format. + + + If [code]true[/code], project textures are exported in the S3TC format. + + + diff --git a/doc/classes/EditorExportPlatformMacOS.xml b/doc/classes/EditorExportPlatformMacOS.xml new file mode 100644 index 000000000000..1a9fd431c7bc --- /dev/null +++ b/doc/classes/EditorExportPlatformMacOS.xml @@ -0,0 +1,291 @@ + + + + Exporter for macOS. + + + + + $DOCS_URL/tutorials/export/exporting_for_macos.html + $DOCS_URL/tutorials//export/running_on_macos.html + + + + Application category for the App Store. + + + 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]). + + + Copyright notice for the bundle visible to the user (in English). + + + Copyright notice for the bundle visible to the user (localized). + + + Application icon file. If left empty, project icon is used instead. + + + Interpolation method used to resize application icon. + + + 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]). + + + Application version visible to the user, can only contain numeric characters ([code]0-9[/code]) and periods ([code].[/code]). + + + A four-character creator code that is specific to the bundle. Optional. + + + 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]). + + + 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. + + + 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]. + + + PKCS #12 certificate file used to sign [code].app[/code] bundle. + + + Password for the certificate file used to sign [code].app[/code] bundle. + + + Tool to use for code signing. + + + Array of the additional command line arguments passed to the code signing tool. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + Custom entitlements [code].plist[/code] file, if specified the rest of entitlements in the export config are ignored. + + + 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]. + + + 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]. + + + 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]. + + + 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]. + + + The "Full Name", "Common Name" or SHA-1 hash of the signing identity used to sign [code].app[/code] bundle. + + + 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. + + + 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]. + + + Path to the custom export template. If left empty, default template is used. + + + Path to the custom export template. If left empty, default template is used. + + + If enabled, a script file that can be used to run the application with console output is created alongside the exported application. + + + 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. + + + Application distribution target. + + + Apple App Store Connect API issuer key file. + + + Apple App Store Connect API issuer key ID. + + + Apple App Store Connect API issuer UUID. + + + Apple ID account name (email address). + + + Apple ID app-specific password. + + + Tool to use for notarization. + + + A message displayed when requesting access to the user's contacts (in English). + + + A message displayed when requesting access to the user's contacts (localized). + + + A message displayed when requesting access to the user's calendar data (in English). + + + A message displayed when requesting access to the user's calendar data (localized). + + + A message displayed when requesting access to the device's camera (in English). + + + A message displayed when requesting access to the device's camera (localized). + + + A message displayed when requesting access to the user's "Desktop" folder (in English). + + + A message displayed when requesting access to the user's "Desktop" folder (localized). + + + A message displayed when requesting access to the user's "Documents" folder (in English). + + + A message displayed when requesting access to the user's "Documents" folder (localized). + + + A message displayed when requesting access to the user's "Downloads" folder (in English). + + + A message displayed when requesting access to the user's "Downloads" folder (localized). + + + A message displayed when requesting access to the user's location information (in English). + + + A message displayed when requesting access to the user's location information (localized). + + + A message displayed when requesting access to the device's microphone (in English). + + + A message displayed when requesting access to the device's microphone (localized). + + + A message displayed when requesting access to the user's network drives (in English). + + + A message displayed when requesting access to the user's network drives (localized). + + + A message displayed when requesting access to the user's photo library (in English). + + + A message displayed when requesting access to the user's photo library (localized). + + + A message displayed when requesting access to the user's removable drives (in English). + + + A message displayed when requesting access to the user's removable drives (localized). + + + 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. + + + Enables remote deploy using SSH/SCP. + + + Array of the additional command line arguments passed to the SCP. + + + Array of the additional command line arguments passed to the SSH. + + + Remote host SSH user name and address, in [code]user@address[/code] format. + + + Remote host SSH port number. + + + 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. + + + macOS build number used to build application executable. + + + macOS SDK build number used to build application executable. + + + macOS SDK name used to build application executable. + + + macOS SDK version used to build application executable in the [code]major.minor[/code] format. + + + Xcode build number used to build application executable. + + + Xcode version used to build application executable. + + + diff --git a/doc/classes/EditorExportPlatformPC.xml b/doc/classes/EditorExportPlatformPC.xml new file mode 100644 index 000000000000..44df4f1884f7 --- /dev/null +++ b/doc/classes/EditorExportPlatformPC.xml @@ -0,0 +1,10 @@ + + + + Base class for the desktop platform exporter (Windows and Linux/BSD). + + + + + + diff --git a/doc/classes/EditorExportPlatformWeb.xml b/doc/classes/EditorExportPlatformWeb.xml new file mode 100644 index 000000000000..6e5a2ac078f4 --- /dev/null +++ b/doc/classes/EditorExportPlatformWeb.xml @@ -0,0 +1,54 @@ + + + + Exporter for the Web. + + + + + $DOCS_URL/tutorials/export/exporting_for_web.html + + + + Path to the custom export template. If left empty, default template is used. + + + Path to the custom export template. If left empty, default template is used. + + + The canvas resize policy determines how the canvas should be resized by Godot. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/classes/EditorExportPlatformWindows.xml b/doc/classes/EditorExportPlatformWindows.xml new file mode 100644 index 000000000000..fee8a118bc56 --- /dev/null +++ b/doc/classes/EditorExportPlatformWindows.xml @@ -0,0 +1,133 @@ + + + + Exporter for Windows. + + + + + $DOCS_URL/tutorials/export/exporting_for_windows.html + + + + Company that produced the application. Required. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url]. + + + Console wrapper icon file. If left empty, application icon is used instead. + + + 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]. + + + File description to be presented to users. Required. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url]. + + + Version number of the file. Required. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url]. + + + Application icon file. If left empty, project icon is used instead. + + + Interpolation method used to resize application icon. + + + If enabled, icon and metadata of the exported executable is set according to the other [code]application/*[/code] values. + + + Name of the application. Required. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url]. + + + Application version visible to the user. Required. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url]. + + + 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]. + + + 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. + + + If [code]true[/code], project resources are embedded into the executable. + + + 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]. + + + Description of the signed content. See [url=https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe]Sign Tool[/url]. + + + Digest algorithm to use for creating signature. See [url=https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe]Sign Tool[/url]. + + + If [code]true[/code], executable signing is enabled. + + + 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]. + + + Type of identity to use. See [url=https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe]Sign Tool[/url]. + + + 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]. + + + 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]. + + + 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]. + + + Path to the custom export template. If left empty, default template is used. + + + Path to the custom export template. If left empty, default template is used. + + + If [code]true[/code], a console wrapper executable is exported alongside the main executable, which allows running the project with enabled console output. + + + 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. + + + Enables remote deploy using SSH/SCP. + + + Array of the additional command line arguments passed to the SCP. + + + Array of the additional command line arguments passed to the SSH. + + + Remote host SSH user name and address, in [code]user@address[/code] format. + + + Remote host SSH port number. + + + 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. + + + If [code]true[/code], project textures are exported in the BPTC format. + + + If [code]true[/code], project textures are exported in the ETC format. + + + If [code]true[/code], project textures are exported in the ETC2 format. + + + If [code]true[/code], project textures are exported in the S3TC format. + + + diff --git a/editor/SCsub b/editor/SCsub index d1781487ca7c..20bfa78c72a4 100644 --- a/editor/SCsub +++ b/editor/SCsub @@ -26,7 +26,7 @@ def _make_doc_data_class_path(to_path): if env.editor_build: # 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" for e in env.platform_exporters: # Glob all .cpp files in export folder @@ -35,6 +35,10 @@ if env.editor_build: reg_exporters += "\tregister_" + e + "_exporter();\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" # NOTE: It is safe to generate this file here, since this is still executed serially diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index d71ef78d8820..110fa941afa7 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -40,6 +40,7 @@ #include "core/string/translation.h" #include "core/version.h" #include "editor/editor_settings.h" +#include "editor/export/editor_export.h" #include "scene/resources/theme.h" #include "scene/theme/theme_db.h" @@ -396,6 +397,16 @@ void DocTools::generate(bool p_basic_types) { } else if (name == "ProjectSettings") { ProjectSettings::get_singleton()->get_property_list(&properties); own_properties = properties; + } else if (name.begins_with("EditorExportPlatform") && ClassDB::can_instantiate(name)) { + Ref platform = Object::cast_to(ClassDB::instantiate(name)); + if (platform.is_valid()) { + List options; + platform->get_export_options(&options); + for (const EditorExportPlatform::ExportOption &E : options) { + properties.push_back(E.option); + } + own_properties = properties; + } } else { ClassDB::get_property_list(name, &properties); 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") { // 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)) { diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index cd762002b2d7..bd975622aa3c 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -259,7 +259,7 @@ void EditorProperty::_notification(int p_what) { } 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")); } else { 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); } + 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()); bool new_can_revert = EditorPropertyRevert::can_property_revert(object, property, ¤t) && !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) { emit_signal(SNAME("property_can_revert_changed"), property, new_can_revert); } + draw_prop_warning = new_warning; can_revert = new_can_revert; pinned = new_pinned; 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); 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 { 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); return help_bit; } 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) { @@ -1158,7 +1174,7 @@ void EditorInspectorCategory::_notification(int p_what) { } 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 { diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 76fe929ce440..b3709e93f42a 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -79,6 +79,7 @@ private: bool checkable = false; bool checked = false; bool draw_warning = false; + bool draw_prop_warning = false; bool keying = false; bool deletable = false; diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp index a93be506ee2f..4ae8b262c177 100644 --- a/editor/editor_property_name_processor.cpp +++ b/editor/editor_property_name_processor.cpp @@ -125,6 +125,8 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() { capitalize_string_remaps["ao"] = "AO"; capitalize_string_remaps["api"] = "API"; 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["armeabi-v7a"] = "armeabi-v7a"; capitalize_string_remaps["arvr"] = "ARVR"; @@ -221,6 +223,8 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() { capitalize_string_remaps["pck"] = "PCK"; capitalize_string_remaps["png"] = "PNG"; 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["pvs"] = "PVS"; capitalize_string_remaps["rcedit"] = "rcedit"; @@ -229,6 +233,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() { capitalize_string_remaps["rid"] = "RID"; capitalize_string_remaps["rmb"] = "RMB"; capitalize_string_remaps["rpc"] = "RPC"; + capitalize_string_remaps["rv64"] = "rv64"; capitalize_string_remaps["s3tc"] = "S3TC"; capitalize_string_remaps["scp"] = "SCP"; capitalize_string_remaps["sdf"] = "SDF"; @@ -274,6 +279,8 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() { capitalize_string_remaps["wine"] = "wine"; capitalize_string_remaps["wifi"] = "Wi-Fi"; 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["xray"] = "X-Ray"; capitalize_string_remaps["xy"] = "XY"; diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h index 05d985eb6ae3..21d871990224 100644 --- a/editor/export/editor_export_platform.h +++ b/editor/export/editor_export_platform.h @@ -143,11 +143,13 @@ public: PropertyInfo option; Variant default_value; 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), default_value(p_default), - update_visibility(p_update_visibility) { + update_visibility(p_update_visibility), + required(p_required) { } ExportOption() {} }; @@ -196,9 +198,10 @@ public: virtual bool fill_log_messages(RichTextLabel *p_log, Error p_err); - virtual void get_export_options(List *r_options) = 0; + virtual void get_export_options(List *r_options) const = 0; virtual bool should_update_export_options() { return false; } - virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap &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_name() const = 0; diff --git a/editor/export/editor_export_platform_pc.cpp b/editor/export/editor_export_platform_pc.cpp index f62b22881c26..fcc974f1aa32 100644 --- a/editor/export/editor_export_platform_pc.cpp +++ b/editor/export/editor_export_platform_pc.cpp @@ -50,7 +50,7 @@ void EditorExportPlatformPC::get_preset_features(const Ref & r_features->push_back(p_preset->get("binary_format/architecture")); } -void EditorExportPlatformPC::get_export_options(List *r_options) { +void EditorExportPlatformPC::get_export_options(List *r_options) const { 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/release", PROPERTY_HINT_GLOBAL_FILE, ext_filter), "")); diff --git a/editor/export/editor_export_platform_pc.h b/editor/export/editor_export_platform_pc.h index 8c24f2fc6893..b49aa09e079e 100644 --- a/editor/export/editor_export_platform_pc.h +++ b/editor/export/editor_export_platform_pc.h @@ -46,7 +46,7 @@ private: public: virtual void get_preset_features(const Ref &p_preset, List *r_features) const override; - virtual void get_export_options(List *r_options) override; + virtual void get_export_options(List *r_options) const override; virtual String get_name() const override; virtual String get_os_name() const override; diff --git a/editor/export/editor_export_preset.cpp b/editor/export/editor_export_preset.cpp index 6beef623bccb..ac9347960525 100644 --- a/editor/export/editor_export_preset.cpp +++ b/editor/export/editor_export_preset.cpp @@ -52,9 +52,17 @@ bool EditorExportPreset::_get(const StringName &p_name, Variant &r_ret) const { 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 *p_list) const { 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); } } diff --git a/editor/export/editor_export_preset.h b/editor/export/editor_export_preset.h index db139d8860bf..003e3c05a352 100644 --- a/editor/export/editor_export_preset.h +++ b/editor/export/editor_export_preset.h @@ -90,6 +90,10 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List *p_list) const; + String _get_property_warning(const StringName &p_name) const; + + static void _bind_methods(); + public: Ref get_platform() const; diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp index 95c79ab58c78..114d927c4d59 100644 --- a/editor/export/project_export.cpp +++ b/editor/export/project_export.cpp @@ -241,6 +241,7 @@ void ProjectExportDialog::_edit_preset(int p_index) { export_path->update_property(); runnable->set_disabled(false); runnable->set_pressed(current->is_runnable()); + parameters->set_object_class(current->get_platform()->get_class_name()); parameters->edit(current.ptr()); export_filter->select(current->get_export_filter()); @@ -1161,6 +1162,7 @@ ProjectExportDialog::ProjectExportDialog() { parameters->set_name(TTR("Options")); parameters->set_v_size_flags(Control::SIZE_EXPAND_FILL); 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)); EditorExport::get_singleton()->connect("export_presets_updated", callable_mp(this, &ProjectExportDialog::_force_update_current_preset_parameters)); diff --git a/editor/register_editor_types.cpp b/editor/register_editor_types.cpp index 66d6eb49230c..724d435f68ec 100644 --- a/editor/register_editor_types.cpp +++ b/editor/register_editor_types.cpp @@ -44,6 +44,7 @@ #include "editor/editor_settings.h" #include "editor/editor_translation_parser.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/export/editor_export_platform_pc.h" #include "editor/filesystem_dock.h" #include "editor/gui/editor_file_dialog.h" #include "editor/gui/editor_spin_slider.h" @@ -108,6 +109,7 @@ #include "editor/plugins/version_control_editor_plugin.h" #include "editor/plugins/visual_shader_editor_plugin.h" #include "editor/plugins/voxel_gi_editor_plugin.h" +#include "editor/register_exporters.h" void register_editor_types() { ResourceLoader::set_timestamp_on_load(true); @@ -134,6 +136,8 @@ void register_editor_types() { GDREGISTER_ABSTRACT_CLASS(EditorInterface); GDREGISTER_CLASS(EditorExportPlugin); GDREGISTER_ABSTRACT_CLASS(EditorExportPlatform); + GDREGISTER_ABSTRACT_CLASS(EditorExportPlatformPC); + register_exporter_types(); GDREGISTER_CLASS(EditorResourceConversionPlugin); GDREGISTER_CLASS(EditorSceneFormatImporter); GDREGISTER_CLASS(EditorScenePostImportPlugin); diff --git a/editor/register_exporters.h b/editor/register_exporters.h index b210f72cce95..5faed5652586 100644 --- a/editor/register_exporters.h +++ b/editor/register_exporters.h @@ -31,6 +31,7 @@ #ifndef REGISTER_EXPORTERS_H #define REGISTER_EXPORTERS_H +void register_exporter_types(); void register_exporters(); #endif // REGISTER_EXPORTERS_H diff --git a/misc/dist/macos_template.app/Contents/Info.plist b/misc/dist/macos_template.app/Contents/Info.plist index 542146cdb81e..40966d2ceda2 100644 --- a/misc/dist/macos_template.app/Contents/Info.plist +++ b/misc/dist/macos_template.app/Contents/Info.plist @@ -24,6 +24,20 @@ $signature CFBundleVersion $version + DTPlatformBuild + $platfbuild + DTPlatformName + macosx + DTPlatformVersion + $sdkver + DTSDKBuild + $sdkbuild + DTSDKName + $sdkname + DTXcode + $xcodever + DTXcodeBuild + $xcodebuild $usage_descriptions NSHumanReadableCopyright $copyright @@ -36,11 +50,11 @@ $usage_descriptions LSApplicationCategoryType public.app-category.$app_category LSMinimumSystemVersion - 10.12 + $min_version LSMinimumSystemVersionByArchitecture x86_64 - 10.12 + $min_version NSHighResolutionCapable $highres diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index d7fe89d97dc8..1e048100d175 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -35,6 +35,10 @@ #include "editor/export/editor_export.h" #include "export_plugin.h" +void register_android_exporter_types() { + GDREGISTER_VIRTUAL_CLASS(EditorExportPlatformAndroid); +} + void register_android_exporter() { #ifndef ANDROID_ENABLED EDITOR_DEF("export/android/android_sdk_path", ""); diff --git a/platform/android/export/export.h b/platform/android/export/export.h index 7ada91aec959..bd689a400d51 100644 --- a/platform/android/export/export.h +++ b/platform/android/export/export.h @@ -31,6 +31,7 @@ #ifndef ANDROID_EXPORT_H #define ANDROID_EXPORT_H +void register_android_exporter_types(); void register_android_exporter(); #endif // ANDROID_EXPORT_H diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index fa97a095ab87..0f0132a5d1ec 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -1703,16 +1703,109 @@ void EditorExportPlatformAndroid::get_preset_features(const Ref *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(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 *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/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::INT, "gradle_build/export_format", PROPERTY_HINT_ENUM, "Export APK,Export AAB"), EXPORT_FORMAT_APK)); + 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, false, true)); // 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. - 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/target_sdk", PROPERTY_HINT_PLACEHOLDER_TEXT, vformat("%d (default)", DEFAULT_TARGET_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)), "", false, true)); Vector plugins_configs = get_plugins(); for (int i = 0; i < plugins_configs.size(); i++) { @@ -1742,7 +1835,7 @@ void EditorExportPlatformAndroid::get_export_options(List *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::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::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)); @@ -1755,10 +1848,10 @@ void EditorExportPlatformAndroid::get_export_options(List *r_optio 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/hand_tracking", PROPERTY_HINT_ENUM, "None,Optional,Required"), XR_HAND_TRACKING_NONE)); + 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, 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/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/support_small"), true)); @@ -1770,9 +1863,9 @@ void EditorExportPlatformAndroid::get_export_options(List *r_optio 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/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())); @@ -2272,111 +2365,39 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref &p_preset, String &r_error) const { String err; bool valid = true; - const bool gradle_build_enabled = p_preset->get("gradle_build/use_gradle_build"); - // Validate the project configuration. - bool apk_expansion = p_preset->get("apk_expansion/enable"); - - if (apk_expansion) { - String apk_expansion_pkey = p_preset->get("apk_expansion/public_key"); - - if (apk_expansion_pkey.is_empty()) { - valid = false; - - err += TTR("Invalid public key for APK expansion.") + "\n"; + List options; + get_export_options(&options); + 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); + if (!warn.is_empty()) { + err += warn + "\n"; + if (E.required) { + valid = false; + } + } } } - 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(); if (!etc_error.is_empty()) { valid = false; 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"); int min_sdk_int = VULKAN_MIN_SDK_VERSION; if (!min_sdk_str.is_empty()) { // Empty means no override, nothing to do. - if (!gradle_build_enabled) { - 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 { + if (min_sdk_str.is_valid_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"); int target_sdk_int = DEFAULT_TARGET_SDK_VERSION; if (!target_sdk_str.is_empty()) { // Empty means no override, nothing to do. - if (!gradle_build_enabled) { - 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 { + if (target_sdk_str.is_valid_int()) { target_sdk_int = target_sdk_str.to_int(); if (target_sdk_int > DEFAULT_TARGET_SDK_VERSION) { // Warning only, so don't override `valid`. @@ -2386,18 +2407,13 @@ bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref img = memnew(Image); - const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); + Ref img = memnew(Image); + const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); - ImageLoaderSVG img_loader; - img_loader.create_image_from_string(img, _android_logo_svg, EDSCALE, upsample, false); - logo = ImageTexture::create_from_image(img); + ImageLoaderSVG img_loader; + img_loader.create_image_from_string(img, _android_logo_svg, EDSCALE, upsample, false); + logo = ImageTexture::create_from_image(img); - img_loader.create_image_from_string(img, _android_run_icon_svg, EDSCALE, upsample, false); - run_icon = ImageTexture::create_from_image(img); + img_loader.create_image_from_string(img, _android_run_icon_svg, EDSCALE, upsample, false); + run_icon = ImageTexture::create_from_image(img); #endif - devices_changed.set(); - plugins_changed.set(); + devices_changed.set(); + plugins_changed.set(); #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 + } } EditorExportPlatformAndroid::~EditorExportPlatformAndroid() { diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h index 337a0228d0ca..f9dad5ce5e0a 100644 --- a/platform/android/export/export_plugin.h +++ b/platform/android/export/export_plugin.h @@ -72,10 +72,10 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { EditorProgress *ep = nullptr; }; - Vector plugins; + mutable Vector plugins; String last_plugin_names; uint64_t last_gradle_build_time = 0; - SafeFlag plugins_changed; + mutable SafeFlag plugins_changed; Mutex plugins_lock; Vector devices; SafeFlag devices_changed; @@ -180,7 +180,9 @@ public: public: virtual void get_preset_features(const Ref &p_preset, List *r_features) const override; - virtual void get_export_options(List *r_options) override; + virtual void get_export_options(List *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; diff --git a/platform/ios/export/export.cpp b/platform/ios/export/export.cpp index e35383206f6e..f4b90d8883c5 100644 --- a/platform/ios/export/export.cpp +++ b/platform/ios/export/export.cpp @@ -33,6 +33,10 @@ #include "editor/export/editor_export.h" #include "export_plugin.h" +void register_ios_exporter_types() { + GDREGISTER_VIRTUAL_CLASS(EditorExportPlatformIOS); +} + void register_ios_exporter() { Ref platform; platform.instantiate(); diff --git a/platform/ios/export/export.h b/platform/ios/export/export.h index 03e92bfccd29..355811054a83 100644 --- a/platform/ios/export/export.h +++ b/platform/ios/export/export.h @@ -31,6 +31,7 @@ #ifndef IOS_EXPORT_H #define IOS_EXPORT_H +void register_ios_exporter_types(); void register_ios_exporter(); #endif // IOS_EXPORT_H diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp index c6f7ec09b194..b6d70048e362 100644 --- a/platform/ios/export/export_plugin.cpp +++ b/platform/ios/export/export_plugin.cpp @@ -120,7 +120,35 @@ static const LoadingScreenInfo loading_screen_infos[] = { { PNAME("portrait_launch_screens/iphone_1242x2208"), "Default-Portrait-736h@3x.png", 1242, 2208, true } }; -void EditorExportPlatformIOS::get_export_options(List *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 *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/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); @@ -129,7 +157,7 @@ void EditorExportPlatformIOS::get_export_options(List *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::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/code_sign_identity_debug", PROPERTY_HINT_PLACEHOLDER_TEXT, "iPhone Developer"), "")); @@ -140,7 +168,7 @@ void EditorExportPlatformIOS::get_export_options(List *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::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/short_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 *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::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::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"), "")); @@ -1907,17 +1935,18 @@ bool EditorExportPlatformIOS::has_valid_project_configuration(const Refget("application/app_store_team_id"); - if (team_id.length() == 0) { - err += TTR("App Store Team ID not specified - cannot configure the project.") + "\n"; - valid = false; - } - - String identifier = p_preset->get("application/bundle_identifier"); - String pn_err; - if (!is_package_name_valid(identifier, &pn_err)) { - err += TTR("Invalid Identifier:") + " " + pn_err + "\n"; - valid = false; + List options; + get_export_options(&options); + 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); + if (!warn.is_empty()) { + err += warn + "\n"; + if (E.required) { + valid = false; + } + } + } } const String etc_error = test_etc2(); @@ -1934,19 +1963,21 @@ bool EditorExportPlatformIOS::has_valid_project_configuration(const Ref img = memnew(Image); - const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); + Ref img = memnew(Image); + const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); - ImageLoaderSVG img_loader; - img_loader.create_image_from_string(img, _ios_logo_svg, EDSCALE, upsample, false); - logo = ImageTexture::create_from_image(img); + ImageLoaderSVG img_loader; + img_loader.create_image_from_string(img, _ios_logo_svg, EDSCALE, upsample, false); + logo = ImageTexture::create_from_image(img); #endif - plugins_changed.set(); + plugins_changed.set(); #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 + } } EditorExportPlatformIOS::~EditorExportPlatformIOS() { diff --git a/platform/ios/export/export_plugin.h b/platform/ios/export/export_plugin.h index 628dae2e6f3f..0fde3b7c0b72 100644 --- a/platform/ios/export/export_plugin.h +++ b/platform/ios/export/export_plugin.h @@ -55,13 +55,13 @@ class EditorExportPlatformIOS : public EditorExportPlatform { Ref logo; // Plugins - SafeFlag plugins_changed; + mutable SafeFlag plugins_changed; #ifndef ANDROID_ENABLED Thread check_for_changes_thread; SafeFlag quit_request; #endif Mutex plugins_lock; - Vector plugins; + mutable Vector plugins; typedef Error (*FileHandler)(String p_file, void *p_userdata); static Error _walk_dir_recursive(Ref &p_da, FileHandler p_handler, void *p_userdata); @@ -178,7 +178,9 @@ class EditorExportPlatformIOS : public EditorExportPlatform { protected: virtual void get_preset_features(const Ref &p_preset, List *r_features) const override; - virtual void get_export_options(List *r_options) override; + virtual void get_export_options(List *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: virtual String get_name() const override { return "iOS"; } diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp index 2c5a945b6cb9..09f354246d8d 100644 --- a/platform/linuxbsd/export/export.cpp +++ b/platform/linuxbsd/export/export.cpp @@ -33,6 +33,10 @@ #include "editor/export/editor_export.h" #include "export_plugin.h" +void register_linuxbsd_exporter_types() { + GDREGISTER_VIRTUAL_CLASS(EditorExportPlatformLinuxBSD); +} + void register_linuxbsd_exporter() { Ref platform; platform.instantiate(); diff --git a/platform/linuxbsd/export/export.h b/platform/linuxbsd/export/export.h index a2d70a73e34d..f49304781573 100644 --- a/platform/linuxbsd/export/export.h +++ b/platform/linuxbsd/export/export.h @@ -31,6 +31,7 @@ #ifndef LINUXBSD_EXPORT_H #define LINUXBSD_EXPORT_H +void register_linuxbsd_exporter_types(); void register_linuxbsd_exporter(); #endif // LINUXBSD_EXPORT_H diff --git a/platform/linuxbsd/export/export_plugin.cpp b/platform/linuxbsd/export/export_plugin.cpp index 2528bb2b99e7..317c6575b33b 100644 --- a/platform/linuxbsd/export/export_plugin.cpp +++ b/platform/linuxbsd/export/export_plugin.cpp @@ -142,7 +142,18 @@ List EditorExportPlatformLinuxBSD::get_binary_extensions(const Ref *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 *r_options) const { 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")); @@ -156,7 +167,7 @@ void EditorExportPlatformLinuxBSD::get_export_options(List *r_opti "kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\")\n" "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/port"), "22")); @@ -503,22 +514,24 @@ Error EditorExportPlatformLinuxBSD::run(const Ref &p_preset, } EditorExportPlatformLinuxBSD::EditorExportPlatformLinuxBSD() { + if (EditorNode::get_singleton()) { #ifdef MODULE_SVG_ENABLED - Ref img = memnew(Image); - const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); + Ref img = memnew(Image); + const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); - ImageLoaderSVG img_loader; - img_loader.create_image_from_string(img, _linuxbsd_logo_svg, EDSCALE, upsample, false); - set_logo(ImageTexture::create_from_image(img)); + ImageLoaderSVG img_loader; + img_loader.create_image_from_string(img, _linuxbsd_logo_svg, EDSCALE, upsample, false); + set_logo(ImageTexture::create_from_image(img)); - img_loader.create_image_from_string(img, _linuxbsd_run_icon_svg, EDSCALE, upsample, false); - run_icon = ImageTexture::create_from_image(img); + img_loader.create_image_from_string(img, _linuxbsd_run_icon_svg, EDSCALE, upsample, false); + run_icon = ImageTexture::create_from_image(img); #endif - Ref theme = EditorNode::get_singleton()->get_editor_theme(); - if (theme.is_valid()) { - stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons")); - } else { - stop_icon.instantiate(); + Ref theme = EditorNode::get_singleton()->get_editor_theme(); + if (theme.is_valid()) { + stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons")); + } else { + stop_icon.instantiate(); + } } } diff --git a/platform/linuxbsd/export/export_plugin.h b/platform/linuxbsd/export/export_plugin.h index 4f860c3fd06c..cef714e86e6b 100644 --- a/platform/linuxbsd/export/export_plugin.h +++ b/platform/linuxbsd/export/export_plugin.h @@ -37,6 +37,8 @@ #include "scene/resources/texture.h" class EditorExportPlatformLinuxBSD : public EditorExportPlatformPC { + GDCLASS(EditorExportPlatformLinuxBSD, EditorExportPlatformPC); + HashMap extensions; struct SSHCleanupCommand { @@ -69,8 +71,9 @@ class EditorExportPlatformLinuxBSD : public EditorExportPlatformPC { Error _export_debug_script(const Ref &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path); public: - virtual void get_export_options(List *r_options) override; + virtual void get_export_options(List *r_options) const override; virtual List get_binary_extensions(const Ref &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 &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 Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override; diff --git a/platform/macos/export/export.cpp b/platform/macos/export/export.cpp index 5a2850a6b726..8930974df9c2 100644 --- a/platform/macos/export/export.cpp +++ b/platform/macos/export/export.cpp @@ -32,6 +32,10 @@ #include "export_plugin.h" +void register_macos_exporter_types() { + GDREGISTER_VIRTUAL_CLASS(EditorExportPlatformMacOS); +} + void register_macos_exporter() { #ifndef ANDROID_ENABLED EDITOR_DEF("export/macos/rcodesign", ""); diff --git a/platform/macos/export/export.h b/platform/macos/export/export.h index 384dab826eac..a7a7dcad1686 100644 --- a/platform/macos/export/export.h +++ b/platform/macos/export/export.h @@ -31,6 +31,7 @@ #ifndef MACOS_EXPORT_H #define MACOS_EXPORT_H +void register_macos_exporter_types(); void register_macos_exporter(); #endif // MACOS_EXPORT_H diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp index ab76d9b27383..cd9d17dd4fc2 100644 --- a/platform/macos/export/export_plugin.cpp +++ b/platform/macos/export/export_plugin.cpp @@ -62,13 +62,191 @@ void EditorExportPlatformMacOS::get_preset_features(const Ref &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. if (p_preset) { int codesign_tool = p_preset->get("codesign/codesign"); switch (codesign_tool) { 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; } } break; @@ -85,17 +263,48 @@ bool EditorExportPlatformMacOS::get_export_option_visibility(const EditorExportP } break; #endif 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; } } 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. int notary_tool = p_preset->get("notarization/notarization"); switch (notary_tool) { 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; } } break; @@ -106,7 +315,7 @@ bool EditorExportPlatformMacOS::get_export_option_visibility(const EditorExportP // All options are visible. } break; 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; } } break; @@ -122,7 +331,39 @@ bool EditorExportPlatformMacOS::get_export_option_visibility(const EditorExportP return true; } -void EditorExportPlatformMacOS::get_export_options(List *r_options) { +List EditorExportPlatformMacOS::get_binary_extensions(const Ref &p_preset) const { + List 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 *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, "custom_template/debug", 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 *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::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::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/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/version"), "1.0")); 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::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::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 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 - 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 + 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: r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_PLACEHOLDER_TEXT, "Type: Name (ID)"), "")); // "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_password", PROPERTY_HINT_PASSWORD), "")); // "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_unsigned_executable_memory"), 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 *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/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/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_client"), 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 *r_options r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "notarization/notarization", PROPERTY_HINT_ENUM, "Disabled,rcodesign"), 0, true)); #endif // "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_password", PROPERTY_HINT_PASSWORD, "Enable two-factor authentication and provide app-specific password"), "")); - 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"), "")); + 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"), "", false, true)); // "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_key", PROPERTY_HINT_GLOBAL_FILE, "*.p8"), "")); - 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_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"), "", false, true)); + 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::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::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::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::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::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::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::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::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::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::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())); String run_script = "#!/usr/bin/env bash\n" @@ -220,7 +472,7 @@ void EditorExportPlatformMacOS::get_export_options(List *r_options "kill $(pgrep -x -f \"{temp_dir}/{exe_name}.app/Contents/MacOS/{exe_name} {cmd_args}\")\n" "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/port"), "22")); @@ -424,8 +676,22 @@ void EditorExportPlatformMacOS::_fix_plist(const Ref &p_pres strnew += lines[i].replace("$app_category", cat.to_lower()) + "\n"; } else if (lines[i].find("$copyright") != -1) { 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) { strnew += lines[i].replace("$highres", p_preset->get("display/high_res") ? "\t" : "\t") + "\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) { String descriptions; if (!((String)p_preset->get("privacy/microphone_usage_description")).is_empty()) { @@ -612,9 +878,9 @@ Error EditorExportPlatformMacOS::_notarize(const Ref &p_pres 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(p_preset->get("notarization/apple_team_id")); + args.push_back(p_preset->get("codesign/apple_team_id")); } String str; @@ -693,9 +959,9 @@ Error EditorExportPlatformMacOS::_notarize(const Ref &p_pres args.push_back("--type"); 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(p_preset->get("notarization/apple_team_id")); + args.push_back(p_preset->get("codesign/apple_team_id")); } args.push_back("--file"); @@ -978,6 +1244,42 @@ Error EditorExportPlatformMacOS::_export_macos_plugins_for(Ref &p_preset, const String &p_pkg_path, const String &p_app_path_name) { + List 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) { List args; @@ -1106,12 +1408,16 @@ Error EditorExportPlatformMacOS::export_project(const Ref &p pkg_name = OS::get_singleton()->get_safe_dir_name(pkg_name); String export_format; - if (use_dmg() && p_path.ends_with("dmg")) { - export_format = "dmg"; - } else if (p_path.ends_with("zip")) { + if (p_path.ends_with("zip")) { export_format = "zip"; } else if (p_path.ends_with("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 { add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Invalid export format.")); return ERR_CANT_CREATE; @@ -1549,6 +1855,19 @@ Error EditorExportPlatformMacOS::export_project(const Ref &p ent_f->store_line(""); } + 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("com.apple.developer.team-identifier"); + ent_f->store_line("" + teamid + ""); + ent_f->store_line("com.apple.application-identifier"); + ent_f->store_line("" + teamid + "." + bid + ""); + } + } + if ((bool)p_preset->get("codesign/entitlements/app_sandbox/enabled")) { ent_f->store_line("com.apple.security.app-sandbox"); ent_f->store_line(""); @@ -1669,6 +1988,15 @@ Error EditorExportPlatformMacOS::export_project(const Ref &p } 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 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)) { return ERR_SKIP; } @@ -1690,6 +2018,14 @@ Error EditorExportPlatformMacOS::export_project(const Ref &p } 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") { // Create ZIP. if (err == OK) { @@ -1712,7 +2048,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref &p bool noto_enabled = (p_preset->get("notarization/notarization").operator int() > 0); 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.")); } else { if (ep.step(TTR("Sending archive for notarization"), 4)) { @@ -1802,15 +2138,10 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Refget("application/bundle_identifier"); - String pn_err; - if (!is_package_name_valid(identifier, &pn_err)) { - err += TTR("Invalid bundle identifier:") + " " + pn_err + "\n"; - valid = false; - } - + 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; @@ -1826,66 +2157,40 @@ bool EditorExportPlatformMacOS::has_valid_project_configuration(const Refget("notarization/notarization"); - if (notary_tool > 0) { - if (ad_hoc) { - err += TTR("Notarization: Notarization with an ad-hoc signature is not supported.") + "\n"; - valid = false; - } - if (codesign_tool == 0) { - err += TTR("Notarization: Code signing is required for notarization.") + "\n"; - 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; - } + List options; + get_export_options(&options); + 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); + if (!warn.is_empty()) { + err += warn + "\n"; + if (E.required) { + 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) { - err += TTR("Code signing is disabled. The exported project will not run on Macs with enabled Gatekeeper and Apple Silicon powered Macs.") + "\n"; + } + + if (dist_type != 2) { + 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 Refget("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()) { @@ -2157,22 +2438,24 @@ Error EditorExportPlatformMacOS::run(const Ref &p_preset, in } EditorExportPlatformMacOS::EditorExportPlatformMacOS() { + if (EditorNode::get_singleton()) { #ifdef MODULE_SVG_ENABLED - Ref img = memnew(Image); - const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); + Ref img = memnew(Image); + const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); - ImageLoaderSVG img_loader; - img_loader.create_image_from_string(img, _macos_logo_svg, EDSCALE, upsample, false); - logo = ImageTexture::create_from_image(img); + ImageLoaderSVG img_loader; + img_loader.create_image_from_string(img, _macos_logo_svg, EDSCALE, upsample, false); + logo = ImageTexture::create_from_image(img); - img_loader.create_image_from_string(img, _macos_run_icon_svg, EDSCALE, upsample, false); - run_icon = ImageTexture::create_from_image(img); + img_loader.create_image_from_string(img, _macos_run_icon_svg, EDSCALE, upsample, false); + run_icon = ImageTexture::create_from_image(img); #endif - Ref theme = EditorNode::get_singleton()->get_editor_theme(); - if (theme.is_valid()) { - stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons")); - } else { - stop_icon.instantiate(); + Ref theme = EditorNode::get_singleton()->get_editor_theme(); + if (theme.is_valid()) { + stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons")); + } else { + stop_icon.instantiate(); + } } } diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h index c10192949cb0..a8caf535c49a 100644 --- a/platform/macos/export/export_plugin.h +++ b/platform/macos/export/export_plugin.h @@ -87,18 +87,10 @@ class EditorExportPlatformMacOS : public EditorExportPlatform { Ref &dir_access, bool p_sign_enabled, const Ref &p_preset, 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_pkg(const Ref &p_preset, const String &p_pkg_path, const String &p_app_path_name); Error _export_debug_script(const Ref &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path); 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 { String pname = p_package; @@ -126,8 +118,9 @@ class EditorExportPlatformMacOS : public EditorExportPlatform { protected: virtual void get_preset_features(const Ref &p_preset, List *r_features) const override; - virtual void get_export_options(List *r_options) override; - virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap &p_options) const override; + virtual void get_export_options(List *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: virtual String get_name() const override { @@ -141,15 +134,7 @@ public: } virtual bool is_executable(const String &p_path) const override; - virtual List get_binary_extensions(const Ref &p_preset) const override { - List list; - if (use_dmg()) { - list.push_back("dmg"); - } - list.push_back("zip"); - list.push_back("app"); - return list; - } + virtual List get_binary_extensions(const Ref &p_preset) const override; virtual Error export_project(const Ref &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override; virtual bool has_valid_export_configuration(const Ref &p_preset, String &r_error, bool &r_missing_templates) const override; diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp index f2b2fa30ce76..85964c53e6c9 100644 --- a/platform/uwp/export/export.cpp +++ b/platform/uwp/export/export.cpp @@ -33,6 +33,10 @@ #include "editor/editor_settings.h" #include "export_plugin.h" +void register_uwp_exporter_types() { + // GDREGISTER_VIRTUAL_CLASS(EditorExportPlatformUWP); +} + void register_uwp_exporter() { #ifdef WINDOWS_ENABLED EDITOR_DEF("export/uwp/signtool", ""); diff --git a/platform/uwp/export/export.h b/platform/uwp/export/export.h index 09449fc53bf1..d2053e02b13f 100644 --- a/platform/uwp/export/export.h +++ b/platform/uwp/export/export.h @@ -31,6 +31,7 @@ #ifndef UWP_EXPORT_H #define UWP_EXPORT_H +void register_uwp_exporter_types(); void register_uwp_exporter(); #endif // UWP_EXPORT_H diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp index f810cb0ca9d2..163236e50642 100644 --- a/platform/uwp/export/export_plugin.cpp +++ b/platform/uwp/export/export_plugin.cpp @@ -62,7 +62,7 @@ void EditorExportPlatformUWP::get_preset_features(const Ref r_features->push_back(p_preset->get("binary_format/architecture")); } -void EditorExportPlatformUWP::get_export_options(List *r_options) { +void EditorExportPlatformUWP::get_export_options(List *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/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); diff --git a/platform/uwp/export/export_plugin.h b/platform/uwp/export/export_plugin.h index d015fcabcd07..37a32b1f7f7e 100644 --- a/platform/uwp/export/export_plugin.h +++ b/platform/uwp/export/export_plugin.h @@ -427,7 +427,7 @@ public: virtual void get_preset_features(const Ref &p_preset, List *r_features) const override; - virtual void get_export_options(List *r_options) override; + virtual void get_export_options(List *r_options) const override; virtual bool has_valid_export_configuration(const Ref &p_preset, String &r_error, bool &r_missing_templates) const override; virtual bool has_valid_project_configuration(const Ref &p_preset, String &r_error) const override; diff --git a/platform/web/export/export.cpp b/platform/web/export/export.cpp index 11e728ea16ca..54d9774da58b 100644 --- a/platform/web/export/export.cpp +++ b/platform/web/export/export.cpp @@ -33,6 +33,10 @@ #include "editor/editor_settings.h" #include "export_plugin.h" +void register_web_exporter_types() { + GDREGISTER_VIRTUAL_CLASS(EditorExportPlatformWeb); +} + void register_web_exporter() { #ifndef ANDROID_ENABLED EDITOR_DEF("export/web/http_host", "localhost"); diff --git a/platform/web/export/export.h b/platform/web/export/export.h index 8d2bbfff266e..da02bd8d9357 100644 --- a/platform/web/export/export.h +++ b/platform/web/export/export.h @@ -31,6 +31,7 @@ #ifndef WEB_EXPORT_H #define WEB_EXPORT_H +void register_web_exporter_types(); void register_web_exporter(); #endif // WEB_EXPORT_H diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp index d8e04904c7dc..7a62cd2a4adc 100644 --- a/platform/web/export/export_plugin.cpp +++ b/platform/web/export/export_plugin.cpp @@ -320,7 +320,7 @@ void EditorExportPlatformWeb::get_preset_features(const Ref r_features->push_back("wasm32"); } -void EditorExportPlatformWeb::get_export_options(List *r_options) { +void EditorExportPlatformWeb::get_export_options(List *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/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); @@ -656,31 +656,35 @@ void EditorExportPlatformWeb::_server_thread_poll(void *data) { } EditorExportPlatformWeb::EditorExportPlatformWeb() { - server.instantiate(); - server_thread.start(_server_thread_poll, this); + if (EditorNode::get_singleton()) { + server.instantiate(); + server_thread.start(_server_thread_poll, this); #ifdef MODULE_SVG_ENABLED - Ref img = memnew(Image); - const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); + Ref img = memnew(Image); + const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); - ImageLoaderSVG img_loader; - img_loader.create_image_from_string(img, _web_logo_svg, EDSCALE, upsample, false); - logo = ImageTexture::create_from_image(img); + ImageLoaderSVG img_loader; + img_loader.create_image_from_string(img, _web_logo_svg, EDSCALE, upsample, false); + logo = ImageTexture::create_from_image(img); - img_loader.create_image_from_string(img, _web_run_icon_svg, EDSCALE, upsample, false); - run_icon = ImageTexture::create_from_image(img); + img_loader.create_image_from_string(img, _web_run_icon_svg, EDSCALE, upsample, false); + run_icon = ImageTexture::create_from_image(img); #endif - Ref theme = EditorNode::get_singleton()->get_editor_theme(); - if (theme.is_valid()) { - stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons")); - } else { - stop_icon.instantiate(); + Ref theme = EditorNode::get_singleton()->get_editor_theme(); + if (theme.is_valid()) { + stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons")); + } else { + stop_icon.instantiate(); + } } } EditorExportPlatformWeb::~EditorExportPlatformWeb() { - server->stop(); + if (server.is_valid()) { + server->stop(); + } server_quit = true; server_thread.wait_to_finish(); } diff --git a/platform/web/export/export_plugin.h b/platform/web/export/export_plugin.h index e74c9458376a..334f12d64d93 100644 --- a/platform/web/export/export_plugin.h +++ b/platform/web/export/export_plugin.h @@ -99,7 +99,7 @@ class EditorExportPlatformWeb : public EditorExportPlatform { public: virtual void get_preset_features(const Ref &p_preset, List *r_features) const override; - virtual void get_export_options(List *r_options) override; + virtual void get_export_options(List *r_options) const override; virtual String get_name() const override; virtual String get_os_name() const override; diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp index 4112bb84b58a..08c620e1e938 100644 --- a/platform/windows/export/export.cpp +++ b/platform/windows/export/export.cpp @@ -33,6 +33,10 @@ #include "editor/export/editor_export.h" #include "export_plugin.h" +void register_windows_exporter_types() { + GDREGISTER_VIRTUAL_CLASS(EditorExportPlatformWindows); +} + void register_windows_exporter() { #ifndef ANDROID_ENABLED EDITOR_DEF("export/windows/rcedit", ""); diff --git a/platform/windows/export/export.h b/platform/windows/export/export.h index f5bf83bb48f5..6c4020f0c8d7 100644 --- a/platform/windows/export/export.h +++ b/platform/windows/export/export.h @@ -31,6 +31,7 @@ #ifndef WINDOWS_EXPORT_H #define WINDOWS_EXPORT_H +void register_windows_exporter_types(); void register_windows_exporter(); #endif // WINDOWS_EXPORT_H diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp index 941e72c8f328..05b25eae0316 100644 --- a/platform/windows/export/export_plugin.cpp +++ b/platform/windows/export/export_plugin.cpp @@ -262,21 +262,72 @@ List EditorExportPlatformWindows::get_binary_extensions(const Ref &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. if (!OS::get_singleton()->has_feature("windows") && p_option == "codesign/identity_type") { 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; } -void EditorExportPlatformWindows::get_export_options(List *r_options) { +void EditorExportPlatformWindows::get_export_options(List *r_options) const { 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::BOOL, "codesign/enable"), false)); - 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::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 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/password", PROPERTY_HINT_PASSWORD), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true)); @@ -285,12 +336,12 @@ void EditorExportPlatformWindows::get_export_options(List *r_optio 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::BOOL, "application/modify_resources"), 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::BOOL, "application/modify_resources"), true, true)); + 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::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/product_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"), "", 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/product_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_description"), "")); @@ -311,7 +362,7 @@ void EditorExportPlatformWindows::get_export_options(List *r_optio "Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue\n" "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/port"), "22")); @@ -632,30 +683,17 @@ bool EditorExportPlatformWindows::has_valid_project_configuration(const Refglobalize_path(p_preset->get("application/icon")); - if (!icon_path.is_empty() && !FileAccess::exists(icon_path)) { - err += TTR("Invalid icon path:") + " " + icon_path + "\n"; - } - - // Only non-negative integers can exist in the version string. - - 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) { - 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"; + List options; + get_export_options(&options); + 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); + if (!warn.is_empty()) { + err += warn + "\n"; + if (E.required) { + valid = false; + } + } } } @@ -957,22 +995,24 @@ Error EditorExportPlatformWindows::run(const Ref &p_preset, } EditorExportPlatformWindows::EditorExportPlatformWindows() { + if (EditorNode::get_singleton()) { #ifdef MODULE_SVG_ENABLED - Ref img = memnew(Image); - const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); + Ref img = memnew(Image); + const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); - ImageLoaderSVG img_loader; - img_loader.create_image_from_string(img, _windows_logo_svg, EDSCALE, upsample, false); - set_logo(ImageTexture::create_from_image(img)); + ImageLoaderSVG img_loader; + img_loader.create_image_from_string(img, _windows_logo_svg, EDSCALE, upsample, false); + set_logo(ImageTexture::create_from_image(img)); - img_loader.create_image_from_string(img, _windows_run_icon_svg, EDSCALE, upsample, false); - run_icon = ImageTexture::create_from_image(img); + img_loader.create_image_from_string(img, _windows_run_icon_svg, EDSCALE, upsample, false); + run_icon = ImageTexture::create_from_image(img); #endif - Ref theme = EditorNode::get_singleton()->get_editor_theme(); - if (theme.is_valid()) { - stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons")); - } else { - stop_icon.instantiate(); + Ref theme = EditorNode::get_singleton()->get_editor_theme(); + if (theme.is_valid()) { + stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons")); + } else { + stop_icon.instantiate(); + } } } diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h index fa75a17a1fdd..c466971202bf 100644 --- a/platform/windows/export/export_plugin.h +++ b/platform/windows/export/export_plugin.h @@ -37,6 +37,8 @@ #include "editor/export/editor_export_platform_pc.h" class EditorExportPlatformWindows : public EditorExportPlatformPC { + GDCLASS(EditorExportPlatformWindows, EditorExportPlatformPC); + struct SSHCleanupCommand { String host; String port; @@ -70,10 +72,12 @@ public: virtual Error modify_template(const Ref &p_preset, bool p_debug, const String &p_path, int p_flags) override; virtual Error sign_shared_object(const Ref &p_preset, bool p_debug, const String &p_path) override; virtual List get_binary_extensions(const Ref &p_preset) const override; - virtual void get_export_options(List *r_options) override; + virtual void get_export_options(List *r_options) const override; virtual bool has_valid_export_configuration(const Ref &p_preset, String &r_error, bool &r_missing_templates) const override; virtual bool has_valid_project_configuration(const Ref &p_preset, String &r_error) const override; - virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap &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 Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override;