diff options
author | Christian Kandeler <christian.kandeler@qt.io> | 2018-08-16 16:17:44 +0200 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@qt.io> | 2018-10-19 09:17:55 +0000 |
commit | 4ebb16fa78277d23a1f571cc3485ce178588983d (patch) | |
tree | 9d1cdc694a0d1d227e8b9eae6e1a223c61652a53 | |
parent | 89d5e584db040bcccab9d8c02479e437f3e37530 (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>
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) |