summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Edelev <[email protected]>2024-11-06 16:08:29 +0100
committerAlexey Edelev <[email protected]>2025-07-07 17:07:23 +0200
commit6e4df829b648e8620d618f1be80985c6638d4e9e (patch)
tree432feb4764680f6a708bb06b69b38fe02122dba1
parent118fa1952813d78707a16f7b9d95c2d72486f38a (diff)
Migrate to the gradle.settings approach when generating Android projectsHEADdev
This approach is more flexible and modernizes the gradle project structure for Qt apps. We now try to reproduce the CMake Android project structure of user applications, in the modern Android project structure described here: https://developer.android.com/build The new structure using the module based application build and unlocks the support for the use of dynamic features and Android libraries(aar). All gradle-related rules are generated by CMake and androiddeployqt is used in the auxiliary mode only(--aux-mode option). Update gradle templates. To opt-in the modern deployment use the QT_ANDROID_MODERN_BUNDLE variable. Task-number: QTBUG-116683 Task-number: QTBUG-124600 Change-Id: I343b884dea77a7b3b9059cf876a81c3693d0294b Reviewed-by: Assam Boudjelthia <[email protected]>
-rw-r--r--cmake/QtBaseHelpers.cmake1
-rw-r--r--cmake/QtPlatformAndroid.cmake8
-rw-r--r--src/3rdparty/gradle/gradle.properties3
-rw-r--r--src/android/CMakeLists.txt1
-rw-r--r--src/android/REUSE.toml2
-rw-r--r--src/android/templates_cmake/CMakeLists.txt24
-rw-r--r--src/android/templates_cmake/build.gradle.in53
-rw-r--r--src/android/templates_cmake/gradle.properties.in12
-rw-r--r--src/android/templates_cmake/settings.gradle.in17
-rw-r--r--src/corelib/CMakeLists.txt4
-rw-r--r--src/corelib/Qt6AndroidGradleHelpers.cmake305
-rw-r--r--src/corelib/Qt6AndroidMacros.cmake116
-rw-r--r--src/corelib/Qt6CoreConfigExtras.cmake.in1
-rw-r--r--src/tools/androiddeployqt/main.cpp7
-rw-r--r--tests/auto/corelib/platform/CMakeLists.txt4
15 files changed, 539 insertions, 19 deletions
diff --git a/cmake/QtBaseHelpers.cmake b/cmake/QtBaseHelpers.cmake
index b3a4e8c7619..c5db1039146 100644
--- a/cmake/QtBaseHelpers.cmake
+++ b/cmake/QtBaseHelpers.cmake
@@ -237,6 +237,7 @@ macro(qt_internal_qtbase_build_repo)
# Needed when building qtbase for android.
if(ANDROID)
include(src/corelib/Qt6AndroidMacros.cmake)
+ include(src/corelib/Qt6AndroidGradleHelpers.cmake)
endif()
# Needed when building for WebAssembly.
diff --git a/cmake/QtPlatformAndroid.cmake b/cmake/QtPlatformAndroid.cmake
index b480b1c14a6..dfcdf12b6a7 100644
--- a/cmake/QtPlatformAndroid.cmake
+++ b/cmake/QtPlatformAndroid.cmake
@@ -124,6 +124,12 @@ function(qt_internal_android_test_runner_arguments target out_test_runner out_te
"--make" "\"${CMAKE_COMMAND}\" --build ${CMAKE_BINARY_DIR} --target ${target}_make_apk"
"--apk" "${android_build_dir}/${target}.apk"
"--ndk-stack" "${ANDROID_NDK_ROOT}/ndk-stack"
- PARENT_SCOPE
)
+
+ if(QT_USE_ANDROID_MODERN_BUNDLE)
+ _qt_internal_android_get_target_deployment_dir(target_deployment_dir ${target})
+ list(APPEND ${out_test_arguments} "--manifest" "${target_deployment_dir}/AndroidManifest.xml")
+ endif()
+
+ set(${out_test_arguments} "${${out_test_arguments}}" PARENT_SCOPE)
endfunction()
diff --git a/src/3rdparty/gradle/gradle.properties b/src/3rdparty/gradle/gradle.properties
index 4fe1674abd3..3472b396d96 100644
--- a/src/3rdparty/gradle/gradle.properties
+++ b/src/3rdparty/gradle/gradle.properties
@@ -16,3 +16,6 @@ org.gradle.parallel=true
# Allow AndroidX usage
android.useAndroidX=true
+
+# User-defined properties
+@EXTRA_PROPERTIES@
diff --git a/src/android/CMakeLists.txt b/src/android/CMakeLists.txt
index 7c99ce7264e..12fbca624b3 100644
--- a/src/android/CMakeLists.txt
+++ b/src/android/CMakeLists.txt
@@ -9,6 +9,7 @@ if (ANDROID)
add_subdirectory(java)
add_subdirectory(templates)
add_subdirectory(templates_aar)
+ add_subdirectory(templates_cmake)
endif()
qt_internal_add_java_documentation(Global)
diff --git a/src/android/REUSE.toml b/src/android/REUSE.toml
index 7d5a22fd2f7..6d821d52904 100644
--- a/src/android/REUSE.toml
+++ b/src/android/REUSE.toml
@@ -1,7 +1,7 @@
version = 1
[[annotations]]
-path = ["jar/build.gradle", "jar/settings.gradle", "templates/build.gradle"]
+path = ["jar/build.gradle", "jar/settings.gradle", "templates/build.gradle", "templates_cmake/**"]
precedence = "closest"
comment = "double check"
SPDX-FileCopyrightText = "Copyright (C) 2024 The Qt Company Ltd."
diff --git a/src/android/templates_cmake/CMakeLists.txt b/src/android/templates_cmake/CMakeLists.txt
new file mode 100644
index 00000000000..253626e3b53
--- /dev/null
+++ b/src/android/templates_cmake/CMakeLists.txt
@@ -0,0 +1,24 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+set(templates_files
+ "${CMAKE_CURRENT_SOURCE_DIR}/settings.gradle.in"
+ "${CMAKE_CURRENT_SOURCE_DIR}/build.gradle.in"
+ "${CMAKE_CURRENT_SOURCE_DIR}/gradle.properties.in"
+)
+
+add_custom_target(Qt6AndroidCMakeTemplates
+ SOURCES
+ ${templates_files}
+)
+
+qt_path_join(destination ${QT_INSTALL_DIR} ${INSTALL_DATADIR} "src/android/templates_cmake")
+
+qt_copy_or_install(FILES ${templates_files} DESTINATION "${destination}")
+
+if(NOT QT_WILL_INSTALL)
+ qt_internal_copy_at_build_time(TARGET Qt6AndroidCMakeTemplates
+ FILES ${templates_files}
+ DESTINATION ${destination}
+ )
+endif()
diff --git a/src/android/templates_cmake/build.gradle.in b/src/android/templates_cmake/build.gradle.in
new file mode 100644
index 00000000000..a76172594bd
--- /dev/null
+++ b/src/android/templates_cmake/build.gradle.in
@@ -0,0 +1,53 @@
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:8.6.0'
+ }
+}
+
+apply plugin: '@GRADLE_PLUGIN_TYPE@'
+
+dependencies {
+ @GRADLE_DEPENDENCIES@
+}
+
+android {
+ namespace '@PACKAGE_NAME@'
+ compileSdkVersion '@ANDROID_COMPILE_SDK_VERSION@'
+ buildToolsVersion '@ANDROID_BUILD_TOOLS_VERSION@'
+ ndkVersion '@ANDROID_NDK_REVISION@'
+
+ defaultConfig {
+ @DEFAULT_CONFIG_VALUES@
+ }
+
+ sourceSets {
+ main {
+@SOURCE_SETS@
+ }
+ }
+
+ tasks.withType(JavaCompile) {
+ options.incremental = true
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+
+ // Do not compress Qt binary resources file
+ aaptOptions {
+ noCompress 'rcc'
+ }
+
+ @ANDROID_DEPLOYMENT_EXTRAS@
+}
diff --git a/src/android/templates_cmake/gradle.properties.in b/src/android/templates_cmake/gradle.properties.in
new file mode 100644
index 00000000000..b751946190a
--- /dev/null
+++ b/src/android/templates_cmake/gradle.properties.in
@@ -0,0 +1,12 @@
+# Project-wide Gradle settings.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2500m -XX:MaxMetaspaceSize=768m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+
+# Enable building projects in parallel
+org.gradle.parallel=true
+
+# Allow AndroidX usage
+android.useAndroidX=true
diff --git a/src/android/templates_cmake/settings.gradle.in b/src/android/templates_cmake/settings.gradle.in
new file mode 100644
index 00000000000..4aca55ffd6d
--- /dev/null
+++ b/src/android/templates_cmake/settings.gradle.in
@@ -0,0 +1,17 @@
+pluginManagement {
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.name = "@ROOT_PROJECT_NAME@"
+include(":app")
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index 4d83bbf794e..bdf0bee8166 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -16,7 +16,9 @@ qt_internal_extend_sbom(WrapZLIB::WrapZLIB
if(ANDROID)
set(corelib_extra_cmake_files
- "${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}AndroidMacros.cmake")
+ "${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}AndroidMacros.cmake"
+ "${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}AndroidGradleHelpers.cmake"
+ )
endif()
if(WASM)
set(corelib_extra_cmake_files
diff --git a/src/corelib/Qt6AndroidGradleHelpers.cmake b/src/corelib/Qt6AndroidGradleHelpers.cmake
new file mode 100644
index 00000000000..889438ffaad
--- /dev/null
+++ b/src/corelib/Qt6AndroidGradleHelpers.cmake
@@ -0,0 +1,305 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# Generates the settings.gradle file for the target. Writes the result to the target android build
+# directory.
+function(_qt_internal_android_generate_bundle_settings_gradle target)
+ set(settings_gradle_filename "settings.gradle")
+ _qt_internal_android_template_dir(template_directory)
+ set(template_file "${template_directory}/${settings_gradle_filename}.in")
+
+ set(android_app_name "$<TARGET_PROPERTY:${target},QT_ANDROID_APP_NAME>")
+ string(JOIN "" ROOT_PROJECT_NAME
+ "$<IF:$<BOOL:${android_app_name}>,"
+ "${android_app_name},"
+ "${target}"
+ ">"
+ )
+
+ _qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
+ set(settings_gradle_file "${android_build_dir}/${settings_gradle_filename}")
+
+ _qt_internal_configure_file(GENERATE OUTPUT ${settings_gradle_file}
+ INPUT "${template_file}")
+endfunction()
+
+# Generates the build.gradle file for the target. Writes the result to the target app deployment
+# directory.
+function(_qt_internal_android_generate_target_build_gradle target)
+ # TODO: The current build.gradle.in templates hardcodes couple values that needs to be
+ # configurable in the future. For example the buildscript dependencies, or the use of
+ # androidx.core:core:1.13.1 and the dependency for all user applications.
+
+ _qt_internal_android_get_gradle_property(PACKAGE_NAME ${target}
+ QT_ANDROID_PACKAGE_NAME "org.qtproject.example.$<MAKE_C_IDENTIFIER:${target}>")
+
+ _qt_internal_android_get_target_sdk_build_tools_revision(ANDROID_BUILD_TOOLS_VERSION
+ ${target})
+
+ _qt_internal_detect_latest_android_platform(ANDROID_COMPILE_SDK_VERSION)
+ if(NOT ANDROID_COMPILE_SDK_VERSION)
+ message(FATAL_ERROR "Unable to detect the android platform in ${ANDROID_SDK_ROOT}. "
+ "Please check your Android SDK installation.")
+ endif()
+
+ _qt_internal_android_java_dir(android_java_dir)
+ string(JOIN "\n " SOURCE_SETS
+ "manifest.srcFile 'AndroidManifest.xml'"
+ "java.srcDirs = ['${android_java_dir}/src', 'src', 'java']"
+ "aidl.srcDirs = ['${android_java_dir}/src', 'src', 'aidl']"
+ "res.srcDirs = ['${android_java_dir}/res', 'res']"
+ "resources.srcDirs = ['resources']"
+ "renderscript.srcDirs = ['src']"
+ "assets.srcDirs = ['assets']"
+ "jniLibs.srcDirs = ['libs']"
+ )
+
+ string(JOIN "\n " GRADLE_DEPENDENCIES
+ "implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])"
+ "//noinspection GradleDependency"
+ "implementation 'androidx.core:core:1.13.1'"
+ )
+
+ _qt_internal_android_get_gradle_property(min_sdk_version ${target}
+ QT_ANDROID_MIN_SDK_VERSION "28")
+
+ _qt_internal_android_get_gradle_property(target_sdk_version ${target}
+ QT_ANDROID_TARGET_SDK_VERSION "34")
+
+ set(target_abis "$<TARGET_PROPERTY:${target},_qt_android_abis>")
+ set(target_abi_list "$<JOIN:${target_abis};${CMAKE_ANDROID_ARCH_ABI},'$<COMMA> '>")
+
+ string(JOIN "\n " DEFAULT_CONFIG_VALUES
+ "resConfig 'en'"
+ "minSdkVersion ${min_sdk_version}"
+ "targetSdkVersion ${target_sdk_version}"
+ "ndk.abiFilters = ['${target_abi_list}']"
+ )
+
+ set(ANDROID_DEPLOYMENT_EXTRAS "")
+
+ get_target_property(android_target_type ${target} _qt_android_target_type)
+ if(android_target_type STREQUAL "APPLICATION")
+ set(GRADLE_PLUGIN_TYPE "com.android.application")
+ else()
+ message(FATAL_ERROR "Unsupported target type for android bundle deployment ${target}")
+ endif()
+
+ _qt_internal_android_get_target_deployment_dir(target_deployment_dir ${target})
+ set(build_gradle_filename "build.gradle")
+ set(build_gradle_file "${target_deployment_dir}/${build_gradle_filename}")
+ _qt_internal_android_template_dir(template_directory)
+ _qt_internal_configure_file(GENERATE OUTPUT "${build_gradle_file}"
+ INPUT "${template_directory}/${build_gradle_filename}.in")
+endfunction()
+
+# Prepares the artifacts for the gradle build of the target.
+function(_qt_internal_android_prepare_gradle_build target)
+ _qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
+ _qt_internal_android_get_target_deployment_dir(deployment_dir ${target})
+
+ _qt_internal_android_copy_gradle_files(${target} "${android_build_dir}")
+
+ _qt_internal_android_generate_bundle_gradle_properties(${target})
+ _qt_internal_android_generate_bundle_settings_gradle(${target})
+ _qt_internal_android_generate_bundle_local_properties(${target})
+ _qt_internal_android_generate_target_build_gradle(${target})
+ _qt_internal_android_generate_target_gradle_properties(${target})
+
+ set(gradle_scripts
+ "${android_build_dir}/gradle.properties"
+ "${android_build_dir}/local.properties"
+ "${android_build_dir}/settings.gradle"
+ "${deployment_dir}/build.gradle"
+ "${deployment_dir}/gradle.properties"
+ )
+ set_target_properties(${target} PROPERTIES _qt_android_deployment_files "${gradle_scripts}")
+
+ _qt_internal_android_add_gradle_build(${target} apk)
+ _qt_internal_android_add_gradle_build(${target} aab)
+
+ # Make global apk, aab, and aar targets depend on the respective targets.
+ _qt_internal_android_add_global_package_dependencies(${target})
+ _qt_internal_create_global_apk_all_target_if_needed()
+endfunction()
+
+# Adds the modern gradle build targets.
+# These targets use the settings.gradle based build directory structure.
+function(_qt_internal_android_add_gradle_build target type)
+ _qt_internal_android_get_deployment_type_option(android_deployment_type_option
+ "assembleRelease" "assembleDebug")
+
+ _qt_internal_android_gradlew_name(gradlew_file_name)
+ _qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
+ set(gradlew "${android_build_dir}/${gradlew_file_name}")
+
+ set(extra_args "")
+ if(type STREQUAL "aab")
+ set(extra_args "bundle")
+ endif()
+
+ set(package_file_path "${android_build_dir}/${target}.${type}")
+
+ _qt_internal_android_package_path(package_build_dir ${target} ${type})
+ _qt_internal_android_get_deployment_type_option(deployment_type_suffix
+ "release" "debug")
+ set(package_build_file_path
+ "${package_build_dir}/${deployment_type_suffix}/app-${deployment_type_suffix}.${type}")
+
+ set(gradle_scripts "$<TARGET_PROPERTY:${target},_qt_android_deployment_files>")
+ add_custom_command(OUTPUT "${package_file_path}"
+ BYPRODUCTS "${package_build_file_path}"
+ COMMAND
+ "${gradlew}" ${android_deployment_type_option} ${extra_args}
+ COMMAND
+ ${CMAKE_COMMAND} -E copy_if_different
+ "${package_build_file_path}" "${package_file_path}"
+ DEPENDS
+ ${target}
+ ${gradle_scripts}
+ ${target}_copy_gradle_files
+ ${target}_android_deploy_aux
+ WORKING_DIRECTORY
+ "${android_build_dir}"
+ VERBATIM
+ )
+
+ add_custom_target(${target}_make_${type} DEPENDS "${package_file_path}")
+endfunction()
+
+# Returns the path to the android executable package either apk or aab.
+function(_qt_internal_android_package_path out_var target type)
+ set(supported_package_types apk aab)
+ if(NOT type IN_LIST supported_package_types)
+ message(FATAL_ERROR "Invalid package type, supported types: ${supported_package_types}")
+ endif()
+
+ # aab packages are located in the bundle directory
+ if(type STREQUAL "aab")
+ set(type "bundle")
+ endif()
+
+ _qt_internal_android_get_target_deployment_dir(deployment_dir ${target})
+
+ set(${out_var} "${deployment_dir}/build/outputs/${type}" PARENT_SCOPE)
+endfunction()
+
+# Returns the path to the gradle build directory.
+function(_qt_internal_android_gradle_template_dir out_var)
+ if(PROJECT_NAME STREQUAL "QtBase" OR QT_SUPERBUILD)
+ set(${out_var} "${QtBase_SOURCE_DIR}/src/3rdparty/gradle" PARENT_SCOPE)
+ else()
+ set(${out_var} "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_DATA}/src/3rdparty/gradle" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Returns the path to the android java dir.
+function(_qt_internal_android_java_dir out_var)
+ if(PROJECT_NAME STREQUAL "QtBase" OR QT_SUPERBUILD)
+ set(${out_var} "${QtBase_SOURCE_DIR}/src/android/java" PARENT_SCOPE)
+ else()
+ set(${out_var} "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_DATA}/src/android/java" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Returns the platform-spefic name of the gradlew script.
+function(_qt_internal_android_gradlew_name out_var)
+ if(CMAKE_HOST_WIN32)
+ set(gradlew_file_name "gradlew.bat")
+ else()
+ set(gradlew_file_name "gradlew")
+ endif()
+
+ set(${out_var} "${gradlew_file_name}" PARENT_SCOPE)
+endfunction()
+
+# Return the path to the gradlew script.
+function(_qt_internal_android_gradlew_path out_var target)
+ _qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
+ set(${out_var} "${android_build_dir}/${gradlew_file_name}" PARENT_SCOPE)
+endfunction()
+
+# Returns the generator expression for the gradle_property value. Defaults to the default_value
+# argument.
+function(_qt_internal_android_get_gradle_property out_var target target_property default_value)
+ set(target_property_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:${target},${target_property}>>")
+ string(JOIN "" result
+ "$<IF:$<BOOL:${target_property_genex}>,"
+ "${target_property_genex},"
+ "${default_value}"
+ ">"
+ )
+ set(${out_var} "${result}" PARENT_SCOPE)
+endfunction()
+
+# Generates gradle.properties for the specific target. Usually contains the
+# target build type(executable, dynamic feature, library).
+function(_qt_internal_android_generate_target_gradle_properties target)
+ set(gradle_properties "gradle.properties")
+ _qt_internal_android_template_dir(template_directory)
+ set(template_file "${template_directory}/${gradle_properties}.in")
+ _qt_internal_android_get_target_deployment_dir(deployment_dir ${target})
+
+ _qt_internal_configure_file(CONFIGURE OUTPUT "${deployment_dir}/${gradle_properties}"
+ INPUT "${template_file}")
+endfunction()
+
+# Generates the top-level gradle.properties in the android-build directory
+# The file contains the information about the versions of the android build
+# tools, the list of supported ABIs.
+function(_qt_internal_android_generate_bundle_gradle_properties target)
+ set(EXTRA_PROPERTIES "")
+
+ set(gradle_properties_file_name "gradle.properties")
+ _qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
+ _qt_internal_android_template_dir(template_directory)
+ set(template_file "${template_directory}/${gradle_properties_file_name}.in")
+ _qt_internal_configure_file(CONFIGURE
+ OUTPUT "${android_build_dir}/${gradle_properties_file_name}"
+ INPUT "${template_file}"
+ )
+endfunction()
+
+# Generates the local.properties for gradle builds. Contains the path to the
+# Android SDK root.
+function(_qt_internal_android_generate_bundle_local_properties target)
+ _qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
+
+ file(TO_CMAKE_PATH "${ANDROID_SDK_ROOT}" ANDROID_SDK_ROOT_NATIVE)
+ _qt_internal_configure_file(CONFIGURE OUTPUT "${android_build_dir}/local.properties"
+ CONTENT "sdk.dir=${ANDROID_SDK_ROOT_NATIVE}\n")
+endfunction()
+
+# Copies gradle scripts to a build directory.
+function(_qt_internal_android_copy_gradle_files target output_directory)
+ _qt_internal_android_gradlew_name(gradlew_file_name)
+ _qt_internal_android_gradle_template_dir(gradle_template_dir)
+
+ set(gradlew_file_src "${gradle_template_dir}/${gradlew_file_name}")
+ set(gradlew_file_dst "${output_directory}/${gradlew_file_name}")
+
+ add_custom_command(OUTPUT "${gradlew_file_dst}"
+ COMMAND
+ ${CMAKE_COMMAND} -E copy_if_different "${gradlew_file_src}" "${gradlew_file_dst}"
+ DEPENDS "${gradlew_file_src}"
+ COMMENT "Copying gradlew script for ${target}"
+ VERBATIM
+ )
+
+ # TODO: make a more precise directory copying
+ set(gradle_dir_src "${gradle_template_dir}/gradle")
+ set(gradle_dir_dst "${output_directory}/gradle")
+ add_custom_command(OUTPUT "${gradle_dir_dst}"
+ COMMAND
+ ${CMAKE_COMMAND} -E copy_directory "${gradle_dir_src}" "${gradle_dir_dst}"
+ DEPENDS "${gradle_dir_src}"
+ COMMENT "Copying gradle support files for ${target}"
+ VERBATIM
+ )
+
+ add_custom_target(${target}_copy_gradle_files
+ DEPENDS
+ "${gradlew_file_dst}"
+ "${gradle_dir_dst}"
+ )
+endfunction()
diff --git a/src/corelib/Qt6AndroidMacros.cmake b/src/corelib/Qt6AndroidMacros.cmake
index aa0e5bfed24..960ca73778b 100644
--- a/src/corelib/Qt6AndroidMacros.cmake
+++ b/src/corelib/Qt6AndroidMacros.cmake
@@ -519,18 +519,6 @@ function(qt6_android_add_apk_target target)
">"
)
- # Make global apk and aab targets depend on the current apk target.
- if(TARGET aab)
- add_dependencies(aab ${target}_make_aab)
- endif()
- if(TARGET aar)
- add_dependencies(aar ${target}_make_aar)
- endif()
- if(TARGET apk)
- add_dependencies(apk ${target}_make_apk)
- _qt_internal_create_global_apk_all_target_if_needed()
- endif()
-
_qt_internal_android_get_deployment_tool(deployment_tool)
# No need to use genex for the BINARY_DIR since it's read-only.
@@ -719,6 +707,10 @@ function(qt6_android_add_apk_target target)
)
add_dependencies(${target}_make_aab ${target}_prepare_apk_dir)
+ # Make global apk, aab, and aar targets depend on the respective targets.
+ _qt_internal_android_add_global_package_dependencies(${target})
+ _qt_internal_create_global_apk_all_target_if_needed()
+
if(QT_IS_ANDROID_MULTI_ABI_EXTERNAL_PROJECT)
# When building per-ABI external projects we only need to copy ABI-specific libraries and
# resources to the "main" ABI android build folder.
@@ -1666,7 +1658,15 @@ function(_qt_internal_android_executable_finalizer target)
_qt_internal_configure_android_multiabi_target("${target}")
qt6_android_generate_deployment_settings("${target}")
- qt6_android_add_apk_target("${target}")
+ if(QT_USE_ANDROID_MODERN_BUNDLE)
+ _qt_internal_android_prepare_gradle_build("${target}")
+ _qt_internal_android_add_aux_deployment("${target}")
+
+ _qt_internal_collect_apk_dependencies_defer()
+ _qt_internal_collect_apk_imported_dependencies_defer("${target}")
+ else()
+ qt6_android_add_apk_target("${target}")
+ endif()
_qt_internal_android_create_runner_wrapper("${target}")
endfunction()
@@ -1754,6 +1754,11 @@ function(_qt_internal_android_get_target_android_build_dir out_build_dir target)
endif()
endfunction()
+function(_qt_internal_android_get_target_deployment_dir out_deploy_dir target)
+ _qt_internal_android_get_target_android_build_dir(build_dir ${target})
+ set(${out_deploy_dir} "${build_dir}/app" PARENT_SCOPE)
+endfunction()
+
function(_qt_internal_expose_android_package_source_dir_to_ide target)
get_target_property(android_package_source_dir ${target} QT_ANDROID_PACKAGE_SOURCE_DIR)
if(android_package_source_dir)
@@ -1778,6 +1783,69 @@ function(_qt_internal_expose_android_package_source_dir_to_ide target)
endif()
endfunction()
+function(_qt_internal_android_add_aux_deployment target)
+ cmake_parse_arguments(arg "" "OUTPUT_TARGET_NAME;DEPLOYMENT_DIRECTORY" "EXTRA_ARGS" ${ARGN})
+ _qt_internal_validate_all_args_are_parsed(arg)
+
+ string(JOIN "" deployment_file
+ "$<GENEX_EVAL:"
+ "$<TARGET_PROPERTY:${target},QT_ANDROID_DEPLOYMENT_SETTINGS_FILE>"
+ ">"
+ )
+
+ _qt_internal_android_get_deployment_tool(deployment_tool)
+ if(arg_DEPLOYMENT_DIRECTORY)
+ set(deployment_dir "${arg_DEPLOYMENT_DIRECTORY}")
+ else()
+ _qt_internal_android_get_target_deployment_dir(deployment_dir ${target})
+ endif()
+
+ set(android_manifest "${deployment_dir}/AndroidManifest.xml")
+
+ cmake_policy(PUSH)
+ if(POLICY CMP0116)
+ # Without explicitly setting this policy to NEW, we get a warning
+ # even though we ensure there's actually no problem here.
+ # See https://gitlab.kitware.com/cmake/cmake/-/issues/21959
+ cmake_policy(SET CMP0116 NEW)
+ set(relative_to_dir ${CMAKE_CURRENT_BINARY_DIR})
+ else()
+ set(relative_to_dir ${CMAKE_BINARY_DIR})
+ endif()
+
+ set(target_file_copy_relative_path
+ "libs/${CMAKE_ANDROID_ARCH_ABI}/$<TARGET_FILE_NAME:${target}>")
+ _qt_internal_copy_file_if_different_command(copy_command
+ "$<TARGET_FILE:${target}>"
+ "${deployment_dir}/${target_file_copy_relative_path}"
+ )
+
+ _qt_internal_android_get_use_terminal_for_deployment(uses_terminal)
+
+ add_custom_command(OUTPUT "${android_manifest}"
+ COMMAND ${copy_command}
+ COMMAND "${deployment_tool}"
+ --input "${deployment_file}"
+ --output "${deployment_dir}"
+ --builddir "${relative_to_dir}"
+ --aux-mode
+ ${arg_EXTRA_ARGS}
+ #TODO: Support signing
+ COMMENT "Deploying Android artifacts for ${target}"
+ DEPENDS "${target}" "${deployment_file}"
+ VERBATIM
+ ${uses_terminal}
+ )
+
+ if(NOT arg_OUTPUT_TARGET_NAME)
+ set(arg_OUTPUT_TARGET_NAME ${target}_android_deploy_aux)
+ endif()
+
+ add_custom_target(${arg_OUTPUT_TARGET_NAME} DEPENDS "${android_manifest}")
+
+ cmake_policy(POP)
+endfunction()
+
# Enables the terminal usage for the add_custom_command calls when verbose deployment is enabled.
function(_qt_internal_android_get_use_terminal_for_deployment out_var)
if(QT_ENABLE_VERBOSE_DEPLOYMENT)
@@ -1822,6 +1890,28 @@ function(_qt_internal_android_get_deployment_type_option out_var release_flag de
endif()
endfunction()
+# Returns the path to the android template directory, that are used by CMake
+# deployment procedures.
+function(_qt_internal_android_template_dir out_var)
+ if(PROJECT_NAME STREQUAL "QtBase" OR QT_SUPERBUILD)
+ set(${out_var} "${QtBase_SOURCE_DIR}/src/android/templates_cmake" PARENT_SCOPE)
+ else()
+ set(${out_var}
+ "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_DATA}/src/android/templates_cmake" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Add target_make_<apk|aab> as the depednecy for the respective global apk/aab
+# target.
+function(_qt_internal_android_add_global_package_dependencies target)
+ foreach(type apk aab aar)
+ # Make global apk and aab targets depend on the current apk target.
+ if(TARGET ${type} AND TARGET ${target}_make_${type})
+ add_dependencies(${type} ${target}_make_${type})
+ endif()
+ endforeach()
+endfunction()
+
function(_qt_internal_android_get_target_abis out_abis target)
get_target_property(target_abis ${target} QT_ANDROID_ABIS)
if(target_abis)
diff --git a/src/corelib/Qt6CoreConfigExtras.cmake.in b/src/corelib/Qt6CoreConfigExtras.cmake.in
index 15405197a61..37155ac716b 100644
--- a/src/corelib/Qt6CoreConfigExtras.cmake.in
+++ b/src/corelib/Qt6CoreConfigExtras.cmake.in
@@ -30,6 +30,7 @@ _qt_internal_setup_deploy_support()
if(ANDROID_PLATFORM)
include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
+ include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
_qt_internal_create_global_android_targets()
_qt_internal_collect_default_android_abis()
if(__qt_Core_targets_file_included)
diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp
index e93c3038fca..4e888551445 100644
--- a/src/tools/androiddeployqt/main.cpp
+++ b/src/tools/androiddeployqt/main.cpp
@@ -1580,8 +1580,11 @@ bool copyAndroidTemplate(const Options &options)
if (options.verbose)
fprintf(stdout, "Copying Android package template.\n");
- if (!copyGradleTemplate(options))
- return false;
+ if (!options.auxMode) {
+ // Gradle is not configured and is not running in aux mode
+ if (!copyGradleTemplate(options))
+ return false;
+ }
if (!copyAndroidTemplate(options, "/src/android/templates"_L1))
return false;
diff --git a/tests/auto/corelib/platform/CMakeLists.txt b/tests/auto/corelib/platform/CMakeLists.txt
index 3a66ec2eae6..9810947e3c6 100644
--- a/tests/auto/corelib/platform/CMakeLists.txt
+++ b/tests/auto/corelib/platform/CMakeLists.txt
@@ -5,7 +5,9 @@ if(ANDROID)
add_subdirectory(android)
add_subdirectory(android_appless)
add_subdirectory(androiditemmodel)
- add_subdirectory(android_legacy_packaging)
+ if(NOT QT_USE_ANDROID_MODERN_BUNDLE)
+ add_subdirectory(android_legacy_packaging)
+ endif()
endif()
if(WIN32)
add_subdirectory(windows)