forked from qt-creator/qt-creator
Android: Deploy Qt live apk for QML projects
Task-number: QDS-16 Change-Id: Iafb1f7ea5d354e73020ff3c5175efa82f99bdffe Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
This commit is contained in:
@@ -93,7 +93,6 @@ namespace {
|
||||
const QLatin1String OpenJDKLocationKey("OpenJDKLocation");
|
||||
const QLatin1String KeystoreLocationKey("KeystoreLocation");
|
||||
const QLatin1String AutomaticKitCreationKey("AutomatiKitCreation");
|
||||
const QLatin1String DeviceQmlsceneCommandKey("DeviceQmlsceneCommand");
|
||||
const QLatin1String MakeExtraSearchDirectory("MakeExtraSearchDirectory");
|
||||
const QLatin1String PartitionSizeKey("PartitionSize");
|
||||
const QLatin1String ToolchainHostKey("ToolchainHost");
|
||||
@@ -126,8 +125,8 @@ namespace {
|
||||
const QLatin1String sdkToolsVersionKey("Pkg.Revision");
|
||||
const QLatin1String ndkRevisionKey("Pkg.Revision");
|
||||
|
||||
const QLatin1String defaultQmlScene("org.qtproject.example.qmlscene/"
|
||||
"org.qtproject.qt5.android.bindings.QtActivity");
|
||||
const QString defaultQtLiveApk = Core::ICore::resourcePath() +
|
||||
("/qtlive/android/armv7/qt_live_viewer.apk");
|
||||
|
||||
static QString sdkSettingsFileName()
|
||||
{
|
||||
@@ -257,7 +256,6 @@ void AndroidConfig::load(const QSettings &settings)
|
||||
m_keystoreLocation = FileName::fromString(settings.value(KeystoreLocationKey).toString());
|
||||
m_toolchainHost = settings.value(ToolchainHostKey).toString();
|
||||
m_automaticKitCreation = settings.value(AutomaticKitCreationKey, true).toBool();
|
||||
m_deviceQmlsceneCommand = settings.value(DeviceQmlsceneCommandKey, defaultQmlScene).toString();
|
||||
QString extraDirectory = settings.value(MakeExtraSearchDirectory).toString();
|
||||
m_makeExtraSearchDirectories.clear();
|
||||
if (!extraDirectory.isEmpty())
|
||||
@@ -274,7 +272,6 @@ void AndroidConfig::load(const QSettings &settings)
|
||||
m_keystoreLocation = FileName::fromString(reader.restoreValue(KeystoreLocationKey, m_keystoreLocation.toString()).toString());
|
||||
m_toolchainHost = reader.restoreValue(ToolchainHostKey, m_toolchainHost).toString();
|
||||
m_automaticKitCreation = reader.restoreValue(AutomaticKitCreationKey, m_automaticKitCreation).toBool();
|
||||
m_deviceQmlsceneCommand = reader.restoreValue(DeviceQmlsceneCommandKey, m_deviceQmlsceneCommand).toString();
|
||||
QString extraDirectory = reader.restoreValue(MakeExtraSearchDirectory).toString();
|
||||
m_makeExtraSearchDirectories.clear();
|
||||
if (!extraDirectory.isEmpty())
|
||||
@@ -298,7 +295,6 @@ void AndroidConfig::save(QSettings &settings) const
|
||||
settings.setValue(KeystoreLocationKey, m_keystoreLocation.toString());
|
||||
settings.setValue(PartitionSizeKey, m_partitionSize);
|
||||
settings.setValue(AutomaticKitCreationKey, m_automaticKitCreation);
|
||||
settings.setValue(DeviceQmlsceneCommandKey, m_deviceQmlsceneCommand);
|
||||
settings.setValue(ToolchainHostKey, m_toolchainHost);
|
||||
settings.setValue(MakeExtraSearchDirectory,
|
||||
m_makeExtraSearchDirectories.isEmpty() ? QString()
|
||||
@@ -876,14 +872,12 @@ void AndroidConfig::setAutomaticKitCreation(bool b)
|
||||
m_automaticKitCreation = b;
|
||||
}
|
||||
|
||||
QString AndroidConfig::deviceQmlsceneCommand() const
|
||||
FileName AndroidConfig::qtLiveApkPath() const
|
||||
{
|
||||
return m_deviceQmlsceneCommand;
|
||||
}
|
||||
|
||||
void AndroidConfig::setDeviceQmlsceneCommand(const QString &qmlsceneCommand)
|
||||
{
|
||||
m_deviceQmlsceneCommand = qmlsceneCommand;
|
||||
QString apkPathStr(defaultQtLiveApk);
|
||||
if (qEnvironmentVariableIsSet("QTC_QT_LIVE_APK_PATH"))
|
||||
apkPathStr = QString::fromLocal8Bit(qgetenv("QTC_QT_LIVE_APK_PATH"));
|
||||
return Utils::FileName::fromString(apkPathStr);
|
||||
}
|
||||
|
||||
///////////////////////////////////
|
||||
|
||||
@@ -124,8 +124,7 @@ public:
|
||||
bool automaticKitCreation() const;
|
||||
void setAutomaticKitCreation(bool b);
|
||||
|
||||
QString deviceQmlsceneCommand() const;
|
||||
void setDeviceQmlsceneCommand(const QString &qmlsceneCommand);
|
||||
Utils::FileName qtLiveApkPath() const;
|
||||
|
||||
Utils::FileName adbToolPath() const;
|
||||
Utils::FileName androidToolPath() const;
|
||||
@@ -182,7 +181,6 @@ private:
|
||||
QStringList m_makeExtraSearchDirectories;
|
||||
unsigned m_partitionSize = 1024;
|
||||
bool m_automaticKitCreation = true;
|
||||
QString m_deviceQmlsceneCommand;
|
||||
|
||||
//caches
|
||||
mutable bool m_NdkInformationUpToDate = false;
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <projectexplorer/buildsteplist.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/runconfiguration.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <projectexplorer/toolchain.h>
|
||||
|
||||
@@ -72,6 +73,7 @@ const QLatin1String InstallFailedUpdateIncompatible("INSTALL_FAILED_UPDATE_INCOM
|
||||
const QLatin1String InstallFailedPermissionModelDowngrade("INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE");
|
||||
const QLatin1String InstallFailedVersionDowngrade("INSTALL_FAILED_VERSION_DOWNGRADE");
|
||||
const Core::Id AndroidDeployQtStep::Id("Qt4ProjectManager.AndroidDeployQtStep");
|
||||
static const char *qmlProjectRunConfigIdName = "QmlProjectManager.QmlRunConfiguration";
|
||||
|
||||
|
||||
// AndroidDeployQtStepFactory
|
||||
@@ -121,10 +123,17 @@ bool AndroidDeployQtStep::init(QList<const BuildStep *> &earlierSteps)
|
||||
return false;
|
||||
}
|
||||
|
||||
AndroidBuildApkStep *androidBuildApkStep
|
||||
= AndroidGlobal::buildStep<AndroidBuildApkStep>(buildConfiguration());
|
||||
if (!androidBuildApkStep)
|
||||
RunConfiguration *rc = target()->activeRunConfiguration();
|
||||
QTC_ASSERT(rc, return false);
|
||||
const bool deployQtLive = rc->id().name().startsWith(qmlProjectRunConfigIdName);
|
||||
ProjectExplorer::BuildConfiguration *bc = buildConfiguration();
|
||||
QTC_ASSERT(deployQtLive || bc, return false);
|
||||
|
||||
AndroidBuildApkStep *androidBuildApkStep = AndroidGlobal::buildStep<AndroidBuildApkStep>(bc);
|
||||
if (!androidBuildApkStep && !deployQtLive) {
|
||||
emit addOutput(tr("Cannot find the android build step."), OutputFormat::Stderr);
|
||||
return false;
|
||||
}
|
||||
|
||||
int deviceAPILevel = AndroidManager::minimumSDK(target());
|
||||
AndroidDeviceInfo info = earlierDeviceInfo(earlierSteps, Id);
|
||||
@@ -140,40 +149,9 @@ bool AndroidDeployQtStep::init(QList<const BuildStep *> &earlierSteps)
|
||||
m_serialNumber = info.serialNumber;
|
||||
qCDebug(deployStepLog) << "AVD:" << m_avdName << "Device Serial:" << m_serialNumber;
|
||||
|
||||
ProjectExplorer::BuildConfiguration *bc = buildConfiguration();
|
||||
m_filesToPull.clear();
|
||||
QString buildDir = bc ? bc->buildDirectory().toString() : QString();
|
||||
if (bc && !buildDir.endsWith("/")) {
|
||||
buildDir += "/";
|
||||
}
|
||||
if (!deployQtLive)
|
||||
gatherFilesToPull();
|
||||
|
||||
ProjectExplorer::ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(
|
||||
target()->kit(), ProjectExplorer::Constants::CXX_LANGUAGE_ID);
|
||||
qCDebug(deployStepLog) << "Device CPU ABI: " << info.cpuAbi.join(", ");
|
||||
qCDebug(deployStepLog) << "TC ABI: " << (tc ? tc->targetAbi().toString() : "No Toolchain");
|
||||
|
||||
QString linkerName("linker");
|
||||
QString libDirName("lib");
|
||||
if (info.cpuAbi.contains(QLatin1String("arm64-v8a")) ||
|
||||
info.cpuAbi.contains(QLatin1String("x86_64"))) {
|
||||
if (tc && tc->targetAbi().wordWidth() == 64) {
|
||||
m_filesToPull["/system/bin/app_process64"] = buildDir + "app_process";
|
||||
libDirName = "lib64";
|
||||
linkerName = "linker64";
|
||||
} else {
|
||||
m_filesToPull["/system/bin/app_process32"] = buildDir + "app_process";
|
||||
}
|
||||
} else {
|
||||
m_filesToPull["/system/bin/app_process32"] = buildDir + "app_process";
|
||||
m_filesToPull["/system/bin/app_process"] = buildDir + "app_process";
|
||||
}
|
||||
|
||||
m_filesToPull["/system/bin/" + linkerName] = buildDir + linkerName;
|
||||
m_filesToPull["/system/" + libDirName + "/libc.so"] = buildDir + "libc.so";
|
||||
|
||||
qCDebug(deployStepLog) << "Files to pull from device:";
|
||||
for (auto itr = m_filesToPull.constBegin(); itr != m_filesToPull.constEnd(); ++itr)
|
||||
qCDebug(deployStepLog) << itr.key() << "to" << itr.value();
|
||||
AndroidManager::setDeviceSerialNumber(target(), m_serialNumber);
|
||||
AndroidManager::setDeviceApiLevel(target(), info.sdk);
|
||||
|
||||
@@ -186,7 +164,8 @@ bool AndroidDeployQtStep::init(QList<const BuildStep *> &earlierSteps)
|
||||
m_manifestName = AndroidManager::manifestPath(target());
|
||||
|
||||
AndroidQtSupport *qtSupport = AndroidManager::androidQtSupport(target());
|
||||
m_useAndroiddeployqt = qtSupport && version->qtVersion() >= QtSupport::QtVersionNumber(5, 4, 0);
|
||||
m_useAndroiddeployqt = !deployQtLive && qtSupport &&
|
||||
version->qtVersion() >= QtSupport::QtVersionNumber(5, 4, 0);
|
||||
|
||||
if (m_useAndroiddeployqt) {
|
||||
m_command = version->qmakeProperty("QT_HOST_BINS");
|
||||
@@ -199,8 +178,7 @@ bool AndroidDeployQtStep::init(QList<const BuildStep *> &earlierSteps)
|
||||
m_command += QLatin1Char('/');
|
||||
m_command += Utils::HostOsInfo::withExecutableSuffix(QLatin1String("androiddeployqt"));
|
||||
|
||||
m_workingDirectory = bc ? bc->buildDirectory().appendPath(QLatin1String(Constants::ANDROID_BUILDDIRECTORY)).toString()
|
||||
: QString();
|
||||
m_workingDirectory = bc->buildDirectory().appendPath(QLatin1String(Constants::ANDROID_BUILDDIRECTORY)).toString();
|
||||
|
||||
Utils::QtcProcess::addArg(&m_androiddeployqtArgs, QLatin1String("--verbose"));
|
||||
Utils::QtcProcess::addArg(&m_androiddeployqtArgs, QLatin1String("--output"));
|
||||
@@ -233,7 +211,9 @@ bool AndroidDeployQtStep::init(QList<const BuildStep *> &earlierSteps)
|
||||
} else {
|
||||
m_uninstallPreviousPackageRun = true;
|
||||
m_command = AndroidConfigurations::currentConfig().adbToolPath().toString();
|
||||
m_apkPath = qtSupport ? qtSupport->apkPath(target()).toString() : QString();
|
||||
const AndroidConfig &config = AndroidConfigurations::currentConfig();
|
||||
m_apkPath = deployQtLive ? config.qtLiveApkPath() :
|
||||
(qtSupport ? qtSupport->apkPath(target()) : Utils::FileName());
|
||||
m_workingDirectory = bc ? bc->buildDirectory().toString() : QString();
|
||||
}
|
||||
m_environment = bc ? bc->environment() : Utils::Environment();
|
||||
@@ -262,14 +242,24 @@ AndroidDeployQtStep::DeployErrorCode AndroidDeployQtStep::runDeploy(QFutureInter
|
||||
Utils::QtcProcess::addArg(&args, m_serialNumber);
|
||||
}
|
||||
} else {
|
||||
RunConfiguration *rc = target()->activeRunConfiguration();
|
||||
QTC_ASSERT(rc, return DeployErrorCode::Failure);
|
||||
const bool deployQtLive = rc->id().name().startsWith(qmlProjectRunConfigIdName);
|
||||
QString packageName;
|
||||
if (deployQtLive) {
|
||||
AndroidManager::apkInfo(m_apkPath, &packageName);
|
||||
if (AndroidManager::packageInstalled(m_serialNumber, packageName))
|
||||
return DeployErrorCode::NoError;
|
||||
}
|
||||
|
||||
if (m_uninstallPreviousPackageRun) {
|
||||
qCDebug(deployStepLog) << "Uninstalling previous package";
|
||||
const QString packageName = AndroidManager::packageName(m_manifestName);
|
||||
if (!deployQtLive)
|
||||
packageName = AndroidManager::packageName(m_manifestName);
|
||||
if (packageName.isEmpty()) {
|
||||
emit addOutput(tr("Cannot find the package name."), OutputFormat::Stderr);
|
||||
return Failure;
|
||||
}
|
||||
|
||||
qCDebug(deployStepLog) << "Uninstalling previous package";
|
||||
emit addOutput(tr("Uninstall previous package %1.").arg(packageName), OutputFormat::NormalMessage);
|
||||
runCommand(m_adbPath,
|
||||
AndroidDeviceInfo::adbSelector(m_serialNumber)
|
||||
@@ -281,7 +271,7 @@ AndroidDeployQtStep::DeployErrorCode AndroidDeployQtStep::runDeploy(QFutureInter
|
||||
|
||||
Utils::QtcProcess::addArg(&args, QLatin1String("install"));
|
||||
Utils::QtcProcess::addArg(&args, QLatin1String("-r"));
|
||||
Utils::QtcProcess::addArg(&args, m_apkPath);
|
||||
Utils::QtcProcess::addArg(&args, m_apkPath.toString());
|
||||
}
|
||||
|
||||
m_process = new Utils::QtcProcess;
|
||||
@@ -407,12 +397,6 @@ void AndroidDeployQtStep::run(QFutureInterface<bool> &fi)
|
||||
emit setSerialNumber(serialNumber);
|
||||
}
|
||||
|
||||
if (!buildConfiguration()) { // nothing to deploy
|
||||
qCDebug(deployStepLog) << "Skip deployment. No build configuration. (e.g. *.qmlproject)";
|
||||
reportRunResult(fi, true);
|
||||
return;
|
||||
}
|
||||
|
||||
DeployErrorCode returnValue = runDeploy(fi);
|
||||
if (returnValue > DeployErrorCode::NoError && returnValue < DeployErrorCode::Failure) {
|
||||
emit askForUninstall(returnValue);
|
||||
@@ -422,7 +406,9 @@ void AndroidDeployQtStep::run(QFutureInterface<bool> &fi)
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_filesToPull.isEmpty())
|
||||
emit addOutput(tr("Pulling files necessary for debugging."), OutputFormat::NormalMessage);
|
||||
|
||||
for (auto itr = m_filesToPull.constBegin(); itr != m_filesToPull.constEnd(); ++itr) {
|
||||
QFile::remove(itr.value());
|
||||
runCommand(m_adbPath,
|
||||
@@ -438,6 +424,44 @@ void AndroidDeployQtStep::run(QFutureInterface<bool> &fi)
|
||||
reportRunResult(fi, returnValue == NoError);
|
||||
}
|
||||
|
||||
void AndroidDeployQtStep::gatherFilesToPull()
|
||||
{
|
||||
m_filesToPull.clear();
|
||||
ProjectExplorer::BuildConfiguration *bc = buildConfiguration();
|
||||
QString buildDir = bc ? bc->buildDirectory().toString() : QString();
|
||||
if (bc && !buildDir.endsWith("/")) {
|
||||
buildDir += "/";
|
||||
}
|
||||
|
||||
if (!m_deviceInfo.isValid())
|
||||
return;
|
||||
|
||||
QString linkerName("linker");
|
||||
QString libDirName("lib");
|
||||
if (m_deviceInfo.cpuAbi.contains(QLatin1String("arm64-v8a")) ||
|
||||
m_deviceInfo.cpuAbi.contains(QLatin1String("x86_64"))) {
|
||||
const Core::Id cxxLanguageId = ProjectExplorer::Constants::CXX_LANGUAGE_ID;
|
||||
ToolChain *tc = ToolChainKitInformation::toolChain(target()->kit(), cxxLanguageId);
|
||||
if (tc && tc->targetAbi().wordWidth() == 64) {
|
||||
m_filesToPull["/system/bin/app_process64"] = buildDir + "app_process";
|
||||
libDirName = "lib64";
|
||||
linkerName = "linker64";
|
||||
} else {
|
||||
m_filesToPull["/system/bin/app_process32"] = buildDir + "app_process";
|
||||
}
|
||||
} else {
|
||||
m_filesToPull["/system/bin/app_process32"] = buildDir + "app_process";
|
||||
m_filesToPull["/system/bin/app_process"] = buildDir + "app_process";
|
||||
}
|
||||
|
||||
m_filesToPull["/system/bin/" + linkerName] = buildDir + linkerName;
|
||||
m_filesToPull["/system/" + libDirName + "/libc.so"] = buildDir + "libc.so";
|
||||
|
||||
qCDebug(deployStepLog) << "Files to pull from device:";
|
||||
for (auto itr = m_filesToPull.constBegin(); itr != m_filesToPull.constEnd(); ++itr)
|
||||
qCDebug(deployStepLog) << itr.key() << "to" << itr.value();
|
||||
}
|
||||
|
||||
void AndroidDeployQtStep::runCommand(const QString &program, const QStringList &arguments)
|
||||
{
|
||||
Utils::SynchronousProcess buildProc;
|
||||
|
||||
@@ -91,6 +91,7 @@ private:
|
||||
|
||||
bool init(QList<const BuildStep *> &earlierSteps) override;
|
||||
void run(QFutureInterface<bool> &fi) override;
|
||||
void gatherFilesToPull();
|
||||
DeployErrorCode runDeploy(QFutureInterface<bool> &fi);
|
||||
void slotAskForUninstall(DeployErrorCode errorCode);
|
||||
void slotSetSerialNumber(const QString &serialNumber);
|
||||
@@ -113,7 +114,7 @@ private:
|
||||
Utils::FileName m_manifestName;
|
||||
QString m_serialNumber;
|
||||
QString m_avdName;
|
||||
QString m_apkPath;
|
||||
Utils::FileName m_apkPath;
|
||||
QMap<QString, QString> m_filesToPull;
|
||||
|
||||
QString m_targetArch;
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "androidconstants.h"
|
||||
#include "androidsignaloperation.h"
|
||||
#include "androidconfigurations.h"
|
||||
#include "androidmanager.h"
|
||||
|
||||
#include <projectexplorer/runconfiguration.h>
|
||||
|
||||
@@ -47,7 +48,10 @@ AndroidDevice::AndroidDevice()
|
||||
{
|
||||
setDisplayName(QCoreApplication::translate("Android::Internal::AndroidDevice", "Run on Android"));
|
||||
setDeviceState(DeviceReadyToUse);
|
||||
setQmlsceneCommand(AndroidConfigurations::currentConfig().deviceQmlsceneCommand());
|
||||
QString activityPath;
|
||||
const AndroidConfig &config = AndroidConfigurations::currentConfig();
|
||||
AndroidManager::apkInfo(config.qtLiveApkPath(), nullptr, nullptr, &activityPath);
|
||||
setQmlsceneCommand(activityPath);
|
||||
}
|
||||
|
||||
AndroidDevice::AndroidDevice(const AndroidDevice &other)
|
||||
|
||||
Reference in New Issue
Block a user