diff options
author | Jake Petroules <jake.petroules@qt.io> | 2017-09-29 09:18:58 -0700 |
---|---|---|
committer | Jake Petroules <jake.petroules@qt.io> | 2017-10-04 22:09:17 +0000 |
commit | 9d1a039f674417add84105dd75b58a1151ce450b (patch) | |
tree | ee726e86c3f41c736b5119ded4e9b01136110c6a /src/lib/corelib | |
parent | 4e811eada68dc26a425b7a7e4e9b0d367ad95c74 (diff) | |
download | qbs-9d1a039f674417add84105dd75b58a1151ce450b.tar.gz |
Add support for running Android apps on devices
Change-Id: I1a3a4afb9742f1c89e6396430d178277ea41c451
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Diffstat (limited to 'src/lib/corelib')
-rw-r--r-- | src/lib/corelib/api/project.cpp | 2 | ||||
-rw-r--r-- | src/lib/corelib/api/projectdata.cpp | 3 | ||||
-rw-r--r-- | src/lib/corelib/api/projectdata_p.h | 8 | ||||
-rw-r--r-- | src/lib/corelib/api/runenvironment.cpp | 68 |
4 files changed, 77 insertions, 4 deletions
diff --git a/src/lib/corelib/api/project.cpp b/src/lib/corelib/api/project.cpp index 19b2072f9..ad49a7f2c 100644 --- a/src/lib/corelib/api/project.cpp +++ b/src/lib/corelib/api/project.cpp @@ -760,7 +760,7 @@ RuleCommandList ProjectPrivate::ruleCommands(const ProductData &product, static bool productIsRunnable(const ResolvedProductConstPtr &product) { - return product->fileTags.contains("application"); + return isRunnableArtifact(product->fileTags); } static bool productIsMultiplexed(const ResolvedProductConstPtr &product) diff --git a/src/lib/corelib/api/projectdata.cpp b/src/lib/corelib/api/projectdata.cpp index b5e1ddd9d..03aa95f60 100644 --- a/src/lib/corelib/api/projectdata.cpp +++ b/src/lib/corelib/api/projectdata.cpp @@ -261,8 +261,7 @@ bool ArtifactData::isGenerated() const */ bool ArtifactData::isExecutable() const { - return d->fileTags.contains(QLatin1String("application")) - || d->fileTags.contains(QLatin1String("msi")); + return Internal::isRunnableArtifact(Internal::FileTags::fromStringList(d->fileTags)); } /*! diff --git a/src/lib/corelib/api/projectdata_p.h b/src/lib/corelib/api/projectdata_p.h index 58ae2ffea..41617fc81 100644 --- a/src/lib/corelib/api/projectdata_p.h +++ b/src/lib/corelib/api/projectdata_p.h @@ -40,6 +40,7 @@ #define QBS_PROJECTDATA_P_H #include "projectdata.h" +#include <language/filetags.h> #include <QtCore/qshareddata.h> @@ -138,6 +139,13 @@ public: QString buildDir; }; +static inline bool isRunnableArtifact(const FileTags &fileTags) +{ + return fileTags.contains("application") + || fileTags.contains("android.apk") + || fileTags.contains("msi"); +} + } // namespace Internal } // namespace qbs diff --git a/src/lib/corelib/api/runenvironment.cpp b/src/lib/corelib/api/runenvironment.cpp index a2caea987..16c188442 100644 --- a/src/lib/corelib/api/runenvironment.cpp +++ b/src/lib/corelib/api/runenvironment.cpp @@ -60,6 +60,8 @@ #include <QtCore/qtemporaryfile.h> #include <QtCore/qvariant.h> +#include <QtXml/qdom.h> + #include <stdlib.h> namespace qbs { @@ -208,6 +210,34 @@ static QString findExecutable(const QStringList &fileNames) return QString(); } +static QString findMainIntent(const QString &aapt, const QString &apkFilePath) +{ + QString packageId; + QString activity; + QProcess aaptProcess; + aaptProcess.start(aapt, QStringList() + << QStringLiteral("dump") + << QStringLiteral("badging") + << apkFilePath); + if (aaptProcess.waitForFinished(-1)) { + for (auto line : aaptProcess.readAllStandardOutput().split('\n')) { + if (line.startsWith(QByteArrayLiteral("package:"))) { + QDomDocument doc; + doc.setContent(QByteArrayLiteral("<") + line + QByteArrayLiteral("/>")); + packageId = doc.firstChild().toElement().attribute(QStringLiteral("name")); + } else if (line.startsWith(QByteArrayLiteral("launchable-activity:"))) { + QDomDocument doc; + doc.setContent(QByteArrayLiteral("<") + line + QByteArrayLiteral("/>")); + activity = doc.firstChild().toElement().attribute(QStringLiteral("name")); + } + } + } + + if (!packageId.isEmpty() && !activity.isEmpty()) + return packageId + QStringLiteral("/") + activity; + return QString(); +} + int RunEnvironment::doRunTarget(const QString &targetBin, const QStringList &arguments) { const QStringList targetOS = d->resolvedProduct->moduleProperties->qbsPropertyValue( @@ -219,7 +249,43 @@ int RunEnvironment::doRunTarget(const QString &targetBin, const QStringList &arg QStringList targetArguments = arguments; const QString completeSuffix = QFileInfo(targetBin).completeSuffix(); - if (targetOS.contains(QLatin1String("ios")) || targetOS.contains(QLatin1String("tvos"))) { + if (targetOS.contains(QLatin1String("android"))) { + const auto aapt = d->resolvedProduct->moduleProperties->moduleProperty( + QStringLiteral("Android.sdk"), QStringLiteral("aaptFilePath")).toString(); + const auto intent = findMainIntent(aapt, targetBin); + const auto sdkDir = d->resolvedProduct->moduleProperties->moduleProperty( + QStringLiteral("Android.sdk"), QStringLiteral("sdkDir")).toString(); + targetExecutable = sdkDir + QStringLiteral("/platform-tools/adb"); + + QProcess process; + process.setProcessChannelMode(QProcess::ForwardedChannels); + process.start(targetExecutable, QStringList() + << QStringLiteral("install") + << QStringLiteral("-r") // replace existing application + << QStringLiteral("-t") // allow test packages + << QStringLiteral("-d") // allow version code downgrade + << targetBin); + if (!process.waitForFinished()) { + if (process.error() == QProcess::FailedToStart) { + throw ErrorInfo(Tr::tr("The process '%1' could not be started: %2") + .arg(targetExecutable) + .arg(process.errorString())); + } else { + d->logger.qbsWarning() + << "QProcess error: " << process.errorString(); + } + + return EXIT_FAILURE; + } + + targetArguments << QStringList() + << QStringLiteral("shell") + << QStringLiteral("am") + << QStringLiteral("start") + << QStringLiteral("-W") // wait for launch to complete + << QStringLiteral("-n") + << intent; + } else if (targetOS.contains(QLatin1String("ios")) || targetOS.contains(QLatin1String("tvos"))) { const QString bundlePath = targetBin + QLatin1String("/.."); if (QFileInfo(targetExecutable = findExecutable(QStringList() |