Add option to not include native libraries in APK
Sometimes it is not desirable to include the libraries in the APK, e.g. system and vendor apps could prefer having one set of libraries installed on the device. If unbundled deployment is specified, native libraries will not be included in the APK. With unbundled deployment, optional arguments can be passed to set the path to load the libraries on the device. [ChangeLog][Android][Deployment Changes] Adds option for Unbundled deployment, where native libraries are not packaged in the APK. Task-number: QAA-771 Change-Id: Ica51ef83a24dad58c7586bf610a58abe21fc1100 Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
This commit is contained in:
parent
ff153d9874
commit
9af1f3557a
@ -163,6 +163,24 @@ define_property(TARGET
|
|||||||
"This variable points to the path of the deployment settings JSON file, which holds properties required by androiddeployqt to package the Android app."
|
"This variable points to the path of the deployment settings JSON file, which holds properties required by androiddeployqt to package the Android app."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
define_property(TARGET
|
||||||
|
PROPERTY
|
||||||
|
QT_ANDROID_SYSTEM_LIBS_PREFIX
|
||||||
|
BRIEF_DOCS
|
||||||
|
"This variable is used to specify a path to Qt libraries on the target device in Android."
|
||||||
|
FULL_DOCS
|
||||||
|
"This variable can be used to provide a custom system library path to use for library loading lookup on Android. This is necessary when using Qt libraries installed outside an app's default native (JNI) library directory."
|
||||||
|
)
|
||||||
|
|
||||||
|
define_property(TARGET
|
||||||
|
PROPERTY
|
||||||
|
QT_ANDROID_NO_DEPLOY_QT_LIBS
|
||||||
|
BRIEF_DOCS
|
||||||
|
"This variable is used to control whether Qt libraries should be deployed inside the APK on Android."
|
||||||
|
FULL_DOCS
|
||||||
|
"This variable can be used to exclude Qt shared libraries from being packaged inside the APK when deploying on Android. Not supported when deploying as Android Application Bundle."
|
||||||
|
)
|
||||||
|
|
||||||
# Returns test execution arguments for Android targets
|
# Returns test execution arguments for Android targets
|
||||||
function(qt_internal_android_test_arguments target out_test_runner out_test_arguments)
|
function(qt_internal_android_test_arguments target out_test_runner out_test_arguments)
|
||||||
set(${out_test_runner} "${QT_HOST_PATH}/${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_BINDIR}/androidtestrunner" PARENT_SCOPE)
|
set(${out_test_runner} "${QT_HOST_PATH}/${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_BINDIR}/androidtestrunner" PARENT_SCOPE)
|
||||||
|
@ -76,7 +76,6 @@ public abstract class QtLoader {
|
|||||||
|
|
||||||
// These parameters matter in case of deploying application as system (embedded into firmware)
|
// These parameters matter in case of deploying application as system (embedded into firmware)
|
||||||
public static final String SYSTEM_LIB_PATH = "/system/lib/";
|
public static final String SYSTEM_LIB_PATH = "/system/lib/";
|
||||||
public String[] SYSTEM_APP_PATHS = {"/system/priv-app/", "/system/app/"};
|
|
||||||
|
|
||||||
public String APPLICATION_PARAMETERS = null; // use this variable to pass any parameters to your application,
|
public String APPLICATION_PARAMETERS = null; // use this variable to pass any parameters to your application,
|
||||||
// the parameters must not contain any white spaces
|
// the parameters must not contain any white spaces
|
||||||
@ -255,33 +254,40 @@ public abstract class QtLoader {
|
|||||||
|
|
||||||
if (useLocalLibs == 1) {
|
if (useLocalLibs == 1) {
|
||||||
ArrayList<String> libraryList = new ArrayList<>();
|
ArrayList<String> libraryList = new ArrayList<>();
|
||||||
|
|
||||||
boolean apkDeployFromSystem = false;
|
|
||||||
String apkPath = m_context.getApplicationInfo().publicSourceDir;
|
|
||||||
File apkFile = new File(apkPath);
|
|
||||||
if (apkFile.exists()) {
|
|
||||||
for (String systemAppPath : SYSTEM_APP_PATHS) {
|
|
||||||
apkDeployFromSystem = apkFile.getAbsolutePath().startsWith(systemAppPath);
|
|
||||||
if (apkDeployFromSystem)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String libsDir = null;
|
String libsDir = null;
|
||||||
String bundledLibsDir = null;
|
String bundledLibsDir = null;
|
||||||
if (apkDeployFromSystem) {
|
|
||||||
String systemLibsPrefix = SYSTEM_LIB_PATH;
|
id = resources.getIdentifier("bundle_local_qt_libs", "string", packageName);
|
||||||
if (m_contextInfo.metaData.containsKey("android.app.system_libs_prefix")) {
|
final int bundleLocalLibs = Integer.parseInt(resources.getString(id));
|
||||||
systemLibsPrefix = m_contextInfo.metaData.getString("android.app.system_libs_prefix");
|
if (bundleLocalLibs == 0) {
|
||||||
|
String systemLibsPrefix;
|
||||||
|
final String systemLibsKey = "android.app.system_libs_prefix";
|
||||||
|
// First check if user has provided system libs prefix in AndroidManifest
|
||||||
|
if (m_contextInfo.applicationInfo.metaData != null &&
|
||||||
|
m_contextInfo.applicationInfo.metaData.containsKey(systemLibsKey)) {
|
||||||
|
systemLibsPrefix = m_contextInfo.applicationInfo.metaData.getString(systemLibsKey);
|
||||||
} else {
|
} else {
|
||||||
Log.e(QtApplication.QtTAG, "It looks like app deployed as system app. "
|
// If not, check if it's provided by androiddeployqt in libs.xml
|
||||||
+ "It may be necessary to specify path to system lib directory using "
|
id = resources.getIdentifier("system_libs_prefix","string",
|
||||||
+ "android.app.system_libs_prefix metadata variable in your AndroidManifest.xml");
|
packageName);
|
||||||
|
systemLibsPrefix = resources.getString(id);
|
||||||
|
}
|
||||||
|
if (systemLibsPrefix.isEmpty()) {
|
||||||
|
systemLibsPrefix = SYSTEM_LIB_PATH;
|
||||||
|
Log.e(QtApplication.QtTAG, "It looks like app deployed using Unbundled "
|
||||||
|
+ "deployment. It may be necessary to specify path to directory "
|
||||||
|
+ "where Qt libraries are installed using either "
|
||||||
|
+ "android.app.system_libs_prefix metadata variable in your "
|
||||||
|
+ "AndroidManifest.xml or QT_ANDROID_SYSTEM_LIBS_PATH in your "
|
||||||
|
+ "CMakeLists.txt");
|
||||||
Log.e(QtApplication.QtTAG, "Using " + SYSTEM_LIB_PATH + " as default path");
|
Log.e(QtApplication.QtTAG, "Using " + SYSTEM_LIB_PATH + " as default path");
|
||||||
}
|
}
|
||||||
|
|
||||||
File systemLibraryDir = new File(systemLibsPrefix);
|
File systemLibraryDir = new File(systemLibsPrefix);
|
||||||
if (systemLibraryDir.exists() && systemLibraryDir.isDirectory() && systemLibraryDir.list().length > 0) {
|
if (systemLibraryDir.exists() && systemLibraryDir.isDirectory()
|
||||||
|
&& systemLibraryDir.list().length > 0) {
|
||||||
libsDir = systemLibsPrefix;
|
libsDir = systemLibsPrefix;
|
||||||
|
bundledLibsDir = systemLibsPrefix;
|
||||||
} else {
|
} else {
|
||||||
Log.e(QtApplication.QtTAG,
|
Log.e(QtApplication.QtTAG,
|
||||||
"System library directory " + systemLibsPrefix
|
"System library directory " + systemLibsPrefix
|
||||||
@ -300,7 +306,7 @@ public abstract class QtLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (apkDeployFromSystem && libsDir == null)
|
if (libsDir == null)
|
||||||
throw new Exception("");
|
throw new Exception("");
|
||||||
|
|
||||||
|
|
||||||
@ -310,20 +316,17 @@ public abstract class QtLoader {
|
|||||||
libraryList.add(libPrefix + lib + ".so");
|
libraryList.add(libPrefix + lib + ".so");
|
||||||
}
|
}
|
||||||
|
|
||||||
id = resources.getIdentifier("bundle_local_qt_libs", "string", packageName);
|
id = resources.getIdentifier("load_local_libs", "array", packageName);
|
||||||
final int bundleLocalLibs = Integer.parseInt(resources.getString(id));
|
ArrayList<String> localLibs = prefferedAbiLibs(resources.getStringArray(id));
|
||||||
|
for (String libs : localLibs) {
|
||||||
if (bundleLocalLibs == 1) {
|
for (String lib : libs.split(":")) {
|
||||||
id = resources.getIdentifier("load_local_libs", "array", packageName);
|
if (!lib.isEmpty())
|
||||||
ArrayList<String> localLibs = prefferedAbiLibs(resources.getStringArray(id));
|
libraryList.add(libsDir + lib);
|
||||||
for (String libs : localLibs) {
|
|
||||||
for (String lib : libs.split(":")) {
|
|
||||||
if (!lib.isEmpty())
|
|
||||||
libraryList.add(libsDir + lib);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (bundledLibsDir != null)
|
}
|
||||||
ENVIRONMENT_VARIABLES += "\tQT_BUNDLED_LIBS_PATH=" + bundledLibsDir;
|
if (bundledLibsDir != null) {
|
||||||
|
ENVIRONMENT_VARIABLES += "\tQT_PLUGIN_PATH=" + bundledLibsDir;
|
||||||
|
ENVIRONMENT_VARIABLES += "\tQML_PLUGIN_PATH=" + bundledLibsDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bundle loaderParams = new Bundle();
|
Bundle loaderParams = new Bundle();
|
||||||
|
@ -145,7 +145,7 @@ The following is a list of such meta-data defined by Qt:
|
|||||||
|
|
||||||
\table
|
\table
|
||||||
\header
|
\header
|
||||||
\li meta-data name
|
\li Meta-data Name
|
||||||
\li Description
|
\li Description
|
||||||
\row
|
\row
|
||||||
\target android.app.lib_name
|
\target android.app.lib_name
|
||||||
@ -199,11 +199,23 @@ The following is a list of such meta-data defined by Qt:
|
|||||||
by the app.
|
by the app.
|
||||||
For more information, see
|
For more information, see
|
||||||
\l {QNativeInterface::}{QAndroidApplication::hideSplashScreen()}.
|
\l {QNativeInterface::}{QAndroidApplication::hideSplashScreen()}.
|
||||||
|
\endtable
|
||||||
|
|
||||||
|
\section2 Application Specific Meta-data
|
||||||
|
|
||||||
|
Some meta-data attributes are application-wide, and should be placed under
|
||||||
|
the \c <application> section:
|
||||||
|
|
||||||
|
\table
|
||||||
|
\header
|
||||||
|
\li Meta-data Name
|
||||||
|
\li Description
|
||||||
\row
|
\row
|
||||||
\target android.app.system_libs_prefix
|
\target android.app.system_libs_prefix
|
||||||
\li android.app.system_libs_prefix
|
\li android.app.system_libs_prefix
|
||||||
\li Specifies a custom system library path to use for library loading lookup.
|
\li Specifies a custom system library path to use for library loading lookup.
|
||||||
This is necessary when running as a system app.
|
This is necessary when using Qt libraries installed outside an app's
|
||||||
|
default native (JNI) library directory.
|
||||||
The default value is \c {/system/lib/}.
|
The default value is \c {/system/lib/}.
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
@ -216,7 +228,6 @@ The main ones are:
|
|||||||
\li \l {android.app.lib_name}
|
\li \l {android.app.lib_name}
|
||||||
\li \l {android.app.background_running}
|
\li \l {android.app.background_running}
|
||||||
\li \l {android.app.arguments}
|
\li \l {android.app.arguments}
|
||||||
\li \l {android.app.system_libs_prefix}
|
|
||||||
\endlist
|
\endlist
|
||||||
|
|
||||||
\section2 Qt Permissions and Features
|
\section2 Qt Permissions and Features
|
||||||
|
@ -17,4 +17,5 @@
|
|||||||
<string name="static_init_classes"><!-- %%INSERT_INIT_CLASSES%% --></string>
|
<string name="static_init_classes"><!-- %%INSERT_INIT_CLASSES%% --></string>
|
||||||
<string name="use_local_qt_libs"><!-- %%USE_LOCAL_QT_LIBS%% --></string>
|
<string name="use_local_qt_libs"><!-- %%USE_LOCAL_QT_LIBS%% --></string>
|
||||||
<string name="bundle_local_qt_libs"><!-- %%BUNDLE_LOCAL_QT_LIBS%% --></string>
|
<string name="bundle_local_qt_libs"><!-- %%BUNDLE_LOCAL_QT_LIBS%% --></string>
|
||||||
|
<string name="system_libs_prefix"><!-- %%SYSTEM_LIBS_PREFIX%% --></string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -214,6 +214,10 @@ function(qt6_android_generate_deployment_settings target)
|
|||||||
_qt_internal_add_android_deployment_multi_value_property(file_contents "android-extra-libs"
|
_qt_internal_add_android_deployment_multi_value_property(file_contents "android-extra-libs"
|
||||||
${target} "_qt_android_native_extra_libs" )
|
${target} "_qt_android_native_extra_libs" )
|
||||||
|
|
||||||
|
# Alternative path to Qt libraries on target device
|
||||||
|
_qt_internal_add_android_deployment_property(file_contents "android-system-libs-prefix"
|
||||||
|
${target} "QT_ANDROID_SYSTEM_LIBS_PREFIX")
|
||||||
|
|
||||||
# package source dir
|
# package source dir
|
||||||
_qt_internal_add_android_deployment_property(file_contents "android-package-source-directory"
|
_qt_internal_add_android_deployment_property(file_contents "android-package-source-directory"
|
||||||
${target} "_qt_android_native_package_source_dir")
|
${target} "_qt_android_native_package_source_dir")
|
||||||
@ -234,6 +238,10 @@ function(qt6_android_generate_deployment_settings target)
|
|||||||
_qt_internal_add_android_deployment_property(file_contents "android-target-sdk-version"
|
_qt_internal_add_android_deployment_property(file_contents "android-target-sdk-version"
|
||||||
${target} "QT_ANDROID_TARGET_SDK_VERSION")
|
${target} "QT_ANDROID_TARGET_SDK_VERSION")
|
||||||
|
|
||||||
|
# should Qt shared libs be excluded from deployment
|
||||||
|
_qt_internal_add_android_deployment_property(file_contents "android-no-deploy-qt-libs"
|
||||||
|
${target} "QT_ANDROID_NO_DEPLOY_QT_LIBS")
|
||||||
|
|
||||||
# App binary
|
# App binary
|
||||||
string(APPEND file_contents
|
string(APPEND file_contents
|
||||||
" \"application-binary\": \"${target_output_name}\",\n")
|
" \"application-binary\": \"${target_output_name}\",\n")
|
||||||
|
@ -296,6 +296,45 @@ Projects should not try to set this property themselves, as it will be ignored
|
|||||||
and overwritten by that command.
|
and overwritten by that command.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\page cmake-target-property-QT_ANDROID_SYSTEM_LIBS_PREFIX.html
|
||||||
|
\ingroup cmake-properties-qtcore
|
||||||
|
\ingroup cmake-target-properties-qtcore
|
||||||
|
|
||||||
|
\title QT_ANDROID_SYSTEM_LIBS_PREFIX
|
||||||
|
\target cmake-target-property-QT_ANDROID_SYSTEM_LIBS_PREFIX
|
||||||
|
|
||||||
|
\summary {Specifies the location of Qt libraries on the target device.}
|
||||||
|
|
||||||
|
\preliminarycmakeproperty
|
||||||
|
\cmakepropertyandroidonly
|
||||||
|
|
||||||
|
This property can be set to provide a path to Qt libraries on the target device,
|
||||||
|
when those libraries are installed outside app's native (JNI) library directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\page cmake-target-property-QT_ANDROID_NO_DEPLOY_QT_LIBS.html
|
||||||
|
\ingroup cmake-properties-qtcore
|
||||||
|
\ingroup cmake-target-properties-qtcore
|
||||||
|
|
||||||
|
\title QT_ANDROID_NO_DEPLOY_QT_LIBS
|
||||||
|
\target cmake-target-property-QT_ANDROID_NO_DEPLOY_QT_LIBS
|
||||||
|
|
||||||
|
\summary {Whether Qt shared libraries are packaged in the APK on Android.}
|
||||||
|
|
||||||
|
\preliminarycmakeproperty
|
||||||
|
\cmakepropertyandroidonly
|
||||||
|
|
||||||
|
This property can be set to not package Qt shared libraries inside the APK when
|
||||||
|
deploying the target. Use
|
||||||
|
\l{cmake-target-property-QT_ANDROID_SYSTEM_LIBS_PREFIX}{QT_ANDROID_SYSTEM_LIBS_PREFIX}
|
||||||
|
to provide a path to where those libraries will be located on the target device
|
||||||
|
instead.
|
||||||
|
|
||||||
|
\note Only supported when deploying as an APK.
|
||||||
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\page cmake-target-property-qt_no_entrypoint.html
|
\page cmake-target-property-qt_no_entrypoint.html
|
||||||
\ingroup cmake-properties-qtcore
|
\ingroup cmake-properties-qtcore
|
||||||
|
@ -2733,9 +2733,6 @@ QStringList QCoreApplication::libraryPathsLocked()
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
setPathsFromEnv(qEnvironmentVariable("QT_PLUGIN_PATH"));
|
setPathsFromEnv(qEnvironmentVariable("QT_PLUGIN_PATH"));
|
||||||
#ifdef Q_OS_ANDROID
|
|
||||||
setPathsFromEnv(qEnvironmentVariable("QT_BUNDLED_LIBS_PATH"));
|
|
||||||
#endif
|
|
||||||
#ifdef Q_OS_DARWIN
|
#ifdef Q_OS_DARWIN
|
||||||
// Check the main bundle's PlugIns directory as this is a standard location for Apple OSes.
|
// Check the main bundle's PlugIns directory as this is a standard location for Apple OSes.
|
||||||
// Note that the QLibraryInfo::PluginsPath below will coincidentally be the same as this value
|
// Note that the QLibraryInfo::PluginsPath below will coincidentally be the same as this value
|
||||||
|
@ -72,6 +72,32 @@
|
|||||||
\li \c{--deployment <mechanism>}
|
\li \c{--deployment <mechanism>}
|
||||||
\li Specify this to pick a different deployment mechanism than the
|
\li Specify this to pick a different deployment mechanism than the
|
||||||
default.
|
default.
|
||||||
|
\list
|
||||||
|
\li \c Bundled: includes all the app's dependencies inside
|
||||||
|
the APK.
|
||||||
|
\li \c Unbundled: excludes native libraries from the APK.
|
||||||
|
The libraries are expected to be present on the target
|
||||||
|
device. The location can be provided either by setting
|
||||||
|
the property
|
||||||
|
\l{cmake-target-property-QT_ANDROID_SYSTEM_LIBS_PREFIX}{QT_ANDROID_SYSTEM_LIBS_PREFIX}
|
||||||
|
in your CMake project file, or by defining the path as
|
||||||
|
meta-data in
|
||||||
|
\l {Qt Android Manifest File Configuration}{AndroidManifest.xml}:
|
||||||
|
\badcode
|
||||||
|
<application>
|
||||||
|
<meta-data
|
||||||
|
android:name="system_libs_prefix"
|
||||||
|
android:value="path/to/libraries/"/>
|
||||||
|
</application>
|
||||||
|
\endcode
|
||||||
|
If no path is provided, \c /system/lib/ is used as the
|
||||||
|
default path.
|
||||||
|
\note \c Unbundled deployment does not support
|
||||||
|
incremental builds.
|
||||||
|
\note \c Unbundled deployment not supported when
|
||||||
|
deploying as AAB.
|
||||||
|
\endlist
|
||||||
|
Default is \c Bundled deployment.
|
||||||
\row
|
\row
|
||||||
\li \c{--install}
|
\li \c{--install}
|
||||||
\li Specify this to install the finished package on the target device
|
\li Specify this to install the finished package on the target device
|
||||||
|
@ -101,7 +101,8 @@ struct Options
|
|||||||
|
|
||||||
enum DeploymentMechanism
|
enum DeploymentMechanism
|
||||||
{
|
{
|
||||||
Bundled
|
Bundled,
|
||||||
|
Unbundled
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TriState {
|
enum TriState {
|
||||||
@ -167,6 +168,7 @@ struct Options
|
|||||||
|
|
||||||
// Package information
|
// Package information
|
||||||
DeploymentMechanism deploymentMechanism;
|
DeploymentMechanism deploymentMechanism;
|
||||||
|
QString systemLibsPath;
|
||||||
QString packageName;
|
QString packageName;
|
||||||
QStringList extraLibs;
|
QStringList extraLibs;
|
||||||
QHash<QString, QStringList> archExtraLibs;
|
QHash<QString, QStringList> archExtraLibs;
|
||||||
@ -337,7 +339,6 @@ void deleteMissingFiles(const Options &options, const QDir &srcDir, const QDir &
|
|||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Options parseOptions()
|
Options parseOptions()
|
||||||
{
|
{
|
||||||
Options options;
|
Options options;
|
||||||
@ -383,6 +384,9 @@ Options parseOptions()
|
|||||||
QString deploymentMechanism = arguments.at(++i);
|
QString deploymentMechanism = arguments.at(++i);
|
||||||
if (deploymentMechanism.compare("bundled"_L1, Qt::CaseInsensitive) == 0) {
|
if (deploymentMechanism.compare("bundled"_L1, Qt::CaseInsensitive) == 0) {
|
||||||
options.deploymentMechanism = Options::Bundled;
|
options.deploymentMechanism = Options::Bundled;
|
||||||
|
} else if (deploymentMechanism.compare("unbundled"_L1,
|
||||||
|
Qt::CaseInsensitive) == 0) {
|
||||||
|
options.deploymentMechanism = Options::Unbundled;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Unrecognized deployment mechanism: %s\n", qPrintable(deploymentMechanism));
|
fprintf(stderr, "Unrecognized deployment mechanism: %s\n", qPrintable(deploymentMechanism));
|
||||||
options.helpRequested = true;
|
options.helpRequested = true;
|
||||||
@ -540,7 +544,9 @@ void printHelp()
|
|||||||
" directory will be used if nothing else is specified.\n"
|
" directory will be used if nothing else is specified.\n"
|
||||||
"\n"
|
"\n"
|
||||||
" --deployment <mechanism>: Supported deployment mechanisms:\n"
|
" --deployment <mechanism>: Supported deployment mechanisms:\n"
|
||||||
" bundled (default): Include Qt files in stand-alone package.\n"
|
" bundled (default): Includes Qt files in stand-alone package.\n"
|
||||||
|
" unbundled: Assumes native libraries are present on the device\n"
|
||||||
|
" and does not include them in the APK.\n"
|
||||||
"\n"
|
"\n"
|
||||||
" --aab: Build an Android App Bundle.\n"
|
" --aab: Build an Android App Bundle.\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -796,6 +802,16 @@ QString packageNameFromAndroidManifest(const QString &androidManifestPath)
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool parseCmakeBoolean(const QJsonValue &value)
|
||||||
|
{
|
||||||
|
const QString stringValue = value.toString();
|
||||||
|
return (stringValue.compare(QString::fromUtf8("true"), Qt::CaseInsensitive)
|
||||||
|
|| stringValue.compare(QString::fromUtf8("on"), Qt::CaseInsensitive)
|
||||||
|
|| stringValue.compare(QString::fromUtf8("yes"), Qt::CaseInsensitive)
|
||||||
|
|| stringValue.compare(QString::fromUtf8("y"), Qt::CaseInsensitive)
|
||||||
|
|| stringValue.toInt() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
bool readInputFile(Options *options)
|
bool readInputFile(Options *options)
|
||||||
{
|
{
|
||||||
QFile file(options->inputFileName);
|
QFile file(options->inputFileName);
|
||||||
@ -1022,6 +1038,22 @@ bool readInputFile(Options *options)
|
|||||||
options->extraPlugins = extraPlugins.toString().split(u',');
|
options->extraPlugins = extraPlugins.toString().split(u',');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const QJsonValue systemLibsPath =
|
||||||
|
jsonObject.value("android-system-libs-prefix"_L1);
|
||||||
|
if (!systemLibsPath.isUndefined())
|
||||||
|
options->systemLibsPath = systemLibsPath.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const QJsonValue noDeploy = jsonObject.value("android-no-deploy-qt-libs"_L1);
|
||||||
|
if (!noDeploy.isUndefined()) {
|
||||||
|
bool useUnbundled = parseCmakeBoolean(noDeploy);
|
||||||
|
options->deploymentMechanism = useUnbundled ? Options::Unbundled :
|
||||||
|
Options::Bundled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const QJsonValue stdcppPath = jsonObject.value("stdcpp-path"_L1);
|
const QJsonValue stdcppPath = jsonObject.value("stdcpp-path"_L1);
|
||||||
if (stdcppPath.isUndefined()) {
|
if (stdcppPath.isUndefined()) {
|
||||||
@ -1137,6 +1169,11 @@ bool readInputFile(Options *options)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isDeployment(const Options *options, Options::DeploymentMechanism deployment)
|
||||||
|
{
|
||||||
|
return options->deploymentMechanism == deployment;
|
||||||
|
}
|
||||||
|
|
||||||
bool copyFiles(const QDir &sourceDirectory, const QDir &destinationDirectory, const Options &options, bool forceOverwrite = false)
|
bool copyFiles(const QDir &sourceDirectory, const QDir &destinationDirectory, const Options &options, bool forceOverwrite = false)
|
||||||
{
|
{
|
||||||
const QFileInfoList entries = sourceDirectory.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
|
const QFileInfoList entries = sourceDirectory.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
|
||||||
@ -1249,8 +1286,16 @@ bool copyAndroidExtraLibs(Options *options)
|
|||||||
if (options->extraLibs.isEmpty())
|
if (options->extraLibs.isEmpty())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (options->verbose)
|
if (options->verbose) {
|
||||||
fprintf(stdout, "Copying %zd external libraries to package.\n", size_t(options->extraLibs.size()));
|
switch (options->deploymentMechanism) {
|
||||||
|
case Options::Bundled:
|
||||||
|
fprintf(stdout, "Copying %zd external libraries to package.\n", size_t(options->extraLibs.size()));
|
||||||
|
break;
|
||||||
|
case Options::Unbundled:
|
||||||
|
fprintf(stdout, "Skip copying of external libraries.\n");
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
for (const QString &extraLib : options->extraLibs) {
|
for (const QString &extraLib : options->extraLibs) {
|
||||||
QFileInfo extraLibInfo(extraLib);
|
QFileInfo extraLibInfo(extraLib);
|
||||||
@ -1274,8 +1319,10 @@ bool copyAndroidExtraLibs(Options *options)
|
|||||||
+ u'/'
|
+ u'/'
|
||||||
+ extraLibInfo.fileName());
|
+ extraLibInfo.fileName());
|
||||||
|
|
||||||
if (!copyFileIfNewer(extraLib, destinationFile, *options))
|
if (isDeployment(options, Options::Bundled)
|
||||||
|
&& !copyFileIfNewer(extraLib, destinationFile, *options)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
options->archExtraLibs[options->currentArchitecture] += extraLib;
|
options->archExtraLibs[options->currentArchitecture] += extraLib;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1323,8 +1370,10 @@ bool copyAndroidExtraResources(Options *options)
|
|||||||
if (!resourceFile.endsWith(".so"_L1)) {
|
if (!resourceFile.endsWith(".so"_L1)) {
|
||||||
destinationFile = assetsDir + resourceFile;
|
destinationFile = assetsDir + resourceFile;
|
||||||
} else {
|
} else {
|
||||||
if (!checkArchitecture(*options, originFile))
|
if (isDeployment(options, Options::Unbundled)
|
||||||
|
|| !checkArchitecture(*options, originFile)) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
destinationFile = libsDir + resourceFile;
|
destinationFile = libsDir + resourceFile;
|
||||||
options->archExtraPlugins[options->currentArchitecture] += resourceFile;
|
options->archExtraPlugins[options->currentArchitecture] += resourceFile;
|
||||||
}
|
}
|
||||||
@ -1487,11 +1536,12 @@ bool updateLibsXml(Options *options)
|
|||||||
const QString initClasses = options->initClasses.join(u':');
|
const QString initClasses = options->initClasses.join(u':');
|
||||||
replacements[QStringLiteral("<!-- %%INSERT_INIT_CLASSES%% -->")] = initClasses;
|
replacements[QStringLiteral("<!-- %%INSERT_INIT_CLASSES%% -->")] = initClasses;
|
||||||
|
|
||||||
// Bundle and use libs from the apk because currently we don't have a way avoid
|
// Set BUNDLE_LOCAL_QT_LIBS based on the deployment used
|
||||||
// duplicating them.
|
replacements[QStringLiteral("<!-- %%BUNDLE_LOCAL_QT_LIBS%% -->")]
|
||||||
replacements[QStringLiteral("<!-- %%BUNDLE_LOCAL_QT_LIBS%% -->")] = "1"_L1;
|
= isDeployment(options, Options::Unbundled) ? "0"_L1 : "1"_L1;
|
||||||
replacements[QStringLiteral("<!-- %%USE_LOCAL_QT_LIBS%% -->")] = "1"_L1;
|
replacements[QStringLiteral("<!-- %%USE_LOCAL_QT_LIBS%% -->")] = "1"_L1;
|
||||||
|
replacements[QStringLiteral("<!-- %%SYSTEM_LIBS_PREFIX%% -->")] =
|
||||||
|
isDeployment(options, Options::Unbundled) ? options->systemLibsPath : QStringLiteral("");
|
||||||
|
|
||||||
if (!updateFile(fileName, replacements))
|
if (!updateFile(fileName, replacements))
|
||||||
return false;
|
return false;
|
||||||
@ -1735,7 +1785,7 @@ bool readAndroidDependencyXml(Options *options,
|
|||||||
} else if (reader.name() == "jar"_L1) {
|
} else if (reader.name() == "jar"_L1) {
|
||||||
int bundling = reader.attributes().value("bundling"_L1).toInt();
|
int bundling = reader.attributes().value("bundling"_L1).toInt();
|
||||||
QString fileName = QDir::cleanPath(reader.attributes().value("file"_L1).toString());
|
QString fileName = QDir::cleanPath(reader.attributes().value("file"_L1).toString());
|
||||||
if (bundling == (options->deploymentMechanism == Options::Bundled)) {
|
if (bundling) {
|
||||||
QtDependency dependency(fileName, absoluteFilePath(options, fileName));
|
QtDependency dependency(fileName, absoluteFilePath(options, fileName));
|
||||||
if (!usedDependencies->contains(dependency.absolutePath)) {
|
if (!usedDependencies->contains(dependency.absolutePath)) {
|
||||||
options->qtDependencies[options->currentArchitecture].append(dependency);
|
options->qtDependencies[options->currentArchitecture].append(dependency);
|
||||||
@ -2322,6 +2372,10 @@ bool copyQtFiles(Options *options)
|
|||||||
case Options::Bundled:
|
case Options::Bundled:
|
||||||
fprintf(stdout, "Copying %zd dependencies from Qt into package.\n", size_t(options->qtDependencies[options->currentArchitecture].size()));
|
fprintf(stdout, "Copying %zd dependencies from Qt into package.\n", size_t(options->qtDependencies[options->currentArchitecture].size()));
|
||||||
break;
|
break;
|
||||||
|
case Options::Unbundled:
|
||||||
|
fprintf(stdout, "Copying dependencies from Qt into the package build folder,"
|
||||||
|
"skipping native libraries.\n");
|
||||||
|
break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2336,8 +2390,8 @@ bool copyQtFiles(Options *options)
|
|||||||
for (const QtDependency &qtDependency : qAsConst(options->qtDependencies[options->currentArchitecture])) {
|
for (const QtDependency &qtDependency : qAsConst(options->qtDependencies[options->currentArchitecture])) {
|
||||||
QString sourceFileName = qtDependency.absolutePath;
|
QString sourceFileName = qtDependency.absolutePath;
|
||||||
QString destinationFileName;
|
QString destinationFileName;
|
||||||
|
bool isSharedLibrary = qtDependency.relativePath.endsWith(".so"_L1);
|
||||||
if (qtDependency.relativePath.endsWith(".so"_L1)) {
|
if (isSharedLibrary) {
|
||||||
QString garbledFileName;
|
QString garbledFileName;
|
||||||
if (QDir::fromNativeSeparators(qtDependency.relativePath).startsWith("lib/"_L1)) {
|
if (QDir::fromNativeSeparators(qtDependency.relativePath).startsWith("lib/"_L1)) {
|
||||||
garbledFileName = qtDependency.relativePath.mid(sizeof("lib/") - 1);
|
garbledFileName = qtDependency.relativePath.mid(sizeof("lib/") - 1);
|
||||||
@ -2371,13 +2425,12 @@ bool copyQtFiles(Options *options)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options->deploymentMechanism == Options::Bundled
|
if ((isDeployment(options, Options::Bundled) || !isSharedLibrary)
|
||||||
&& !copyFileIfNewer(sourceFileName,
|
&& !copyFileIfNewer(sourceFileName,
|
||||||
options->outputDirectory + u'/' + destinationFileName,
|
options->outputDirectory + u'/' + destinationFileName,
|
||||||
*options)) {
|
*options)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
options->bundledFiles[options->currentArchitecture] += qMakePair(destinationFileName, qtDependency.relativePath);
|
options->bundledFiles[options->currentArchitecture] += qMakePair(destinationFileName, qtDependency.relativePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2709,6 +2762,8 @@ bool copyPackage(const Options &options)
|
|||||||
|
|
||||||
bool copyStdCpp(Options *options)
|
bool copyStdCpp(Options *options)
|
||||||
{
|
{
|
||||||
|
if (isDeployment(options, Options::Unbundled))
|
||||||
|
return true;
|
||||||
if (options->verbose)
|
if (options->verbose)
|
||||||
fprintf(stdout, "Copying STL library\n");
|
fprintf(stdout, "Copying STL library\n");
|
||||||
|
|
||||||
@ -3115,9 +3170,16 @@ int main(int argc, char *argv[])
|
|||||||
if (Q_UNLIKELY(options.timing))
|
if (Q_UNLIKELY(options.timing))
|
||||||
fprintf(stdout, "[TIMING] %lld ns: Copied GNU STL\n", options.timer.nsecsElapsed());
|
fprintf(stdout, "[TIMING] %lld ns: Copied GNU STL\n", options.timer.nsecsElapsed());
|
||||||
}
|
}
|
||||||
|
// If Unbundled deployment is used, remove app lib as we don't want it packaged inside the APK
|
||||||
if (!containsApplicationBinary(&options))
|
if (options.deploymentMechanism == Options::Unbundled) {
|
||||||
|
QString appLibPath = "%1/libs/%2/lib%3_%2.so"_L1.
|
||||||
|
arg(options.outputDirectory,
|
||||||
|
options.currentArchitecture,
|
||||||
|
options.applicationBinary);
|
||||||
|
QFile::remove(appLibPath);
|
||||||
|
} else if (!containsApplicationBinary(&options)) {
|
||||||
return CannotFindApplicationBinary;
|
return CannotFindApplicationBinary;
|
||||||
|
}
|
||||||
|
|
||||||
if (Q_UNLIKELY(options.timing))
|
if (Q_UNLIKELY(options.timing))
|
||||||
fprintf(stdout, "[TIMING] %lld ns: Checked for application binary\n", options.timer.nsecsElapsed());
|
fprintf(stdout, "[TIMING] %lld ns: Checked for application binary\n", options.timer.nsecsElapsed());
|
||||||
@ -3141,7 +3203,6 @@ int main(int argc, char *argv[])
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (options.build) {
|
if (options.build) {
|
||||||
if (!copyAndroidSources(options))
|
if (!copyAndroidSources(options))
|
||||||
return CannotCopyAndroidSources;
|
return CannotCopyAndroidSources;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user