aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@qt.io>2018-08-16 16:17:44 +0200
committerChristian Kandeler <christian.kandeler@qt.io>2018-10-19 09:17:55 +0000
commit4ebb16fa78277d23a1f571cc3485ce178588983d (patch)
tree9d1cdc694a0d1d227e8b9eae6e1a223c61652a53
parent89d5e584db040bcccab9d8c02479e437f3e37530 (diff)
Android: Enable building apps with native code and no multiplexing
Until now, we needed to either put the native part into its own product or use multiplexing with the "APK product" serving as the aggregate. Now it is also possible to use a single product without multiplexing, which is a more natural approach in the case where there is only one architecture. Change-Id: I976168c99f75ad8e4940ac61f957c64ad29f5f5c Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
-rw-r--r--doc/reference/items/convenience/application.qdoc10
-rw-r--r--share/qbs/imports/qbs/base/Application.qbs4
-rw-r--r--share/qbs/modules/Android/sdk/sdk.qbs2
-rw-r--r--tests/auto/blackbox/testdata-android/minimal-native/minimal-native.qbs11
-rw-r--r--tests/auto/blackbox/testdata-android/minimal-native/src/main/AndroidManifest.xml12
-rw-r--r--tests/auto/blackbox/testdata-android/minimal-native/src/main/java/minimal/MinimalNative.java22
-rw-r--r--tests/auto/blackbox/testdata-android/minimal-native/src/main/native/native.c8
-rw-r--r--tests/auto/blackbox/tst_blackboxandroid.cpp39
8 files changed, 91 insertions, 17 deletions
diff --git a/doc/reference/items/convenience/application.qdoc b/doc/reference/items/convenience/application.qdoc
index 30b3f9c73..c09d15918 100644
--- a/doc/reference/items/convenience/application.qdoc
+++ b/doc/reference/items/convenience/application.qdoc
@@ -36,13 +36,13 @@
\brief Product of the type application.
- An Application item is a \l{Product} of the \l{Product::}{type}
- \c "application".
+ An Application item is a \l{Product} representing an application.
- The target artifact of this type of product is usually an executable binary.
+ The target artifact of this type of product is usually an executable binary
+ tagged \c "application".
However, on Android, unless you set \l{Product::}{consoleApplication} to \c true,
- the application target will be an APK package, and a dependency to the
- \l{Android.sdk} module is automatically added to the product.
+ the application target will be an APK package tagged \c "android.apk", and a
+ dependency to the \l{Android.sdk} module is automatically added to the product.
*/
/*!
diff --git a/share/qbs/imports/qbs/base/Application.qbs b/share/qbs/imports/qbs/base/Application.qbs
index 04d5d3feb..694cfb83b 100644
--- a/share/qbs/imports/qbs/base/Application.qbs
+++ b/share/qbs/imports/qbs/base/Application.qbs
@@ -29,7 +29,7 @@
****************************************************************************/
NativeBinary {
- type: ["application"]
+ type: isForAndroid && !consoleApplication ? ["android.apk"] : ["application"]
property bool usesNativeCode
@@ -48,6 +48,8 @@ NativeBinary {
}
Properties {
condition: isForAndroid && !consoleApplication && usesNativeCode
+ && multiplexByQbsProperties && multiplexByQbsProperties.contains("architectures")
+ && qbs.architectures && qbs.architectures.length > 1
aggregate: true
multiplexedType: "android.nativelibrary"
}
diff --git a/share/qbs/modules/Android/sdk/sdk.qbs b/share/qbs/modules/Android/sdk/sdk.qbs
index 6ed8a2b26..9b684736b 100644
--- a/share/qbs/modules/Android/sdk/sdk.qbs
+++ b/share/qbs/modules/Android/sdk/sdk.qbs
@@ -418,7 +418,7 @@ Module {
]
Artifact {
filePath: product.Android.sdk.apkBaseName + ".apk"
- fileTags: ["android.apk", "application"]
+ fileTags: "android.apk"
}
prepare: SdkUtils.prepareAaptPackage.apply(SdkUtils, arguments)
}
diff --git a/tests/auto/blackbox/testdata-android/minimal-native/minimal-native.qbs b/tests/auto/blackbox/testdata-android/minimal-native/minimal-native.qbs
new file mode 100644
index 000000000..8cdda7a3c
--- /dev/null
+++ b/tests/auto/blackbox/testdata-android/minimal-native/minimal-native.qbs
@@ -0,0 +1,11 @@
+CppApplication {
+ name: "minimalnative"
+ qbs.buildVariant: "release"
+ Properties { condition: qbs.toolchain.contains("clang"); Android.ndk.appStl: "c++_shared" }
+ Android.ndk.appStl: "stlport_shared"
+ files: "src/main/native/native.c"
+ Group {
+ files: "libdependency.so"
+ fileTags: "android.nativelibrary"
+ }
+}
diff --git a/tests/auto/blackbox/testdata-android/minimal-native/src/main/AndroidManifest.xml b/tests/auto/blackbox/testdata-android/minimal-native/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..575e95e8d
--- /dev/null
+++ b/tests/auto/blackbox/testdata-android/minimal-native/src/main/AndroidManifest.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="somedefault">
+ <application android:label="MinimalNative">
+ <activity android:name="MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/auto/blackbox/testdata-android/minimal-native/src/main/java/minimal/MinimalNative.java b/tests/auto/blackbox/testdata-android/minimal-native/src/main/java/minimal/MinimalNative.java
new file mode 100644
index 000000000..1464d2593
--- /dev/null
+++ b/tests/auto/blackbox/testdata-android/minimal-native/src/main/java/minimal/MinimalNative.java
@@ -0,0 +1,22 @@
+package minimalnative;
+
+import android.app.Activity;
+import android.widget.TextView;
+import android.os.Bundle;
+
+public class MinimalNative extends Activity
+{
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ TextView tv = new TextView(this);
+ tv.setText(stringFromNative());
+ setContentView(tv);
+ }
+
+ public native String stringFromNative();
+
+ static {
+ System.loadLibrary("minimal");
+ }
+}
diff --git a/tests/auto/blackbox/testdata-android/minimal-native/src/main/native/native.c b/tests/auto/blackbox/testdata-android/minimal-native/src/main/native/native.c
new file mode 100644
index 000000000..6b625858b
--- /dev/null
+++ b/tests/auto/blackbox/testdata-android/minimal-native/src/main/native/native.c
@@ -0,0 +1,8 @@
+#include <string.h>
+#include <jni.h>
+
+jstring
+Java_minimalnative_MinimalNative_stringFromNative(JNIEnv* env, jobject thiz)
+{
+ return (*env)->NewStringUTF(env, "This message comes from native code.");
+}
diff --git a/tests/auto/blackbox/tst_blackboxandroid.cpp b/tests/auto/blackbox/tst_blackboxandroid.cpp
index 2b8f2bd76..5630bdcb5 100644
--- a/tests/auto/blackbox/tst_blackboxandroid.cpp
+++ b/tests/auto/blackbox/tst_blackboxandroid.cpp
@@ -74,6 +74,7 @@ void TestBlackboxAndroid::android()
QFETCH(QString, projectDir);
QFETCH(QStringList, productNames);
QFETCH(QList<QByteArrayList>, expectedFilesLists);
+ QFETCH(QStringList, customProperties);
const SettingsPtr s = settings();
Profile p(profileName(), s.get());
@@ -100,11 +101,16 @@ void TestBlackboxAndroid::android()
static const QStringList configNames { "debug", "release" };
for (const QString &configName : configNames) {
auto currentExpectedFilesLists = expectedFilesLists;
- QbsRunParameters params(QStringList { "--command-echo-mode", "command-line",
- "modules.Android.ndk.platform:android-21",
- "config:" + configName });
- params.profile = p.name();
- QCOMPARE(runQbs(params), 0);
+ const QString configArgument = "config:" + configName;
+ QbsRunParameters resolveParams("resolve");
+ resolveParams.arguments << "modules.Android.ndk.platform:android-21" << configArgument
+ << customProperties;
+ resolveParams.profile = p.name();
+ QCOMPARE(runQbs(resolveParams), 0);
+ QbsRunParameters buildParams(QStringList{"--command-echo-mode", "command-line",
+ configArgument});
+ buildParams.profile = p.name();
+ QCOMPARE(runQbs(buildParams), 0);
for (const QString &productName : qAsConst(productNames)) {
QCOMPARE(m_qbsStdout.count("Generating BuildConfig.java"), productNames.size());
QVERIFY(m_qbsStdout.contains(productName.toLocal8Bit() + ".apk"));
@@ -207,6 +213,7 @@ void TestBlackboxAndroid::android_data()
QTest::addColumn<QString>("projectDir");
QTest::addColumn<QStringList>("productNames");
QTest::addColumn<QList<QByteArrayList>>("expectedFilesLists");
+ QTest::addColumn<QStringList>("customProperties");
QTest::newRow("teapot")
<< "teapot" << QStringList("TeapotNativeActivity")
<< (QList<QByteArrayList>() << commonFiles + expandArchs(archs, {
@@ -216,7 +223,16 @@ void TestBlackboxAndroid::android_data()
"lib/${ARCH}/libgdbserver.so",
cxxLibPath("libgnustl_shared.so"),
"lib/${ARCH}/libTeapotNativeActivity.so",
- "res/layout/widgets.xml"}));
+ "res/layout/widgets.xml"}))
+ << QStringList();
+ QTest::newRow("minimal-native")
+ << "minimal-native" << QStringList("minimalnative")
+ << (QList<QByteArrayList>() << commonFiles + expandArchs({archs.first()}, {
+ "lib/${ARCH}/libminimalnative.so",
+ cxxLibPath("libstlport_shared.so"),
+ "lib/${ARCH}/libdependency.so"}))
+ << QStringList{"products.minimalnative.multiplexByQbsProperties:[]",
+ "modules.qbs.architecture:" + archsStringList.first()};
QTest::newRow("no native")
<< "no-native"
<< QStringList("com.example.android.basicmediadecoder")
@@ -237,9 +253,10 @@ void TestBlackboxAndroid::android_data()
"res/layout/sample_main.xml",
"res/menu/action_menu.xml",
"res/menu-v11/action_menu.xml",
- "res/raw/vid_bigbuckbunny.mp4"}));
+ "res/raw/vid_bigbuckbunny.mp4"}))
+ << QStringList();
QTest::newRow("aidl") << "aidl" << QStringList("io.qbs.aidltest")
- << QList<QByteArrayList>{commonFiles};
+ << QList<QByteArrayList>{commonFiles} << QStringList();
QTest::newRow("multiple libs")
<< "multiple-libs-per-apk"
<< QStringList("twolibs")
@@ -248,7 +265,8 @@ void TestBlackboxAndroid::android_data()
"lib/${ARCH}/libgdbserver.so",
"lib/${ARCH}/liblib1.so",
"lib/${ARCH}/liblib2.so",
- cxxLibPath("libstlport_shared.so")}));
+ cxxLibPath("libstlport_shared.so")}))
+ << QStringList();
QByteArrayList expectedFiles1 = (commonFiles
+ expandArchs(QByteArrayList{"armeabi-v7a", "x86"}, {
"resources.arsc",
@@ -268,7 +286,8 @@ void TestBlackboxAndroid::android_data()
QTest::newRow("multiple apks")
<< "multiple-apks-per-project"
<< (QStringList() << "twolibs1" << "twolibs2")
- << QList<QByteArrayList>{expectedFiles1, expectedFiles2};
+ << QList<QByteArrayList>{expectedFiles1, expectedFiles2}
+ << QStringList();
}
QTEST_MAIN(TestBlackboxAndroid)