diff --git a/docs/CMake API.md b/docs/CMake API.md index 426e7a1bdf..539a4d418f 100644 --- a/docs/CMake API.md +++ b/docs/CMake API.md @@ -231,7 +231,15 @@ attributes directly to these creation functions, rather than adding them later. - `VERSION` - A version number string in the format "major.minor.bugfix". If not specified, the `VERSION` of - the project containing the target will be used instead. + the project containing the target will be used instead. On Apple platforms, this is the + user-facing version string. This option corresponds to the `CFBundleShortVersionString` field in + the target's plist. + +- `BUILD_VERSION` + - A version number string in the format "major.minor.bugfix". If not specified, this will match + the `VERSION` of the target. On Apple platforms, this is the private version string used to + distinguish between App Store builds. This option corresponds to the `CFBundleVersion` field in + the target's plist. - `BUNDLE_ID` - An identifier string in the form "com.yourcompany.productname" which should uniquely identify @@ -270,7 +278,7 @@ attributes directly to these creation functions, rather than adding them later. - `STATUS_BAR_HIDDEN` - May be either TRUE or FALSE. Adds the appropriate entries to an iOS app's Info.plist. - + - `REQUIRES_FULL_SCREEN` - May be either TRUE or FALSE. Adds the appropriate entries to an iOS app's Info.plist. diff --git a/extras/Build/CMake/JUCEUtils.cmake b/extras/Build/CMake/JUCEUtils.cmake index e121e68909..638bd42aa9 100644 --- a/extras/Build/CMake/JUCEUtils.cmake +++ b/extras/Build/CMake/JUCEUtils.cmake @@ -793,6 +793,7 @@ endfunction() function(_juce_write_configure_time_info target) _juce_append_target_property(file_content EXECUTABLE_NAME ${target} JUCE_PRODUCT_NAME) _juce_append_target_property(file_content VERSION ${target} JUCE_VERSION) + _juce_append_target_property(file_content BUILD_VERSION ${target} JUCE_BUILD_VERSION) _juce_append_target_property(file_content PLIST_TO_MERGE ${target} JUCE_PLIST_TO_MERGE) _juce_append_target_property(file_content BUNDLE_ID ${target} JUCE_BUNDLE_ID) _juce_append_target_property(file_content XCODE_EXTRA_PLIST_ENTRIES ${target} JUCE_XCODE_EXTRA_PLIST_ENTRIES) @@ -1790,6 +1791,8 @@ function(_juce_set_fallback_properties target) message(FATAL_ERROR "Target ${target} must have its VERSION argument set, or must be part of a project with a PROJECT_VERSION") endif() + _juce_set_property_if_not_set(${target} BUILD_VERSION "${final_version}") + get_target_property(custom_xcassets ${target} JUCE_CUSTOM_XCASSETS_FOLDER) set(needs_storyboard TRUE) @@ -1973,6 +1976,7 @@ endfunction() function(_juce_initialise_target target) set(one_value_args VERSION + BUILD_VERSION PRODUCT_NAME PLIST_TO_MERGE BUNDLE_ID diff --git a/extras/Build/juce_build_tools/utils/juce_PlistOptions.cpp b/extras/Build/juce_build_tools/utils/juce_PlistOptions.cpp index 9658777846..25a1fd2fe7 100644 --- a/extras/Build/juce_build_tools/utils/juce_PlistOptions.cpp +++ b/extras/Build/juce_build_tools/utils/juce_PlistOptions.cpp @@ -157,8 +157,8 @@ namespace build_tools addPlistDictionaryKey (*dict, "CFBundleDisplayName", projectName); addPlistDictionaryKey (*dict, "CFBundlePackageType", getXcodePackageType (type)); addPlistDictionaryKey (*dict, "CFBundleSignature", getXcodeBundleSignature (type)); - addPlistDictionaryKey (*dict, "CFBundleShortVersionString", version); - addPlistDictionaryKey (*dict, "CFBundleVersion", version); + addPlistDictionaryKey (*dict, "CFBundleShortVersionString", marketingVersion); + addPlistDictionaryKey (*dict, "CFBundleVersion", currentProjectVersion); addPlistDictionaryKey (*dict, "NSHumanReadableCopyright", companyCopyright); addPlistDictionaryKey (*dict, "NSHighResolutionCapable", true); diff --git a/extras/Build/juce_build_tools/utils/juce_PlistOptions.h b/extras/Build/juce_build_tools/utils/juce_PlistOptions.h index 27fbef60ce..a1a93cea7a 100644 --- a/extras/Build/juce_build_tools/utils/juce_PlistOptions.h +++ b/extras/Build/juce_build_tools/utils/juce_PlistOptions.h @@ -59,7 +59,8 @@ namespace build_tools File iconFile; String projectName; - String version; + String marketingVersion; + String currentProjectVersion; String companyCopyright; String applicationCategory; diff --git a/extras/Build/juceaide/Main.cpp b/extras/Build/juceaide/Main.cpp index a88a4a2650..ff69a004b2 100644 --- a/extras/Build/juceaide/Main.cpp +++ b/extras/Build/juceaide/Main.cpp @@ -248,7 +248,8 @@ juce::build_tools::PlistOptions parsePlistOptions (const juce::File& file, updateField ("SHOULD_ADD_STORYBOARD", result.shouldAddStoryboardToProject); updateField ("LAUNCH_STORYBOARD_FILE", result.storyboardName); updateField ("PROJECT_NAME", result.projectName); - updateField ("VERSION", result.version); + updateField ("VERSION", result.marketingVersion); + updateField ("BUILD_VERSION", result.currentProjectVersion); updateField ("COMPANY_COPYRIGHT", result.companyCopyright); updateField ("DOCUMENT_EXTENSIONS", result.documentExtensions); updateField ("FILE_SHARING_ENABLED", result.fileSharingEnabled); @@ -274,7 +275,7 @@ juce::build_tools::PlistOptions parsePlistOptions (const juce::File& file, updateField ("ICON_FILE", result.iconFile); result.type = type; - result.versionAsHex = juce::build_tools::getVersionAsHexInteger (result.version); + result.versionAsHex = juce::build_tools::getVersionAsHexInteger (result.marketingVersion); if (result.storyboardName.isNotEmpty()) result.storyboardName = result.storyboardName.fromLastOccurrenceOf ("/", false, false) diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h index 2be52173a9..015d2b299d 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h @@ -187,7 +187,8 @@ public: customLaunchStoryboardValue (settings, Ids::customLaunchStoryboard, getUndoManager()), exporterBundleIdentifierValue (settings, Ids::bundleIdentifier, getUndoManager()), suppressPlistResourceUsageValue (settings, Ids::suppressPlistResourceUsage, getUndoManager()), - useLegacyBuildSystemValue (settings, Ids::useLegacyBuildSystem, getUndoManager()) + useLegacyBuildSystemValue (settings, Ids::useLegacyBuildSystem, getUndoManager()), + buildNumber (settings, Ids::buildNumber, getUndoManager()) { if (iOS) { @@ -288,6 +289,12 @@ public: String getDevelopmentTeamIDString() const { return iosDevelopmentTeamIDValue.get(); } String getAppGroupIdString() const { return iosAppGroupsIDValue.get(); } + String getBuildNumber() const + { + const auto buildNumberString = buildNumber.get().toString(); + return buildNumberString.isNotEmpty() ? buildNumberString : project.getVersionString(); + } + String getDefaultLaunchStoryboardName() const { return "LaunchScreen"; } //============================================================================== @@ -370,6 +377,11 @@ public: props.add (new ChoicePropertyComponent (duplicateAppExResourcesFolderValue, "Add Duplicate Resources Folder to App Extension"), "Disable this to prevent the Projucer from creating a duplicate resources folder for AUv3 app extensions."); + props.add (new TextPropertyComponent (buildNumber, "Build Number", 128, false), + "The current version of the project. Used to disambiguate different builds of the same project on App Store Connect. " + "If this field is empty, the project's version will be used as the build number. " + "For more details about the difference between the project version and build version, see developer.apple.com/library/archive/technotes/tn2420/_index.html"); + if (iOS) { props.add (new ChoicePropertyComponent (iosDeviceFamilyValue, "Device Family", @@ -1820,7 +1832,8 @@ public: options.shouldAddStoryboardToProject = owner.shouldAddStoryboardToProject(); options.iconFile = owner.iconFile; options.projectName = owner.projectName; - options.version = owner.project.getVersionString(); + options.marketingVersion = owner.project.getVersionString(); + options.currentProjectVersion = owner.getBuildNumber(); options.companyCopyright = owner.project.getCompanyCopyrightString(); options.allPreprocessorDefs = owner.getAllPreprocessorDefs(); options.documentExtensions = owner.getDocumentExtensionsString(); @@ -3566,7 +3579,7 @@ private: uiFileSharingEnabledValue, uiSupportsDocumentBrowserValue, uiStatusBarHiddenValue, uiRequiresFullScreenValue, documentExtensionsValue, iosInAppPurchasesValue, iosContentSharingValue, iosBackgroundAudioValue, iosBackgroundBleValue, iosPushNotificationsValue, iosAppGroupsValue, iCloudPermissionsValue, iosDevelopmentTeamIDValue, iosAppGroupsIDValue, keepCustomXcodeSchemesValue, useHeaderMapValue, customLaunchStoryboardValue, - exporterBundleIdentifierValue, suppressPlistResourceUsageValue, useLegacyBuildSystemValue; + exporterBundleIdentifierValue, suppressPlistResourceUsageValue, useLegacyBuildSystemValue, buildNumber; JUCE_DECLARE_NON_COPYABLE (XcodeProjectExporter) }; diff --git a/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h b/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h index 2ac035f59d..d744522dc5 100644 --- a/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h +++ b/extras/Projucer/Source/Utility/Helpers/jucer_PresetIDs.h @@ -378,6 +378,7 @@ namespace Ids DECLARE_ID (liveBuildEnabled); DECLARE_ID (guiEditorEnabled); DECLARE_ID (jucerFormatVersion); + DECLARE_ID (buildNumber); const Identifier ID ("id"); const Identifier ID_uppercase ("ID");