Android: Make the manifest less to scary to read and edit

Remove unnecessary elements from the manifest file, making it
easier to manage and read. Mostly, the removed elements are
more internal data that is populated by the build system
and the user shouldn't have to worry or confront that.

Also, use the same formatting used by Android Studio.

[ChangeLog][Android] Remove some elements from the manifest
file that are internal, to make it easier to deal with the
manifest.

Pick-to: 6.2
Change-Id: I6a1f275b579370972c0bf022502a8fbfe7d0bfd1
Reviewed-by: BogDan Vatra <bogdan@kdab.com>
This commit is contained in:
Assam Boudjelthia 2021-06-22 19:34:12 +03:00
parent af6bc5a21b
commit 963a31c0f4
4 changed files with 113 additions and 99 deletions

View File

@ -1,4 +1,5 @@
/* /*
Copyright (C) 2021 The Qt Company Ltd.
Copyright (c) 2019, BogDan Vatra <bogdan@kde.org> Copyright (c) 2019, BogDan Vatra <bogdan@kde.org>
Contact: http://www.qt.io/licensing/ Contact: http://www.qt.io/licensing/
@ -42,6 +43,7 @@ import android.content.ContextWrapper;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ComponentInfo; import android.content.pm.ComponentInfo;
import android.content.res.Resources;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
@ -170,13 +172,16 @@ public abstract class QtLoader {
// this function is used to load and start the loader // this function is used to load and start the loader
private void loadApplication(Bundle loaderParams) private void loadApplication(Bundle loaderParams)
{ {
final Resources resources = m_context.getResources();
final String packageName = m_context.getPackageName();
try { try {
final int errorCode = loaderParams.getInt(ERROR_CODE_KEY); final int errorCode = loaderParams.getInt(ERROR_CODE_KEY);
if (errorCode != 0) { if (errorCode != 0) {
// fatal error, show the error and quit // fatal error, show the error and quit
AlertDialog errorDialog = new AlertDialog.Builder(m_context).create(); AlertDialog errorDialog = new AlertDialog.Builder(m_context).create();
errorDialog.setMessage(loaderParams.getString(ERROR_MESSAGE_KEY)); errorDialog.setMessage(loaderParams.getString(ERROR_MESSAGE_KEY));
errorDialog.setButton(m_context.getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() { errorDialog.setButton(resources.getString(android.R.string.ok),
new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
finish(); finish();
@ -187,11 +192,9 @@ public abstract class QtLoader {
} }
// add all bundled Qt libs to loader params // add all bundled Qt libs to loader params
ArrayList<String> libs = new ArrayList<String>(); int id = resources.getIdentifier("bundled_libs", "array", packageName);
if (m_contextInfo.metaData.containsKey("android.app.bundled_libs_resource_id")) { final String[] bundledLibs = resources.getStringArray(id);
int resourceId = m_contextInfo.metaData.getInt("android.app.bundled_libs_resource_id"); ArrayList<String> libs = new ArrayList<>(prefferedAbiLibs(bundledLibs));
libs.addAll(prefferedAbiLibs(m_context.getResources().getStringArray(resourceId)));
}
String libName = null; String libName = null;
if (m_contextInfo.metaData.containsKey("android.app.lib_name")) { if (m_contextInfo.metaData.containsKey("android.app.lib_name")) {
@ -225,12 +228,11 @@ public abstract class QtLoader {
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
AlertDialog errorDialog = new AlertDialog.Builder(m_context).create(); AlertDialog errorDialog = new AlertDialog.Builder(m_context).create();
if (m_contextInfo.metaData.containsKey("android.app.fatal_error_msg")) int id = resources.getIdentifier("fatal_error_msg", "string",
errorDialog.setMessage(m_contextInfo.metaData.getString("android.app.fatal_error_msg")); packageName);
else errorDialog.setMessage(resources.getString(id));
errorDialog.setMessage("Fatal error, your application can't be started."); errorDialog.setButton(resources.getString(android.R.string.ok),
new DialogInterface.OnClickListener() {
errorDialog.setButton(m_context.getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
finish(); finish();
@ -243,14 +245,16 @@ public abstract class QtLoader {
public void startApp(final boolean firstStart) public void startApp(final boolean firstStart)
{ {
try { try {
if (m_contextInfo.metaData.containsKey("android.app.qt_libs_resource_id")) { final Resources resources = m_context.getResources();
int resourceId = m_contextInfo.metaData.getInt("android.app.qt_libs_resource_id"); final String packageName = m_context.getPackageName();
m_qtLibs = prefferedAbiLibs(m_context.getResources().getStringArray(resourceId)); int id = resources.getIdentifier("qt_libs", "array", packageName);
} m_qtLibs = prefferedAbiLibs(resources.getStringArray(id));
if (m_contextInfo.metaData.containsKey("android.app.use_local_qt_libs") id = resources.getIdentifier("use_local_qt_libs", "string", packageName);
&& m_contextInfo.metaData.getInt("android.app.use_local_qt_libs") == 1) { final int useLocalLibs = Integer.parseInt(resources.getString(id));
ArrayList<String> libraryList = new ArrayList<String>();
if (useLocalLibs == 1) {
ArrayList<String> libraryList = new ArrayList<>();
boolean apkDeployFromSystem = false; boolean apkDeployFromSystem = false;
String apkPath = m_context.getApplicationInfo().publicSourceDir; String apkPath = m_context.getApplicationInfo().publicSourceDir;
@ -293,10 +297,13 @@ public abstract class QtLoader {
libraryList.add(libPrefix + lib + ".so"); libraryList.add(libPrefix + lib + ".so");
} }
if (m_contextInfo.metaData.containsKey("android.app.bundle_local_qt_libs") id = resources.getIdentifier("bundle_local_qt_libs", "string", packageName);
&& m_contextInfo.metaData.getInt("android.app.bundle_local_qt_libs") == 1) { final int bundleLocalLibs = Integer.parseInt(resources.getString(id));
int resourceId = m_contextInfo.metaData.getInt("android.app.load_local_libs_resource_id");
for (String libs : prefferedAbiLibs(m_context.getResources().getStringArray(resourceId))) { if (bundleLocalLibs == 1) {
id = resources.getIdentifier("load_local_libs", "array", packageName);
ArrayList<String> localLibs = prefferedAbiLibs(resources.getStringArray(id));
for (String libs : localLibs) {
for (String lib : libs.split(":")) { for (String lib : libs.split(":")) {
if (!lib.isEmpty()) if (!lib.isEmpty())
libraryList.add(libsDir + lib); libraryList.add(libsDir + lib);
@ -310,10 +317,11 @@ public abstract class QtLoader {
loaderParams.putInt(ERROR_CODE_KEY, 0); loaderParams.putInt(ERROR_CODE_KEY, 0);
loaderParams.putString(DEX_PATH_KEY, new String()); loaderParams.putString(DEX_PATH_KEY, new String());
loaderParams.putString(LOADER_CLASS_NAME_KEY, loaderClassName()); loaderParams.putString(LOADER_CLASS_NAME_KEY, loaderClassName());
if (m_contextInfo.metaData.containsKey("android.app.static_init_classes")) {
loaderParams.putStringArray(STATIC_INIT_CLASSES_KEY, id = resources.getIdentifier("static_init_classes", "string", packageName);
m_contextInfo.metaData.getString("android.app.static_init_classes").split(":")); loaderParams.putStringArray(STATIC_INIT_CLASSES_KEY, resources.getString(id)
} .split(":"));
loaderParams.putStringArrayList(NATIVE_LIBRARIES_KEY, libraryList); loaderParams.putStringArrayList(NATIVE_LIBRARIES_KEY, libraryList);

View File

@ -1,75 +1,82 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<manifest package="org.qtproject.example" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="-- %%INSERT_VERSION_NAME%% --" android:versionCode="-- %%INSERT_VERSION_CODE%% --" android:installLocation="auto"> <manifest xmlns:android="http://schemas.android.com/apk/res/android"
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application. package="org.qtproject.example"
android:installLocation="auto"
android:versionCode="-- %%INSERT_VERSION_CODE%% --"
android:versionName="-- %%INSERT_VERSION_NAME%% --">
<!-- The comment below will be replaced with dependencies permissions upon deployment.
Remove the comment if you do not require these default permissions. --> Remove the comment if you do not require these default permissions. -->
<!-- %%INSERT_PERMISSIONS --> <!-- %%INSERT_PERMISSIONS -->
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application. <!-- The comment below will be replaced with dependencies permissions upon deployment.
Remove the comment if you do not require these default features. --> Remove the comment if you do not require these default features. -->
<!-- %%INSERT_FEATURES --> <!-- %%INSERT_FEATURES -->
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/> <supports-screens
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt.android.bindings.QtApplication" android:label="-- %%INSERT_APP_NAME%% --" android:extractNativeLibs="true" android:requestLegacyExternalStorage="true"> android:anyDensity="true"
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="org.qtproject.qt.android.bindings.QtActivity" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="unspecified" android:launchMode="singleTop"> android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true" />
<application
android:name="org.qtproject.qt.android.bindings.QtApplication"
android:extractNativeLibs="true"
android:hardwareAccelerated="true"
android:label="-- %%INSERT_APP_NAME%% --"
android:requestLegacyExternalStorage="true">
<activity
android:name="org.qtproject.qt.android.bindings.QtActivity"
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
android:label="-- %%INSERT_APP_NAME%% --"
android:launchMode="singleTop"
android:screenOrientation="unspecified">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter> </intent-filter>
<!-- Application arguments -->
<meta-data android:name="android.app.arguments" android:value="-- %%INSERT_APP_ARGUMENTS%% --"/>
<!-- Application arguments --> <!-- Application arguments -->
<meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/> <meta-data
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/> android:name="android.app.arguments"
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/> android:value="-- %%INSERT_APP_ARGUMENTS%% --" />
<!-- Deploy Qt libs as part of package --> <!-- Application arguments -->
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/> <meta-data
android:name="android.app.lib_name"
android:value="-- %%INSERT_APP_LIB_NAME%% --" />
<!-- Run with local libs -->
<meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.load_local_libs_resource_id" android:resource="@array/load_local_libs"/>
<meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
<meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
<!-- Used to specify custom system library path to run with local system libs --> <!-- Used to specify custom system library path to run with local system libs -->
<!-- <meta-data android:name="android.app.system_libs_prefix" android:value="/system/lib/"/> --> <!-- <meta-data android:name="android.app.system_libs_prefix" android:value="/system/lib/"/>-->
<!-- Messages maps -->
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
<meta-data android:value="@string/unsupported_android_version" android:name="android.app.unsupported_android_version"/>
<!-- Messages maps -->
<!-- Splash screen --> <!-- Splash screen -->
<!-- Orientation-specific (portrait/landscape) data is checked first. If not available for current orientation, <!-- Orientation-specific (portrait/landscape) data is checked first. If not available
then android.app.splash_screen_drawable. For best results, use together with splash_screen_sticky and for current orientation, then android.app.splash_screen_drawable. For best
use hideSplashScreen() with a fade-out animation from Qt Android Extras to hide the splash screen when you results, use together with splash_screen_sticky and use hideSplashScreen() with
are done populating your window with content. --> a fade-out animation to hide the splash screen when you are done populating
<!-- meta-data android:name="android.app.splash_screen_drawable_portrait" android:resource="@drawable/logo_portrait" / --> your window with content. -->
<!-- meta-data android:name="android.app.splash_screen_drawable_landscape" android:resource="@drawable/logo_landscape" / --> <!-- <meta-data android:name="android.app.splash_screen_drawable_portrait" android:resource="@drawable/logo_portrait" />-->
<!-- meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/ --> <!-- <meta-data android:name="android.app.splash_screen_drawable_landscape" android:resource="@drawable/logo_landscape" />-->
<!-- meta-data android:name="android.app.splash_screen_sticky" android:value="true"/ --> <!-- <meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/>-->
<!-- <meta-data android:name="android.app.splash_screen_sticky" android:value="true"/>-->
<!-- Splash screen --> <!-- Splash screen -->
<!-- Background running --> <!-- Background running -->
<!-- Warning: changing this value to true may cause unexpected crashes if the <!-- Warning: changing this value to true may cause unexpected crashes if the
application still try to draw after application still try to draw after
"applicationStateChanged(Qt::ApplicationSuspended)" "applicationStateChanged(Qt::ApplicationSuspended)" signal is sent! -->
signal is sent! --> <meta-data
<meta-data android:name="android.app.background_running" android:value="false"/> android:name="android.app.background_running"
android:value="false" />
<!-- Background running --> <!-- Background running -->
<!-- extract android style --> <!-- extract android style -->
<!-- available android:values : <!-- available android:values :
* default - In most cases this will be the same as "full", but it can also be something else if needed, e.g., for compatibility reasons * default - In most cases this will be the same as "full", but it can also be
* something else if needed, e.g., for compatibility reasons
* full - useful QWidget & Quick Controls 1 apps * full - useful QWidget & Quick Controls 1 apps
* minimal - useful for Quick Controls 2 apps, it is much faster than "full" * minimal - useful for Quick Controls 2 apps, it is much faster than "full"
* none - useful for apps that don't use any of the above Qt modules * none - useful for apps that don't use any of the above Qt modules -->
--> <meta-data
<meta-data android:name="android.app.extract_android_style" android:value="default"/> android:name="android.app.extract_android_style"
android:value="default" />
<!-- extract android style --> <!-- extract android style -->
</activity> </activity>
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
</application> </application>
</manifest> </manifest>

View File

@ -1,7 +1,6 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<resources> <resources>
<!-- The following is handled automatically by the deployment tool. It should <!-- DO NOT EDIT THIS: This file is populated automatically by the deployment tool. -->
not be edited manually. -->
<array name="bundled_libs"> <array name="bundled_libs">
<!-- %%INSERT_EXTRA_LIBS%% --> <!-- %%INSERT_EXTRA_LIBS%% -->
@ -15,4 +14,7 @@
<!-- %%INSERT_LOCAL_LIBS%% --> <!-- %%INSERT_LOCAL_LIBS%% -->
</array> </array>
<string name="static_init_classes"><!-- %%INSERT_INIT_CLASSES%% --></string>
<string name="use_local_qt_libs"><!-- %%USE_LOCAL_QT_LIBS%% --></string>
<string name="bundle_local_qt_libs"><!-- %%BUNDLE_LOCAL_QT_LIBS%% --></string>
</resources> </resources>

View File

@ -235,7 +235,6 @@ struct Options
bool usesOpenGL = false; bool usesOpenGL = false;
// Per package collected information // Per package collected information
QStringList localJars;
QStringList initClasses; QStringList initClasses;
QStringList permissions; QStringList permissions;
QStringList features; QStringList features;
@ -1411,10 +1410,20 @@ bool updateLibsXml(Options *options)
allLocalLibs += QLatin1String(" <item>%1;%2</item>\n").arg(it.key(), localLibs.join(QLatin1Char(':'))); allLocalLibs += QLatin1String(" <item>%1;%2</item>\n").arg(it.key(), localLibs.join(QLatin1Char(':')));
} }
options->initClasses.removeDuplicates();
QHash<QString, QString> replacements; QHash<QString, QString> replacements;
replacements[QStringLiteral("<!-- %%INSERT_QT_LIBS%% -->")] += qtLibs.trimmed(); replacements[QStringLiteral("<!-- %%INSERT_QT_LIBS%% -->")] += qtLibs.trimmed();
replacements[QStringLiteral("<!-- %%INSERT_LOCAL_LIBS%% -->")] = allLocalLibs.trimmed(); replacements[QStringLiteral("<!-- %%INSERT_LOCAL_LIBS%% -->")] = allLocalLibs.trimmed();
replacements[QStringLiteral("<!-- %%INSERT_EXTRA_LIBS%% -->")] = extraLibs.trimmed(); replacements[QStringLiteral("<!-- %%INSERT_EXTRA_LIBS%% -->")] = extraLibs.trimmed();
const QString initClasses = options->initClasses.join(QLatin1Char(':'));
replacements[QStringLiteral("<!-- %%INSERT_INIT_CLASSES%% -->")] = initClasses;
// Bundle and use libs from the apk because currently we don't have a way avoid
// duplicating them.
replacements[QStringLiteral("<!-- %%BUNDLE_LOCAL_QT_LIBS%% -->")] = QLatin1String("1");
replacements[QStringLiteral("<!-- %%USE_LOCAL_QT_LIBS%% -->")] = QLatin1String("1");
if (!updateFile(fileName, replacements)) if (!updateFile(fileName, replacements))
return false; return false;
@ -1456,22 +1465,13 @@ bool updateAndroidManifest(Options &options)
if (options.verbose) if (options.verbose)
fprintf(stdout, " -- AndroidManifest.xml \n"); fprintf(stdout, " -- AndroidManifest.xml \n");
options.localJars.removeDuplicates();
options.initClasses.removeDuplicates();
QHash<QString, QString> replacements; QHash<QString, QString> replacements;
replacements[QStringLiteral("-- %%INSERT_APP_NAME%% --")] = options.applicationBinary; replacements[QStringLiteral("-- %%INSERT_APP_NAME%% --")] = options.applicationBinary;
replacements[QStringLiteral("-- %%INSERT_APP_ARGUMENTS%% --")] = options.applicationArguments; replacements[QStringLiteral("-- %%INSERT_APP_ARGUMENTS%% --")] = options.applicationArguments;
replacements[QStringLiteral("-- %%INSERT_APP_LIB_NAME%% --")] = options.applicationBinary; replacements[QStringLiteral("-- %%INSERT_APP_LIB_NAME%% --")] = options.applicationBinary;
replacements[QStringLiteral("-- %%INSERT_LOCAL_JARS%% --")] = options.localJars.join(QLatin1Char(':'));
replacements[QStringLiteral("-- %%INSERT_INIT_CLASSES%% --")] = options.initClasses.join(QLatin1Char(':'));
replacements[QStringLiteral("-- %%INSERT_VERSION_NAME%% --")] = options.versionName; replacements[QStringLiteral("-- %%INSERT_VERSION_NAME%% --")] = options.versionName;
replacements[QStringLiteral("-- %%INSERT_VERSION_CODE%% --")] = options.versionCode; replacements[QStringLiteral("-- %%INSERT_VERSION_CODE%% --")] = options.versionCode;
replacements[QStringLiteral("package=\"org.qtproject.example\"")] = QLatin1String("package=\"%1\"").arg(options.packageName); replacements[QStringLiteral("package=\"org.qtproject.example\"")] = QLatin1String("package=\"%1\"").arg(options.packageName);
replacements[QStringLiteral("-- %%BUNDLE_LOCAL_QT_LIBS%% --")]
= (options.deploymentMechanism == Options::Bundled) ? QLatin1String("1") : QLatin1String("0");
// use libs from the apk
replacements[QStringLiteral("-- %%USE_LOCAL_QT_LIBS%% --")] = QLatin1String("1");
QString permissions; QString permissions;
for (const QString &permission : qAsConst(options.permissions)) for (const QString &permission : qAsConst(options.permissions))
@ -1664,9 +1664,6 @@ bool readAndroidDependencyXml(Options *options,
} }
} }
if (!fileName.isEmpty())
options->localJars.append(fileName);
if (reader.attributes().hasAttribute(QLatin1String("initClass"))) { if (reader.attributes().hasAttribute(QLatin1String("initClass"))) {
options->initClasses.append(reader.attributes().value(QLatin1String("initClass")).toString()); options->initClasses.append(reader.attributes().value(QLatin1String("initClass")).toString());
} }