4#include <QCoreApplication>
7#include <QJsonDocument>
13#include <QXmlStreamReader>
14#include <QStandardPaths>
16#include <QDirIterator>
17#include <QElapsedTimer>
18#include <QRegularExpression>
29#if defined(Q_OS_WIN32)
35#define QT_POPEN_READ "rb"
38#define QT_POPEN_READ "r"
49#if defined(Q_OS_WIN32)
50 QString processedCommand = u
'\"' + command + u
'\"';
52 const QString& processedCommand = command;
100 ,
sigAlg(
"SHA256withRSA"_L1)
244 {
"aarch64",
"arm64-v8a"},
245 {
"arm",
"armeabi-v7a"},
260 if (!
match.hasMatch())
262 return match.captured(1);
267#if defined(Q_OS_WIN32)
275#if defined(Q_OS_WIN32)
306 fprintf(stderr,
"Command does not exist: %s\n",
qPrintable(readElf));
313 if (!readElfCommand) {
314 fprintf(stderr,
"Cannot execute command %s\n",
qPrintable(readElf));
319 while (fgets(
buffer,
sizeof(
buffer), readElfCommand) !=
nullptr) {
324 pclose(readElfCommand);
328 pclose(readElfCommand);
347 if (
dst.fileName() ==
src.fileName()) {
386 options.
build =
true;
388 options.
build =
false;
411 }
else if (deploymentMechanism.
compare(
"unbundled"_L1,
415 fprintf(stderr,
"Unrecognized deployment mechanism: %s\n",
qPrintable(deploymentMechanism));
452 fprintf(stderr,
"Package signing path and alias values are not specified.\n");
455 "Using package signing path and alias values found from the "
456 "environment variables.\n");
466 fprintf(stderr,
"Package signing path and alias values are not "
472 fprintf(stdout,
"Using package signing store password found from the environment "
477 fprintf(stdout,
"Using package signing key password found from the environment "
531 }
else if (
argument.compare(
"--no-rcc-bundle-cleanup"_L1,
534 }
else if (
argument.compare(
"--copy-dependencies-only"_L1,
563Syntax: androiddeployqt --output <destination> [options]
565Creates an Android package in the build directory <destination> and
566builds it into an .apk file.
569 --input <inputfile>: Reads <inputfile> for options generated by
570 qmake. A default file name based on the current working
571 directory will be used if nothing else is specified.
573 --deployment <mechanism>: Supported deployment mechanisms:
574 bundled (default): Includes Qt files in stand-alone package.
575 unbundled: Assumes native libraries are present on the device
576 and does not include them in the APK.
578 --aab: Build an Android App Bundle.
580 --no-build: Do not build the package, it is useful to just install
581 a package previously built.
583 --install: Installs apk to device/emulator. By default this step is
584 not taken. If the application has previously been installed on
585 the device, it will be uninstalled first.
587 --reinstall: Installs apk to device/emulator. By default this step
588 is not taken. If the application has previously been installed on
589 the device, it will be overwritten, but its data will be left
592 --device [device ID]: Use specified device for deployment. Default
593 is the device selected by default by adb.
595 --android-platform <platform>: Builds against the given android
596 platform. By default, the highest available version will be
599 --release: Builds a package ready for release. By default, the
600 package will be signed with a debug key.
602 --sign <url/to/keystore> <alias>: Signs the package with the
603 specified keystore, alias and store password.
604 Optional arguments for use with signing:
605 --storepass <password>: Keystore password.
606 --storetype <type>: Keystore type.
607 --keypass <password>: Password for private key (if different
608 from keystore password.)
609 --sigfile <file>: Name of .SF/.DSA file.
610 --digestalg <name>: Name of digest algorithm. Default is
612 --sigalg <name>: Name of signature algorithm. Default is
614 --tsa <url>: Location of the Time Stamping Authority.
615 --tsacert <alias>: Public key certificate for TSA.
616 --internalsf: Include the .SF file inside the signature block.
617 --sectionsonly: Don't compute hash of entire manifest.
618 --protected: Keystore has protected authentication path.
619 --jarsigner: Deprecated, ignored.
621 NOTE: To conceal the keystore information, the environment variables
622 QT_ANDROID_KEYSTORE_PATH, and QT_ANDROID_KEYSTORE_ALIAS are used to
623 set the values keysotore and alias respectively.
624 Also the environment variables QT_ANDROID_KEYSTORE_STORE_PASS,
625 and QT_ANDROID_KEYSTORE_KEY_PASS are used to set the store and key
626 passwords respectively. This option needs only the --sign parameter.
628 --jdk <path/to/jdk>: Used to find the jarsigner tool when used
629 in combination with the --release argument. By default,
630 an attempt is made to detect the tool using the JAVA_HOME and
631 PATH environment variables, in that order.
633 --qml-import-paths: Specify additional search paths for QML
636 --verbose: Prints out information during processing.
638 --no-generated-assets-cache: Do not pregenerate the entry list for
639 the assets file engine.
641 --aux-mode: Operate in auxiliary mode. This will only copy the
642 dependencies into the build directory and update the XML templates.
643 The project will not be built or installed.
645 --apk <path/where/to/copy/the/apk>: Path where to copy the built apk.
647 --qml-importscanner-binary <path/to/qmlimportscanner>: Override the
648 default qmlimportscanner binary path. By default the
649 qmlimportscanner binary is located using the Qt directory
650 specified in the input file.
652 --depfile <path/to/depfile>: Output a dependency file.
654 --builddir <path/to/build/directory>: build directory. Necessary when
655 generating a depfile because ninja requires relative paths.
657 --no-rcc-bundle-cleanup: skip cleaning rcc bundle directory after
658 running androiddeployqt. This option simplifies debugging of
659 the resource bundle content, but it should not be used when deploying
660 a project, since it litters the 'assets' directory.
662 --copy-dependencies-only: resolve application dependencies and stop
663 deploying process after all libraries and resources that the
664 application depends on have been copied.
666 --help: Displays this information.
678 if (
s1.size() ==
s2.size())
681 return s1.size() >
s2.size();
688 return (
fileName.endsWith(
"/res/values/libs.xml"_L1)
689 ||
fileName.endsWith(
"/AndroidManifest.xml"_L1)
690 ||
fileName.endsWith(
"/res/values/strings.xml"_L1)
691 ||
fileName.endsWith(
"/src/org/qtproject/qt/android/bindings/QtActivity.java"_L1));
696 const QString &destinationFileName,
698 bool forceOverwrite =
false)
702 QFileInfo destinationFileInfo(destinationFileName);
703 QFileInfo sourceFileInfo(sourceFileName);
709 fprintf(stdout,
" -- Skipping file %s. Same or newer file already in place.\n",
qPrintable(sourceFileName));
713 fprintf(stderr,
"Can't remove old file: %s\n",
qPrintable(destinationFileName));
720 fprintf(stderr,
"Cannot make output directory for %s.\n",
qPrintable(destinationFileName));
725 fprintf(stderr,
"Failed to copy %s to %s.\n",
qPrintable(sourceFileName),
qPrintable(destinationFileName));
728 fprintf(stdout,
" -- Copied %s\n",
qPrintable(destinationFileName));
736 auto isLegalChar = [] (
QChar c) ->
bool {
738 return (
ch >=
'0' &&
ch <=
'9') ||
739 (
ch >=
'A' &&
ch <=
'Z') ||
740 (
ch >=
'a' &&
ch <=
'z') ||
743 for (
QChar &
c : packageName) {
750 keywords <<
"abstract"_L1 <<
"continue"_L1 <<
"for"_L1
751 <<
"new"_L1 <<
"switch"_L1 <<
"assert"_L1
752 <<
"default"_L1 <<
"if"_L1 <<
"package"_L1
753 <<
"synchronized"_L1 <<
"boolean"_L1 <<
"do"_L1
754 <<
"goto"_L1 <<
"private"_L1 <<
"this"_L1
755 <<
"break"_L1 <<
"double"_L1 <<
"implements"_L1
756 <<
"protected"_L1 <<
"throw"_L1 <<
"byte"_L1
757 <<
"else"_L1 <<
"import"_L1 <<
"public"_L1
758 <<
"throws"_L1 <<
"case"_L1 <<
"enum"_L1
759 <<
"instanceof"_L1 <<
"return"_L1 <<
"transient"_L1
760 <<
"catch"_L1 <<
"extends"_L1 <<
"int"_L1
761 <<
"short"_L1 <<
"try"_L1 <<
"char"_L1
762 <<
"final"_L1 <<
"interface"_L1 <<
"static"_L1
763 <<
"void"_L1 <<
"class"_L1 <<
"finally"_L1
764 <<
"long"_L1 <<
"strictfp"_L1 <<
"volatile"_L1
765 <<
"const"_L1 <<
"float"_L1 <<
"native"_L1
766 <<
"super"_L1 <<
"while"_L1;
778 if ((
c >= u
'0' &&
c <= u
'9') ||
c == u
'_') {
797 QDir dir(sdkPath +
"/platforms"_L1);
799 fprintf(stderr,
"Directory %s does not exist\n",
qPrintable(
dir.absolutePath()));
805 fprintf(stderr,
"No platforms found in %s",
qPrintable(
dir.absolutePath()));
817 QFile androidManifestXml(androidManifestPath);
819 QXmlStreamReader reader(&androidManifestXml);
820 while (!reader.atEnd()) {
822 if (reader.isStartElement() && reader.name() ==
"manifest"_L1)
823 return cleanPackageName(reader.attributes().value(
"package"_L1).toString());
836 || stringValue.
toInt() > 0);
844 if (
keyName ==
"qtDataDirectory"_L1) {
847 }
else if (
keyName ==
"qtLibsDirectory"_L1) {
850 }
else if (
keyName ==
"qtLibExecsDirectory"_L1) {
853 }
else if (
keyName ==
"qtPluginsDirectory"_L1) {
856 }
else if (
keyName ==
"qtQmlDirectory"_L1) {
866 for (
auto it =
object.constBegin();
it !=
object.
constEnd(); ++
it) {
867 if (
it.value().isUndefined()) {
869 "Invalid '%s' record in deployment settings: %s\n",
874 if (
it.value().isNull())
877 fprintf(stderr,
"Architecture %s unknown (%s).",
qPrintable(
it.key()),
883 }
else if (qtDirectory.
isString()) {
892 fprintf(stderr,
"Invalid format for %s in json file %s.\n",
909 if (jsonDocument.
isNull()) {
931 fprintf(stderr,
"Warning: Android platform '%s' does not exist in SDK.\n",
940 if (!
value.isUndefined())
951 if (qtInstallDirectory.
isObject()) {
953 for (
auto it =
object.constBegin();
it !=
object.
constEnd(); ++
it) {
954 if (
it.value().isUndefined()) {
956 "Invalid 'qt' record in deployment settings: %s\n",
960 if (
it.value().isNull())
965 }
else if (qtInstallDirectory.
isString()) {
979 fprintf(stderr,
"Invalid format for Qt install prefixes in json file %s.\n",
998 fprintf(stderr,
"Invalid format for Qt host directory in json file %s.\n",
1006 const auto extraPrefixDirs = jsonObject.
value(
"extraPrefixDirs"_L1).
toArray();
1008 for (
const QJsonValue prefix : extraPrefixDirs) {
1014 const auto extraLibraryDirs = jsonObject.
value(
"extraLibraryDirs"_L1).
toArray();
1022 const QJsonValue androidSourcesDirectory = jsonObject.
value(
"android-package-source-directory"_L1);
1028 const QJsonValue applicationArguments = jsonObject.
value(
"android-application-arguments"_L1);
1036 const QJsonValue androidVersionName = jsonObject.
value(
"android-version-name"_L1);
1044 const QJsonValue androidVersionCode = jsonObject.
value(
"android-version-code"_L1);
1052 const QJsonValue ver = jsonObject.
value(
"android-min-sdk-version"_L1);
1058 const QJsonValue ver = jsonObject.
value(
"android-target-sdk-version"_L1);
1065 if (targetArchitectures.
isEmpty()) {
1066 fprintf(stderr,
"No target architecture defined in json file.\n");
1070 if (
it.value().isUndefined()) {
1071 fprintf(stderr,
"Invalid architecture.\n");
1074 if (
it.value().isNull())
1077 fprintf(stderr,
"Architecture %s unknown (%s).",
qPrintable(
it.key()),
1089 fprintf(stderr,
"No NDK path defined in json file.\n");
1097 fprintf(stderr,
"Couldn't retrieve the NDK version from \"%s\".\n",
1105 const QJsonValue toolchainPrefix = jsonObject.
value(
"toolchain-prefix"_L1);
1107 fprintf(stderr,
"No toolchain prefix defined in json file.\n");
1116 fprintf(stderr,
"No NDK host defined in json file.\n");
1123 const QJsonValue extraLibs = jsonObject.
value(
"android-extra-libs"_L1);
1129 const QJsonValue qmlSkipImportScanning = jsonObject.
value(
"qml-skip-import-scanning"_L1);
1135 const QJsonValue extraPlugins = jsonObject.
value(
"android-extra-plugins"_L1);
1142 jsonObject.
value(
"android-system-libs-prefix"_L1);
1148 const QJsonValue noDeploy = jsonObject.
value(
"android-no-deploy-qt-libs"_L1);
1159 fprintf(stderr,
"No stdcpp-path defined in json file.\n");
1169 }
else if (qmlRootPath.
isArray()) {
1170 auto qmlRootPaths = qmlRootPath.
toArray();
1171 for (
auto path : qmlRootPaths) {
1172 if (
path.isString())
1181 const QJsonValue qmlImportPaths = jsonObject.
value(
"qml-import-paths"_L1);
1187 const QJsonValue qmlImportScannerBinaryPath = jsonObject.
value(
"qml-importscanner-binary"_L1);
1199 const QJsonValue applicationBinary = jsonObject.
value(
"application-binary"_L1);
1201 fprintf(stderr,
"No application binary defined in json file.\n");
1205 if (options->
build) {
1211 fprintf(stderr,
"Cannot find application binary in build dir %s.\n",
qPrintable(appBinaryPath));
1219 const QJsonValue deploymentDependencies = jsonObject.
value(
"deployment-dependencies"_L1);
1221 QString deploymentDependenciesString = deploymentDependencies.
toString();
1222 const auto dependencies =
QStringView{deploymentDependenciesString}.
split(u
',');
1223 for (
const auto &dependency : dependencies) {
1228 while (iterator.hasNext()) {
1230 if (iterator.fileInfo().isFile()) {
1233 if (!arch.isEmpty()) {
1236 }
else if (options->
verbose) {
1237 fprintf(stderr,
"Skipping \"%s\", unknown architecture\n",
qPrintable(
subPath));
1243 auto qtDependency = [options](
const QStringView &dependency,
1245 const auto installDir = options->
architectures[arch].qtInstallDirectory;
1252 if (!arch.isEmpty()) {
1253 options->
qtDependencies[arch].append(qtDependency(dependency, arch));
1254 }
else if (options->
verbose) {
1255 fprintf(stderr,
"Skipping \"%s\", unknown architecture\n",
qPrintable(
path));
1260 options->
qtDependencies[arch].append(qtDependency(dependency, arch));
1271 const QJsonValue zstdCompressionFlag = jsonObject.
value(
"zstdCompression"_L1);
1272 if (zstdCompressionFlag.
isBool()) {
1292 if (
entry.isDir()) {
1294 if (!destinationDirectory.
mkpath(
dir.dirName())) {
1315 if (
dir.fileName() !=
"libs"_L1)
1334 if (!sourceDirectory.
exists()) {
1353 if (!sourceDirectory.
exists()) {
1370 fprintf(stdout,
"Copying Android package template.\n");
1387 fprintf(stdout,
"Copying Android sources from project.\n");
1390 if (!sourceDirectory.
exists()) {
1406 fprintf(stdout,
"Copying %zd external libraries to package.\n",
size_t(options->
extraLibs.size()));
1409 fprintf(stdout,
"Skip copying of external libraries.\n");
1416 if (!extraLibInfo.
exists()) {
1417 fprintf(stderr,
"External library %s does not exist!\n",
qPrintable(extraLib));
1422 fprintf(stdout,
"Skipping \"%s\", architecture mismatch.\n",
qPrintable(extraLib));
1426 fprintf(stderr,
"The file name of external library %s must begin with \"lib\" and end with the suffix \".so\".\n",
1467 fprintf(stdout,
"Copying %zd external resources to package.\n",
size_t(options->
extraPlugins.size()));
1470 QFileInfo extraResourceInfo(extraResource);
1471 if (!extraResourceInfo.
exists() || !extraResourceInfo.
isDir()) {
1472 fprintf(stderr,
"External resource %s does not exist or not a correct directory!\n",
qPrintable(extraResource));
1476 QDir resourceDir(extraResource);
1485 if (!resourceFile.endsWith(
".so"_L1)) {
1486 destinationFile = assetsDir + resourceFile;
1492 destinationFile = libsDir + resourceFile;
1515 bool hasReplacements =
false;
1518 if (
it.key() ==
it.value())
1525 hasReplacements =
true;
1532 if (hasReplacements) {
1550 fprintf(stdout,
" -- res/values/libs.xml\n");
1554 fprintf(stderr,
"Cannot find %s in prepared packaged. This file is required.\n",
qPrintable(
fileName));
1566 qtLibs +=
" <item>%1;%2</item>\n"_L1.
arg(
it.key(), options->
stdCppName);
1568 if (bundledFile.second.startsWith(
"lib/lib"_L1)) {
1569 if (!bundledFile.second.endsWith(
".so"_L1)) {
1571 "The bundled library %s doesn't end with .so. Android only supports "
1572 "versionless libraries ending with the .so suffix.\n",
1576 QString s = bundledFile.second.
mid(
sizeof(
"lib/lib") - 1);
1577 s.
chop(
sizeof(
".so") - 1);
1578 qtLibs +=
" <item>%1;%2</item>\n"_L1.
arg(
it.key(),
s);
1588 "The library %s doesn't end with .so. Android only supports "
1589 "versionless libraries ending with the .so suffix.\n",
1595 extraLibs +=
" <item>%1;%2</item>\n"_L1.
arg(
it.key(),
name);
1603 if (localLibs.isEmpty()) {
1606 if (qtDependency.relativePath.contains(
"libplugins_platforms_qtforandroid_"_L1))
1607 plugin = qtDependency.relativePath;
1609 if (qtDependency.relativePath.contains(
1611 || qtDependency.relativePath.contains(
1617 if (plugin.isEmpty()) {
1619 fprintf(stderr,
"No platform plugin (libplugins_platforms_qtforandroid.so) included"
1620 " in the deployment. Make sure the app links to Qt Gui library.\n");
1625 localLibs.append(plugin);
1627 fprintf(stdout,
" -- Using platform plugin %s\n",
qPrintable(plugin));
1631 for (
auto &lib : localLibs) {
1632 if (lib.endsWith(
".so"_L1))
1633 lib = lib.mid(lib.lastIndexOf(u
'/') + 1);
1635 allLocalLibs +=
" <item>%1;%2</item>\n"_L1.
arg(
it.key(), localLibs.join(u
':'));
1645 replacements[
QStringLiteral(
"<!-- %%INSERT_INIT_CLASSES%% -->")] = initClasses;
1648 replacements[
QStringLiteral(
"<!-- %%BUNDLE_LOCAL_QT_LIBS%% -->")]
1650 replacements[
QStringLiteral(
"<!-- %%USE_LOCAL_QT_LIBS%% -->")] =
"1"_L1;
1651 replacements[
QStringLiteral(
"<!-- %%SYSTEM_LIBS_PREFIX%% -->")] =
1663 fprintf(stdout,
" -- res/values/strings.xml\n");
1671 fprintf(stdout,
" -- Create strings.xml since it's missing.\n");
1677 file.
write(
QByteArray(
"<?xml version='1.0' encoding='utf-8'?><resources><string name=\"app_name\" translatable=\"false\">")
1679 .append(
"</string></resources>\n"));
1692 fprintf(stdout,
" -- AndroidManifest.xml \n");
1704 permissions +=
" <uses-permission android:name=\"%1\" />\n"_L1.
arg(permission);
1709 features +=
" <uses-feature android:name=\"%1\" android:required=\"false\" />\n"_L1.
arg(feature);
1711 features +=
" <uses-feature android:glEsVersion=\"0x00020000\" android:required=\"true\" />"_L1;
1716 if (!
updateFile(androidManifestPath, replacements))
1720 bool checkOldAndroidLabelString =
false;
1721 QFile androidManifestXml(androidManifestPath);
1722 if (androidManifestXml.
exists()) {
1724 fprintf(stderr,
"Cannot open %s for reading.\n",
qPrintable(androidManifestPath));
1728 QXmlStreamReader reader(&androidManifestXml);
1729 while (!reader.atEnd()) {
1732 if (reader.isStartElement()) {
1733 if (reader.name() ==
"manifest"_L1) {
1734 if (!reader.attributes().hasAttribute(
"package"_L1)) {
1735 fprintf(stderr,
"Invalid android manifest file: %s\n",
qPrintable(androidManifestPath));
1738 options.
packageName = reader.attributes().value(
"package"_L1).toString();
1739 }
else if (reader.name() ==
"uses-sdk"_L1) {
1740 if (reader.attributes().hasAttribute(
"android:minSdkVersion"_L1))
1741 if (reader.attributes().value(
"android:minSdkVersion"_L1).toInt() < 23) {
1742 fprintf(stderr,
"Invalid minSdkVersion version, minSdkVersion must be >= 23\n");
1745 }
else if ((reader.name() ==
"application"_L1 ||
1746 reader.name() ==
"activity"_L1) &&
1747 reader.attributes().hasAttribute(
"android:label"_L1) &&
1748 reader.attributes().value(
"android:label"_L1) ==
"@string/app_name"_L1) {
1749 checkOldAndroidLabelString =
true;
1750 }
else if (reader.name() ==
"meta-data"_L1) {
1751 const auto name = reader.attributes().value(
"android:name"_L1);
1752 const auto value = reader.attributes().value(
"android:value"_L1);
1753 if (
name ==
"android.app.lib_name"_L1 &&
value.contains(u
' ')) {
1754 fprintf(stderr,
"The Activity's android.app.lib_name should not contain"
1762 if (reader.hasError()) {
1767 fprintf(stderr,
"No android manifest file");
1771 if (checkOldAndroidLabelString)
1780 fprintf(stdout,
"Updating Android package files with project settings.\n");
1796 if (relativeFileName.
startsWith(
"lib/"_L1)) {
1805 const QString path = prefix + u
'/' + relativeFileName;
1810 if (relativeFileName.
endsWith(
"-android-dependencies.xml"_L1)) {
1812 u
'/' + relativeFileName;
1815 if (relativeFileName.
startsWith(
"jar/"_L1)) {
1817 u
'/' + relativeFileName;
1820 if (relativeFileName.
startsWith(
"lib/"_L1)) {
1822 u
'/' + relativeFileName.
mid(
sizeof(
"lib/") - 1);
1869 QFile androidDependencyFile(androidDependencyName);
1870 if (androidDependencyFile.
exists()) {
1872 fprintf(stdout,
"Reading Android dependencies for %s\n",
qPrintable(moduleName));
1875 fprintf(stderr,
"Cannot open %s for reading.\n",
qPrintable(androidDependencyName));
1879 QXmlStreamReader reader(&androidDependencyFile);
1880 while (!reader.atEnd()) {
1883 if (reader.isStartElement()) {
1884 if (reader.name() ==
"bundled"_L1) {
1885 if (!reader.attributes().hasAttribute(
"file"_L1)) {
1886 fprintf(stderr,
"Invalid android dependency file: %s\n",
qPrintable(androidDependencyName));
1890 QString file = reader.attributes().value(
"file"_L1).toString();
1898 if (
fileName.absolutePath.endsWith(
".so"_L1)) {
1902 &remainingDependencies)) {
1903 fprintf(stdout,
"Skipping dependencies from xml: %s\n",
1911 fprintf(stdout,
"Appending dependency from xml: %s\n",
qPrintable(
fileName.relativePath));
1915 }
else if (reader.name() ==
"jar"_L1) {
1916 int bundling = reader.attributes().value(
"bundling"_L1).toInt();
1926 if (reader.attributes().hasAttribute(
"initClass"_L1)) {
1927 options->
initClasses.append(reader.attributes().value(
"initClass"_L1).toString());
1929 }
else if (reader.name() ==
"lib"_L1) {
1931 if (reader.attributes().hasAttribute(
"replaces"_L1)) {
1932 QString replaces = reader.attributes().value(
"replaces"_L1).toString();
1945 }
else if (reader.name() ==
"permission"_L1) {
1946 QString name = reader.attributes().value(
"name"_L1).toString();
1948 }
else if (reader.name() ==
"feature"_L1) {
1949 QString name = reader.attributes().value(
"name"_L1).toString();
1955 if (reader.hasError()) {
1959 }
else if (options->
verbose) {
1960 fprintf(stdout,
"No android dependencies for %s\n",
qPrintable(moduleName));
1963 options->
features.removeDuplicates();
1972 fprintf(stderr,
"Command does not exist: %s\n",
qPrintable(readElf));
1979 if (!readElfCommand) {
1980 fprintf(stderr,
"Cannot execute command %s\n",
qPrintable(readElf));
1986 bool readLibs =
false;
1988 while (fgets(
buffer,
sizeof(
buffer), readElfCommand) !=
nullptr) {
2007 QString libraryName =
"lib/"_L1 + library;
2012 pclose(readElfCommand);
2027 for (
const QString &dep : dependencies)
2032 for (
const QString &dependency : dependencies) {
2033 if (usedDependencies->
contains(dependency))
2037 usedDependencies->
insert(dependency);
2039 absoluteDependencyPath,
2041 remainingDependencies)) {
2047 fprintf(stdout,
"Appending dependency: %s\n",
qPrintable(dependency));
2048 dependenciesToCheck.
append(dependency);
2051 for (
const QString &dependency : std::as_const(dependenciesToCheck)) {
2052 QString qtBaseName = dependency.
mid(
sizeof(
"lib/lib") - 1);
2053 qtBaseName = qtBaseName.
left(qtBaseName.
size() - (
sizeof(
".so") - 1));
2065 fprintf(stdout,
"Scanning for QML imports.\n");
2072 "/qmlimportscanner"_L1);
2089 importPaths +=
shellQuote(prefix +
"/qml"_L1);
2096 fprintf(stderr,
"Warning: QML import path %s does not exist.\n",
2101 bool qmlImportExists =
false;
2103 for (
const QString &
import : importPaths) {
2105 qmlImportExists =
true;
2112 if (!qmlImportExists) {
2113 fprintf(stderr,
"Warning: no 'qml' directory found under Qt install directory "
2114 "or import paths. Skipping QML dependency scanning.\n");
2119 fprintf(stderr,
"%s: qmlimportscanner not found at %s\n",
2120 qmlImportExists ?
"Error"_L1.data() :
"Warning"_L1.data(),
2125 for (
auto rootPath : options->
rootPaths) {
2128 if (!rootPath.endsWith(u
'/'))
2132 if (!rootPath.isEmpty())
2135 qmlImportScanner +=
" -rootPath %1"_L1.
arg(
shellQuote(rootPath));
2138 if (!options->
qrcFiles.isEmpty()) {
2139 qmlImportScanner +=
" -qrcFiles"_L1;
2141 qmlImportScanner += u
' ' +
shellQuote(qrcFile);
2144 qmlImportScanner +=
" -importPath %1"_L1.
arg(importPaths.join(u
' '));
2147 fprintf(stdout,
"Running qmlimportscanner with the following command: %s\n",
2152 if (qmlImportScannerCommand == 0) {
2153 fprintf(stderr,
"Couldn't run qmlimportscanner.\n");
2159 while (fgets(
buffer,
sizeof(
buffer), qmlImportScannerCommand) != 0)
2163 if (jsonDocument.
isNull()) {
2164 fprintf(stderr,
"Invalid json output from qmlimportscanner.\n");
2169 for (
int i=0;
i<jsonArray.
count(); ++
i) {
2171 if (!
value.isObject()) {
2172 fprintf(stderr,
"Invalid format of qmlimportscanner output.\n");
2177 QString path =
object.value(
"path"_L1).toString();
2178 if (
path.isEmpty()) {
2179 fprintf(stderr,
"Warning: QML import could not be resolved in any of the import paths: %s\n",
2183 fprintf(stdout,
" -- Adding '%s' as QML dependency\n",
qPrintable(
path));
2190 fprintf(stdout,
" -- Skipping because path does not exist.\n");
2203 fprintf(stdout,
" -- Skipping because path is in QML root path.\n");
2207 QString importPathOfThisImport;
2208 for (
const QString &importPath : std::as_const(importPaths)) {
2211 importPathOfThisImport = importPath;
2216 if (importPathOfThisImport.
isEmpty()) {
2221 importPathOfThisImport =
QDir(importPathOfThisImport).
absolutePath() + u
'/';
2223 auto collectQmlDependency = [&usedDependencies, &qmlImportsDependencies,
2224 &importPathOfThisImport](
const QString &filePath) {
2225 if (!usedDependencies->
contains(filePath)) {
2226 usedDependencies->
insert(filePath);
2228 "qml/"_L1 + filePath.mid(importPathOfThisImport.
size()),
2233 QString plugin =
object.value(
"plugin"_L1).toString();
2234 bool pluginIsOptional =
object.value(
"pluginIsOptional"_L1).toBool();
2236 path + u
'/' +
"lib"_L1 + plugin + u
'_'
2242 &remainingDependencies)) {
2243 collectQmlDependency(pluginFilePath);
2244 }
else if (!pluginIsOptional) {
2246 fprintf(stdout,
" -- Skipping because the required plugin is missing.\n");
2251 if (qmldirFileInfo.
exists()) {
2255 QString prefer =
object.value(
"prefer"_L1).toString();
2261 object.
value(
"components"_L1).toArray().toVariantList();
2262 qmlFiles.
append(
object.
value(
"scripts"_L1).toArray().toVariantList());
2263 bool qmlFilesMissing =
false;
2264 for (
const auto &qmlFileEntry : qmlFiles) {
2265 QFileInfo fileInfo(qmlFileEntry.toString());
2266 if (!fileInfo.
exists()) {
2267 qmlFilesMissing =
true;
2273 if (qmlFilesMissing) {
2276 " -- Skipping because the required qml files are missing.\n");
2291 for (
auto rootPath : options->
rootPaths) {
2301 fprintf(stdout,
"Running command '%s'\n",
qPrintable(command));
2305 fprintf(stderr,
"Cannot run command '%s'\n",
qPrintable(command));
2311 fprintf(stdout,
"%s",
buffer);
2322 if (!
QDir{
"%1/android_rcc_bundle"_L1.arg(assetsDir)}.
exists()) {
2323 fprintf(stdout,
"Skipping createRCC\n");
2328 fprintf(stdout,
"Create rcc bundle.\n");
2339 fprintf(stderr,
"rcc not found: %s\n",
qPrintable(rcc));
2344 fprintf(stderr,
"Cannot set current dir to: %s\n",
qPrintable(
"%1/android_rcc_bundle"_L1.arg(assetsDir)));
2348 bool res =
runCommand(options,
"%1 --project -o %2"_L1.arg(rcc,
shellQuote(
"%1/android_rcc_bundle.qrc"_L1.arg(assetsDir))));
2354 noZstd =
"--no-zstd"_L1;
2356 QFile::rename(
"%1/android_rcc_bundle.qrc"_L1.arg(assetsDir),
"%1/android_rcc_bundle/android_rcc_bundle.qrc"_L1.arg(assetsDir));
2358 res =
runCommand(options,
"%1 %2 %3 --binary -o %4 android_rcc_bundle.qrc"_L1.arg(rcc,
shellQuote(
"--root=/android_rcc_bundle/"_L1),
2360 shellQuote(
"%1/android_rcc_bundle.rcc"_L1.arg(assetsDir))));
2362 fprintf(stderr,
"Cannot set current dir to: %s\n",
qPrintable(currentDir));
2366 QFile::remove(
"%1/android_rcc_bundle.qrc"_L1.arg(assetsDir));
2375 fprintf(stdout,
"Detecting dependencies of application.\n");
2380 fprintf(stdout,
"\tDependencies explicitly overridden in .pro file. No detection needed.\n");
2391 while (!remainingDependencies.
isEmpty()) {
2402 fprintf(stdout,
"Skipping %s due to unmet dependencies: %s\n",
2412 fprintf(stdout,
"Skipping %s due to unmet dependencies: %s\n",
2429 if (!options->
build)
2433 fprintf(stdout,
"Checking if application binary is in package.\n");
2440 applicationFileName);
2442#if defined(Q_OS_WIN32)
2443 const auto makeTool =
"mingw32-make"_L1;
2445 const auto makeTool =
"make"_L1;
2447 fprintf(stderr,
"Application binary is not in output directory: %s. Please run '%s install INSTALL_ROOT=%s' first.\n",
2460 fprintf(stderr,
"Cannot find adb tool: %s\n",
qPrintable(adb));
2473 if (adbCommand == 0) {
2474 fprintf(stderr,
"Cannot start adb: %s\n",
qPrintable(adb));
2483 if (!
file.endsWith(
".so"_L1))
2491 for (
const QString &lib : libs) {
2494 unmetDependencies->append(lib);
2509 fprintf(stdout,
"Copying dependencies from Qt into the package build folder,"
2510 "skipping native libraries.\n");
2515 if (!options->
build)
2519 QString libsDirectory =
"libs/"_L1;
2522 auto assetsDestinationDirectory =
"assets/android_rcc_bundle/"_L1;
2524 QString sourceFileName = qtDependency.absolutePath;
2526 bool isSharedLibrary = qtDependency.relativePath.
endsWith(
".so"_L1);
2527 if (isSharedLibrary) {
2528 QString garbledFileName = qtDependency.relativePath.
mid(
2529 qtDependency.relativePath.lastIndexOf(u
'/') + 1);
2530 destinationFileName = libsDirectory + options->
currentArchitecture + u
'/' + garbledFileName;
2532 destinationFileName = libsDirectory + qtDependency.relativePath.
mid(
sizeof(
"jar/") - 1);
2534 destinationFileName = assetsDestinationDirectory + qtDependency.relativePath;
2538 fprintf(stderr,
"Source Qt file does not exist: %s.\n",
qPrintable(sourceFileName));
2543 if (!
goodToCopy(options, sourceFileName, &unmetDependencies)) {
2544 if (unmetDependencies.isEmpty()) {
2546 fprintf(stdout,
" -- Skipping %s, architecture mismatch.\n",
2550 fprintf(stdout,
" -- Skipping %s. It has unmet dependencies: %s.\n",
2579 if (equalSignIndex >= 0) {
2600#if defined(Q_OS_WIN32)
2649 QFile oldFile(oldPathStr);
2651 while (!oldFile.
atEnd()) {
2654 if (prop.
size() > 1) {
2655 GradleProperties::iterator
it =
properties.find(prop.
at(0).trimmed());
2675#if defined(Q_OS_WIN32)
2676void checkAndWarnGradleLongPaths(
const QString &outputDirectory)
2681 while (
it.hasNext()) {
2683 longFileNames.append(
it.next());
2686 if (!longFileNames.isEmpty()) {
2688 "The maximum path length that can be processed by Gradle on Windows is %d characters.\n"
2689 "Consider moving your project to reduce its path length.\n"
2690 "The following files have too long paths:\n%s.\n",
2715 for (
const auto &
line : lines) {
2716 if (isComment(
line))
2719 flags.setsLegacyPackaging =
true;
2720 }
else if (
line.
contains(
"compileSdkVersion androidCompileSdkVersion.toInteger()")) {
2721 flags.usesIntegerCompileSdkVersion =
true;
2742 gradleProperties[
"android.bundle.enableUncompressedNativeLibs"] =
"false";
2744 gradleProperties[
"buildDir"] =
"build";
2745 gradleProperties[
"qtAndroidDir"] =
2747 "/src/android/java"_L1)
2752 gradleProperties[
"qt5AndroidDir"] =
2754 "/src/android/java"_L1)
2765 sdkPlatformVersion = tmp;
2767 fprintf(stderr,
"Warning: Gradle expects SDK platform version to be an integer, "
2768 "but the set version is not convertible to an integer.");
2772 if (sdkPlatformVersion.
isEmpty())
2775 gradleProperties[
"androidCompileSdkVersion"] = sdkPlatformVersion;
2776 gradleProperties[
"qtMinSdkVersion"] = options.
minSdkVersion;
2779 if (gradleProperties[
"androidBuildToolsVersion"].isEmpty())
2789 gradleProperties[
"qtTargetAbiList"] = abiList.
toLocal8Bit();
2798 fprintf(stderr,
"Cannot set permissions %s\n",
qPrintable(gradlePath));
2810 commandLine +=
" bundle"_L1;
2813 commandLine +=
" --info"_L1;
2816 if (gradleCommand == 0) {
2817 fprintf(stderr,
"Cannot run gradle command: %s\n.",
qPrintable(commandLine));
2822 while (fgets(
buffer,
sizeof(
buffer), gradleCommand) != 0) {
2823 fprintf(stdout,
"%s",
buffer);
2827 int errorCode = pclose(gradleCommand);
2828 if (errorCode != 0) {
2829 fprintf(stderr,
"Building the android package failed!\n");
2831 fprintf(stderr,
" -- For more information, run this command with --verbose.\n");
2833#if defined(Q_OS_WIN32)
2840 fprintf(stderr,
"Cannot change back to old path: %s\n",
qPrintable(oldPath));
2850 fprintf(stdout,
"Uninstalling old Android package %s if present.\n",
qPrintable(options.
packageName));
2854 if (adbCommand == 0)
2861 fprintf(stdout,
"%s",
buffer);
2864 int returnCode = pclose(adbCommand);
2865 if (returnCode != 0) {
2866 fprintf(stderr,
"Warning: Uninstall failed!\n");
2868 fprintf(stderr,
" -- Run with --verbose for more information.\n");
2890 path +=
"release-"_L1;
2894 path +=
"signed.apk"_L1;
2903 path +=
"-signed"_L1;
2920 fprintf(stdout,
"Installing Android package to device.\n");
2922 FILE *adbCommand =
runAdb(options,
" install -r "_L1
2925 if (adbCommand == 0)
2932 fprintf(stdout,
"%s",
buffer);
2935 int returnCode = pclose(adbCommand);
2936 if (returnCode != 0) {
2937 fprintf(stderr,
"Installing to device failed!\n");
2939 fprintf(stderr,
" -- Run with --verbose for more information.\n");
2959 fprintf(stdout,
"Copying STL library\n");
2965 fprintf(stderr,
"STL library does not exist at %s\n",
qPrintable(stdCppPath));
2985 fprintf(stderr,
"zipalign tool not found: %s\n",
qPrintable(zipAlignTool));
2990 return zipAlignTool;
2996 fprintf(stdout,
"Signing Android package.\n");
3007 jarSignerTool = jdkPath +
"/bin/"_L1 + jarSignerTool;
3010 fprintf(stderr,
"Cannot find jarsigner in JAVA_HOME or PATH. Please use --jdk option to pass in the correct path to JDK.\n");
3014 jarSignerTool =
"%1 -sigalg %2 -digestalg %3 -keystore %4"_L1
3039 jarSignerTool +=
" -internalsf"_L1;
3042 jarSignerTool +=
" -sectionsonly"_L1;
3045 jarSignerTool +=
" -protected"_L1;
3054 if (jarSignerCommand == 0) {
3055 fprintf(stderr,
"Couldn't run jarsigner.\n");
3061 while (fgets(
buffer,
sizeof(
buffer), jarSignerCommand) != 0)
3062 fprintf(stdout,
"%s",
buffer);
3065 int errorCode = pclose(jarSignerCommand);
3066 if (errorCode != 0) {
3067 fprintf(stderr,
"jarsigner command failed.\n");
3069 fprintf(stderr,
" -- Run with --verbose for more information.\n");
3092 auto zipalignRunner = [](
const QString &zipAlignCommandLine) {
3093 FILE *zipAlignCommand =
openProcess(zipAlignCommandLine);
3094 if (zipAlignCommand == 0) {
3095 fprintf(stderr,
"Couldn't run zipalign.\n");
3100 while (fgets(
buffer,
sizeof(
buffer), zipAlignCommand) != 0)
3101 fprintf(stdout,
"%s",
buffer);
3103 return pclose(zipAlignCommand) == 0;
3106 const QString verifyZipAlignCommandLine =
3112 if (zipalignRunner(verifyZipAlignCommandLine)) {
3114 fprintf(stdout,
"APK already aligned, copying it for signing.\n");
3120 fprintf(stderr,
"Could not copy unsigned APK.\n");
3125 fprintf(stdout,
"APK not aligned, aligning it for signing.\n");
3127 const QString zipAlignCommandLine =
3128 "%1%2 -f 4 %3 %4"_L1
3134 if (!zipalignRunner(zipAlignCommandLine)) {
3135 fprintf(stderr,
"zipalign command failed.\n");
3137 fprintf(stderr,
" -- Run with --verbose for more information.\n");
3142 QString apkSignCommand =
"%1 sign --ks %2"_L1
3155 apkSignCommand +=
" --verbose"_L1;
3159 auto apkSignerRunner = [](
const QString &command,
bool verbose) {
3161 if (apkSigner == 0) {
3162 fprintf(stderr,
"Couldn't run apksigner.\n");
3168 fprintf(stdout,
"%s",
buffer);
3170 int errorCode = pclose(apkSigner);
3171 if (errorCode != 0) {
3172 fprintf(stderr,
"apksigner command failed.\n");
3174 fprintf(stderr,
" -- Run with --verbose for more information.\n");
3181 if (!apkSignerRunner(apkSignCommand, options.
verbose))
3184 const QString apkVerifyCommand =
3185 "%1 verify --verbose %2"_L1
3220 fprintf(stdout,
"Writing dependency file.\n");
3235 depFile.
write(
": ");
3238 depFile.
write(
" \\\n ");
3242 depFile.
write(
"\n");
3263 fprintf(stdout,
"[TIMING] %lld ns: Read input file\n", options.
timer.
nsecsElapsed());
3266 "Generating Android Package\n"
3268 " Output directory: %s\n"
3269 " Application binary: %s\n"
3270 " Android build platform: %s\n"
3271 " Install to device: %s\n",
3281 bool androidTemplatetCopied =
false;
3287 it.value().qtInstallDirectory,
3288 it.value().qtDirectories);
3294 fprintf(stdout,
"[TIMING] %lld ns: Cleaned Android file\n", options.
timer.
nsecsElapsed());
3300 fprintf(stdout,
"[TIMING] %lld ns: Copied Android template\n", options.
timer.
nsecsElapsed());
3301 androidTemplatetCopied =
true;
3308 fprintf(stdout,
"[TIMING] %lld ns: Read dependencies\n", options.
timer.
nsecsElapsed());
3314 fprintf(stdout,
"[TIMING] %lld ns: Copied Qt files\n", options.
timer.
nsecsElapsed());
3320 fprintf(stdout,
"[TIMING] %lld ms: Copied extra libs\n", options.
timer.
nsecsElapsed());
3326 fprintf(stdout,
"[TIMING] %lld ns: Copied extra resources\n", options.
timer.
nsecsElapsed());
3333 fprintf(stdout,
"[TIMING] %lld ns: Copied GNU STL\n", options.
timer.
nsecsElapsed());
3337 QString appLibPath =
"%1/libs/%2/lib%3_%2.so"_L1.
3347 fprintf(stdout,
"[TIMING] %lld ns: Checked for application binary\n", options.
timer.
nsecsElapsed());
3350 fprintf(stdout,
"[TIMING] %lld ns: Bundled Qt libs\n", options.
timer.
nsecsElapsed());
3368 if (options.
build) {
3373 fprintf(stdout,
"[TIMING] %lld ns: Copied android sources\n", options.
timer.
nsecsElapsed());
3379 fprintf(stdout,
"[TIMING] %lld ns: Updated files\n", options.
timer.
nsecsElapsed());
3382 fprintf(stdout,
"[TIMING] %lld ns: Created project\n", options.
timer.
nsecsElapsed());
3388 fprintf(stdout,
"[TIMING] %lld ns: Built project\n", options.
timer.
nsecsElapsed());
3397 fprintf(stdout,
"[TIMING] %lld ns: Signed package\n", options.
timer.
nsecsElapsed());
3404 fprintf(stdout,
"[TIMING] %lld ns: Installed APK\n", options.
timer.
nsecsElapsed());
3409 fprintf(stdout,
"Android package built successfully in %.3f ms.\n", options.
timer.
elapsed() / 1000.);
3412 fprintf(stdout,
" -- It can now be run from the selected device/emulator.\n");
bool startsWith(QByteArrayView other) const noexcept
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
int toInt(bool *ok=nullptr, int base=10) const
Returns the byte array converted to an int using base base, which is ten by default.
QList< QByteArray > split(char sep) const
Splits the byte array into subarrays wherever sep occurs, and returns the list of those arrays.
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
static QByteArray fromRawData(const char *data, qsizetype size)
Constructs a QByteArray that uses the first size bytes of the data array.
static constexpr QChar fromLatin1(char c) noexcept
Converts the Latin-1 character c to its equivalent QChar.
static QStringList arguments()
The QDirIterator class provides an iterator for directory entrylists.
QStringList entryList(Filters filters=NoFilter, SortFlags sort=NoSort) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString dirName() const
Returns the name of the directory; this is not the same as the path, e.g.
static bool isRelativePath(const QString &path)
Returns true if path is relative; returns false if it is absolute.
static QString fromNativeSeparators(const QString &pathName)
static bool setCurrent(const QString &path)
Sets the application's current working directory to path.
QString path() const
Returns the path.
static QDir current()
Returns the application's current directory.
QString absolutePath() const
Returns the absolute path (a path that starts with "/" or with a drive specification),...
QFileInfoList entryInfoList(Filters filters=NoFilter, SortFlags sort=NoSort) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool exists() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool mkpath(const QString &dirPath) const
Creates the directory path dirPath.
QString filePath(const QString &fileName) const
Returns the path name of a file in the directory.
static QString cleanPath(const QString &path)
Returns path with directory separators normalized (that is, platform-native separators converted to "...
QString relativeFilePath(const QString &fileName) const
Returns the path to fileName relative to the directory.
QString absoluteFilePath(const QString &fileName) const
Returns the absolute path name of a file in the directory.
static QString currentPath()
Returns the absolute path of the application's current directory.
qint64 elapsed() const noexcept
Returns the number of milliseconds since this QElapsedTimer was last started.
void start() noexcept
Starts this timer.
qint64 nsecsElapsed() const noexcept
bool atEnd() const override
Returns true if the end of the file has been reached; otherwise returns false.
void close() override
Calls QFileDevice::flush() and closes the file.
\inmodule QtCore \reentrant
QDateTime lastModified() const
Returns the date and time when the file was last modified.
QString baseName() const
Returns the base name of the file without the path.
QString suffix() const
Returns the suffix (extension) of the file.
QString fileName() const
Returns the name of the file, excluding the path.
bool isExecutable() const
Returns true if the file is executable; otherwise returns false.
QString absoluteFilePath() const
Returns an absolute path including the file name.
bool isFile() const
Returns true if this object points to a file or to a symbolic link to a file.
bool isDir() const
Returns true if this object points to a directory or to a symbolic link to a directory.
QString absolutePath() const
Returns a file's path absolute path.
QString canonicalFilePath() const
Returns the canonical path including the file name, i.e.
QString filePath() const
Returns the file name, including the path (which may be absolute or relative).
bool exists() const
Returns true if the file exists; otherwise returns false.
bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
bool copy(const QString &newName)
Copies the file named fileName() to newName.
bool remove()
Removes the file specified by fileName().
QString fileName() const override
Returns the name set by setFileName() or to the QFile constructors.
bool rename(const QString &newName)
Renames the file currently specified by fileName() to newName.
bool exists() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
qsizetype size() const noexcept
Returns the number of items in the hash.
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
const_iterator constBegin() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
QList< Key > keys() const
Returns a list containing all the keys in the hash, in an arbitrary order.
iterator erase(const_iterator it)
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
bool isEmpty() const noexcept
Returns true if the hash contains no items; otherwise returns false.
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
qint64 readLine(char *data, qint64 maxlen)
This function reads a line of ASCII characters from the device, up to a maximum of maxSize - 1 bytes,...
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
QString errorString() const
Returns a human readable description of the last error that occurred.
\inmodule QtCore\reentrant
qsizetype count() const
Same as size().
QJsonValue at(qsizetype i) const
Returns a QJsonValue representing the value for index i.
\inmodule QtCore\reentrant
bool isNull() const
returns true if this document is null.
QJsonArray array() const
Returns the QJsonArray contained in the document.
QJsonObject object() const
Returns the QJsonObject contained in the document.
static QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error=nullptr)
Parses json as a UTF-8 encoded JSON document, and creates a QJsonDocument from it.
\inmodule QtCore\reentrant
const_iterator constBegin() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item in the object.
const_iterator constEnd() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
QJsonValue value(const QString &key) const
Returns a QJsonValue representing the value for the key key.
bool isEmpty() const
Returns true if the object is empty.
\inmodule QtCore\reentrant
bool isBool() const
Returns true if the value contains a boolean.
bool isString() const
Returns true if the value contains a string.
QJsonObject toObject() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
QJsonArray toArray() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool toBool(bool defaultValue=false) const
Converts the value to a bool and returns it.
bool isArray() const
Returns true if the value contains an array.
QString toString() const
Converts the value to a QString and returns it.
bool isObject() const
Returns true if the value contains an object.
bool isUndefined() const
Returns true if the value is undefined.
qsizetype size() const noexcept
bool isEmpty() const noexcept
const_reference at(qsizetype i) const noexcept
T value(qsizetype i) const
void append(parameter_type t)
\inmodule QtCore \reentrant
QRegularExpressionMatch match(const QString &subject, qsizetype offset=0, MatchType matchType=NormalMatch, MatchOptions matchOptions=NoMatchOption) const
Attempts to match the regular expression against the given subject string, starting at the position o...
const_iterator constEnd() const noexcept
iterator erase(const_iterator i)
bool contains(const T &value) const
iterator insert(const T &value)
QVariant value(QAnyStringView key, const QVariant &defaultValue) const
Returns the value for setting key.
bool endsWith(QStringView s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
QString toString() const
Returns a deep copy of this string view's data as a QString.
\macro QT_RESTRICTED_CAST_FROM_ASCII
QByteArray toLatin1() const &
int toInt(bool *ok=nullptr, int base=10) const
Returns the string converted to an int using base base, which is 10 by default and must be between 2 ...
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
QString & replace(qsizetype i, qsizetype len, QChar after)
void chop(qsizetype n)
Removes n characters from the end of the string.
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QStringList split(const QString &sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the string into substrings wherever sep occurs, and returns the list of those strings.
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void clear()
Clears the contents of the string and makes it null.
qsizetype size() const
Returns the number of characters in this string.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=u' ') const
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
int compare(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
QString & insert(qsizetype i, QChar c)
QByteArray toLocal8Bit() const &
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
QString & append(QChar c)
QString left(qsizetype n) const
Returns a substring that contains the n leftmost characters of the string.
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
QString trimmed() const &
QByteArray toUtf8() const &
static QString static QString asprintf(const char *format,...) Q_ATTRIBUTE_FORMAT_PRINTF(1
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
QString toString() const
Returns the variant as a QString if the variant has a userType() including, but not limited to:
static QByteArray escapeAndEncodeDependencyPath(const QString &path)
list append(new Employee("Blackpool", "Stephen"))
QSet< QString >::iterator it
QList< QVariant > arguments
static const struct @480 keywords[]
size_t qstrlen(const char *str)
std::pair< T1, T2 > QPair
static const QPainterPath::ElementType * subPath(const QPainterPath::ElementType *t, const QPainterPath::ElementType *end, const qreal *points, bool *closed)
static const QCssKnownValue properties[NumProperties - 1]
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char * destination
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLsizei const GLuint * paths
GLsizei const GLchar *const * path
constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
static QString absolutePath(const QString &path)
static QString keyName(const QString &rKey)
#define qPrintable(string)
#define QStringLiteral(str)
bool uninstallApk(const Options &options)
bool containsApplicationBinary(Options *options)
void cleanTopFolders(const Options &options, const QDir &srcDir, const QString &dstDir)
bool writeDependencyFile(const Options &options)
void cleanAndroidFiles(const Options &options)
bool runCommand(const Options &options, const QString &command)
bool alwaysOverwritableFile(const QString &fileName)
static QStringList dependenciesForDepfile
bool checkCanImportFromRootPaths(const Options *options, const QString &absolutePath, const QString &moduleUrl)
QList< QtDependency > findFilesRecursively(const Options &options, const QFileInfo &info, const QString &rootPath)
bool checkArchitecture(const Options &options, const QString &fileName)
static QString absoluteFilePath(const Options *options, const QString &relativeFileName)
bool readAndroidDependencyXml(Options *options, const QString &moduleName, QSet< QString > *usedDependencies, QSet< QString > *remainingDependencies)
bool createRcc(const Options &options)
bool updateFile(const QString &fileName, const QHash< QString, QString > &replacements)
QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
bool updateLibsXml(Options *options)
QStringList getLibraryProjectsInOutputFolder(const Options &options)
static QString batSuffixAppended(QString path)
bool copyPackage(const Options &options)
bool buildAndroidProject(const Options &options)
QString packagePath(const Options &options, PackageType pt)
bool signAAB(const Options &options)
bool quasiLexicographicalReverseLessThan(const QFileInfo &fi1, const QFileInfo &fi2)
@ SyntaxErrorOrHelpRequested
@ CannotCopyAndroidExtraLibs
@ CannotCreateAndroidProject
@ CannotCopyAndroidSources
@ CannotCopyAndroidExtraResources
@ CannotUpdateAndroidFiles
@ CannotFindApplicationBinary
@ CannotCopyAndroidTemplate
@ CannotBuildAndroidProject
QString architectureFromName(const QString &name)
bool readInputFile(Options *options)
static QString zipalignPath(const Options &options, bool *ok)
GradleFlags gradleBuildFlags(const QString &path)
bool copyAndroidSources(const Options &options)
bool copyAndroidExtraResources(Options *options)
QString cleanPackageName(QString packageName)
QString fileArchitecture(const Options &options, const QString &path)
static const bool mustReadOutputAnyway
bool isDeployment(const Options *options, Options::DeploymentMechanism deployment)
static QString execSuffixAppended(QString path)
static const QHash< QByteArray, QByteArray > elfArchitectures
QString packageNameFromAndroidManifest(const QString &androidManifestPath)
QStringList allFilesInside(const QDir ¤t, const QDir &rootDir)
bool scanImports(Options *options, QSet< QString > *usedDependencies)
static bool mergeGradleProperties(const QString &path, GradleProperties properties)
QString defaultLibexecDir()
bool readDependenciesFromElf(Options *options, const QString &fileName, QSet< QString > *usedDependencies, QSet< QString > *remainingDependencies)
bool copyAndroidExtraLibs(Options *options)
bool updateAndroidFiles(Options &options)
bool readInputFileDirectory(Options *options, QJsonObject &jsonObject, const QString keyName)
QString findInPath(const QString &fileName)
QString detectLatestAndroidPlatform(const QString &sdkPath)
bool copyStdCpp(Options *options)
FILE * runAdb(const Options &options, const QString &arguments)
static QString llvmReadobjPath(const Options &options)
bool copyAndroidTemplate(const Options &options, const QString &androidTemplate, const QString &outDirPrefix=QString())
bool copyGradleTemplate(const Options &options)
bool updateStringsXml(const Options &options)
bool copyQtFiles(Options *options)
bool copyFiles(const QDir &sourceDirectory, const QDir &destinationDirectory, const Options &options, bool forceOverwrite=false)
QMap< QByteArray, QByteArray > GradleProperties
bool updateAndroidManifest(Options &options)
bool parseCmakeBoolean(const QJsonValue &value)
void deleteMissingFiles(const Options &options, const QDir &srcDir, const QDir &dstDir)
bool readDependencies(Options *options)
bool installApk(const Options &options)
FILE * openProcess(const QString &command)
bool copyFileIfNewer(const QString &sourceFileName, const QString &destinationFileName, const Options &options, bool forceOverwrite=false)
bool goodToCopy(const Options *options, const QString &file, QStringList *unmetDependencies)
bool signPackage(const Options &options)
static GradleProperties readGradleProperties(const QString &path)
QString qEnvironmentVariable(const char *varName, const QString &defaultValue)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
static bool match(const uchar *found, uint foundLen, const char *target, uint targetLen)
QT_BEGIN_NAMESPACE typedef uchar * output
static QString shellQuote(const QString &arg)
QFileInfo info(fileName)
[8]
QSettings settings("MySoft", "Star Runner")
[0]
settings remove("monkey")
QUrl url("example.com")
[constructor-url-reference]
char * toString(const MyType &t)
[31]
bool usesIntegerCompileSdkVersion
bool copyDependenciesOnly
std::vector< QString > rootPaths
QString currentArchitecture
QByteArray targetSdkVersion
void setCurrentQtArchitecture(const QString &arch, const QString &directory, const QHash< QString, QString > &directories)
QString qtInstallDirectory
DeploymentMechanism deploymentMechanism
bool protectedAuthenticationPath
QStringList qmlImportPaths
bool qmlSkipImportScanning
QHash< QString, QStringList > archExtraPlugins
QString sdkBuildToolsVersion
QString qtLibExecsDirectory
QHash< QString, QStringList > archExtraLibs
QString applicationArguments
QString qmlImportScannerBinaryPath
QHash< QString, QString > qtDirectories
QHash< QString, QtInstallDirectoryWithTriple > architectures
QHash< QString, QList< BundledFile > > bundledFiles
QPair< QString, QString > BundledFile
QHash< QString, QList< QtDependency > > qtDependencies
QString qtPluginsDirectory
std::vector< QString > extraPrefixDirs
QHash< QString, QStringList > localLibs
QString applicationBinary
std::vector< QString > extraLibraryDirs
bool isZstdCompressionEnabled
QString androidSourceDirectory
\inmodule QtCore \reentrant
bool operator==(const QtDependency &other) const
QtDependency(const QString &rpath, const QString &apath)
QString qtInstallDirectory
QHash< QString, QString > qtDirectories
QtInstallDirectoryWithTriple(const QString &dir=QString(), const QString &t=QString(), const QHash< QString, QString > &dirs=QHash< QString, QString >())