From 3bcae5258456577682437c2f09eae7bef59c4c34 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Mon, 22 Sep 2014 16:20:51 +0300 Subject: [PATCH] Android: Say hello to gradle! Switching from Ant to Gradle brings lots of advantages: - it is way faster when rebuilding (25-50% faster than ant). - it enables first class Android Studio integration. - adding Android Extras libs (e.g. Google Play services, OBB, etc.) to your project is now painless. [ChangeLog][Android] Added Gradle support to build the APK. Change-Id: Iee492954f8ffb2c22e6ab14a8a25faf644de9a51 Reviewed-by: Daniel Teske --- src/libs/utils/fileutils.cpp | 35 ++-- src/libs/utils/fileutils.h | 3 +- src/plugins/android/android.pro | 3 +- src/plugins/android/android.qbs | 1 + src/plugins/android/androidbuildapkstep.cpp | 28 ++- src/plugins/android/androidbuildapkstep.h | 8 +- src/plugins/android/androidbuildapkwidget.cpp | 11 +- src/plugins/android/androidbuildapkwidget.h | 1 + src/plugins/android/androidbuildapkwidget.ui | 11 +- src/plugins/android/androidconfigurations.cpp | 16 +- src/plugins/android/androidconfigurations.h | 4 + src/plugins/android/androiddeployqtstep.cpp | 8 +- src/plugins/android/androidmanager.cpp | 108 +++++++++++ src/plugins/android/androidmanager.h | 2 + src/plugins/android/androidqtsupport.cpp | 67 +++++++ src/plugins/android/androidqtsupport.h | 3 +- src/plugins/android/androidsettingswidget.cpp | 6 + src/plugins/android/androidsettingswidget.h | 1 + src/plugins/android/androidsettingswidget.ui | 101 +++++++---- .../androidpackageinstallationstep.cpp | 28 ++- .../androidpackageinstallationstep.h | 2 +- .../createandroidmanifestwizard.cpp | 171 +++++++++++------- .../createandroidmanifestwizard.h | 17 +- .../qmakeandroidbuildapkstep.cpp | 8 +- .../qmakeandroidbuildapkwidget.cpp | 6 +- .../qmakeandroidbuildapkwidget.h | 2 +- .../qmakeandroidbuildapkwidget.ui | 4 +- .../qmakeandroidsupport.cpp | 20 -- .../qmakeandroidsupport/qmakeandroidsupport.h | 2 +- 29 files changed, 507 insertions(+), 170 deletions(-) create mode 100644 src/plugins/android/androidqtsupport.cpp diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 4832d6cf834..a314c69ff56 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -139,18 +139,20 @@ bool FileUtils::removeRecursively(const FileName &filePath, QString *error) Returns whether the operation succeeded. */ bool FileUtils::copyRecursively(const FileName &srcFilePath, const FileName &tgtFilePath, - QString *error) + QString *error, const std::function ©Helper) { QFileInfo srcFileInfo = srcFilePath.toFileInfo(); if (srcFileInfo.isDir()) { - QDir targetDir(tgtFilePath.toString()); - targetDir.cdUp(); - if (!targetDir.mkdir(tgtFilePath.toFileInfo().fileName())) { - if (error) { - *error = QCoreApplication::translate("Utils::FileUtils", "Failed to create directory \"%1\".") - .arg(tgtFilePath.toUserOutput()); + if (!tgtFilePath.toFileInfo().exists()) { + QDir targetDir(tgtFilePath.toString()); + targetDir.cdUp(); + if (!targetDir.mkdir(tgtFilePath.toFileInfo().fileName())) { + if (error) { + *error = QCoreApplication::translate("Utils::FileUtils", "Failed to create directory \"%1\".") + .arg(tgtFilePath.toUserOutput()); + } + return false; } - return false; } QDir sourceDir(srcFilePath.toString()); QStringList fileNames = sourceDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot @@ -160,16 +162,21 @@ bool FileUtils::copyRecursively(const FileName &srcFilePath, const FileName &tgt newSrcFilePath.appendPath(fileName); FileName newTgtFilePath = tgtFilePath; newTgtFilePath.appendPath(fileName); - if (!copyRecursively(newSrcFilePath, newTgtFilePath, error)) + if (!copyRecursively(newSrcFilePath, newTgtFilePath, error, copyHelper)) return false; } } else { - if (!QFile::copy(srcFilePath.toString(), tgtFilePath.toString())) { - if (error) { - *error = QCoreApplication::translate("Utils::FileUtils", "Could not copy file \"%1\" to \"%2\".") - .arg(srcFilePath.toUserOutput(), tgtFilePath.toUserOutput()); + if (copyHelper) { + if (!copyHelper(srcFileInfo, tgtFilePath.toFileInfo(), error)) + return false; + } else { + if (!QFile::copy(srcFilePath.toString(), tgtFilePath.toString())) { + if (error) { + *error = QCoreApplication::translate("Utils::FileUtils", "Could not copy file \"%1\" to \"%2\".") + .arg(srcFilePath.toUserOutput(), tgtFilePath.toUserOutput()); + } + return false; } - return false; } } return true; diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index 54b1a46018e..1f20d645ff4 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -100,11 +100,12 @@ private: FileName(const QString &string); }; + class QTCREATOR_UTILS_EXPORT FileUtils { public: static bool removeRecursively(const FileName &filePath, QString *error = 0); static bool copyRecursively(const FileName &srcFilePath, const FileName &tgtFilePath, - QString *error = 0); + QString *error = 0, const std::function ©Helper = std::function()); static bool isFileNewerThan(const FileName &filePath, const QDateTime &timeStamp); static FileName resolveSymlinks(const FileName &path); static QString shortNativePath(const FileName &path); diff --git a/src/plugins/android/android.pro b/src/plugins/android/android.pro index f978d789183..b3514dc038f 100644 --- a/src/plugins/android/android.pro +++ b/src/plugins/android/android.pro @@ -89,7 +89,8 @@ SOURCES += \ javafilewizard.cpp \ avddialog.cpp \ androidbuildapkstep.cpp \ - androidbuildapkwidget.cpp + androidbuildapkwidget.cpp \ + androidqtsupport.cpp FORMS += \ androidsettingswidget.ui \ diff --git a/src/plugins/android/android.qbs b/src/plugins/android/android.qbs index 0574d80f634..914266b3afe 100644 --- a/src/plugins/android/android.qbs +++ b/src/plugins/android/android.qbs @@ -67,6 +67,7 @@ QtcPlugin { "androidplugin.h", "androidpotentialkit.cpp", "androidpotentialkit.h", + "androidqtsupport.cpp", "androidqtsupport.h", "androidqtversion.cpp", "androidqtversion.h", diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index c1b6a4cfcf1..fc9ce9eca9c 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -59,18 +59,22 @@ const QLatin1String DeployActionKey("Qt4ProjectManager.AndroidDeployQtStep.Deplo const QLatin1String KeystoreLocationKey("KeystoreLocation"); const QLatin1String BuildTargetSdkKey("BuildTargetSdk"); const QLatin1String VerboseOutputKey("VerboseOutput"); +const QLatin1String UseGradleKey("UseGradle"); AndroidBuildApkStep::AndroidBuildApkStep(ProjectExplorer::BuildStepList *parent, const Core::Id id) : ProjectExplorer::AbstractProcessStep(parent, id), m_deployAction(BundleLibrariesDeployment), m_signPackage(false), m_verbose(false), + m_useGradle(false), m_openPackageLocation(false), m_buildTargetSdk(AndroidConfig::apiLevelNameFor(AndroidConfigurations::currentConfig().highestAndroidSdk())) { const QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target()->kit()); - if (version && version->qtVersion() >= QtSupport::QtVersionNumber(5, 4, 0)) + if (version && version->qtVersion() >= QtSupport::QtVersionNumber(5, 4, 0)) { m_deployAction = DebugDeployment; + m_useGradle = AndroidConfigurations::currentConfig().useGrandle(); + } //: AndroidBuildApkStep default display name setDefaultDisplayName(tr("Build Android APK")); } @@ -81,6 +85,7 @@ AndroidBuildApkStep::AndroidBuildApkStep(ProjectExplorer::BuildStepList *parent, m_deployAction(other->deployAction()), m_signPackage(other->signPackage()), m_verbose(other->m_verbose), + m_useGradle(other->m_useGradle), m_openPackageLocation(other->m_openPackageLocation), m_buildTargetSdk(other->m_buildTargetSdk) { @@ -88,6 +93,8 @@ AndroidBuildApkStep::AndroidBuildApkStep(ProjectExplorer::BuildStepList *parent, if (version->qtVersion() < QtSupport::QtVersionNumber(5, 4, 0)) { if (m_deployAction == DebugDeployment) m_deployAction = BundleLibrariesDeployment; + if (m_useGradle) + m_useGradle = false; } } @@ -123,8 +130,7 @@ bool AndroidBuildApkStep::init() setOutputParser(parser); m_openPackageLocationForRun = m_openPackageLocation; - m_apkPath = AndroidManager::androidQtSupport(target())->apkPath(target(), m_signPackage ? AndroidQtSupport::ReleaseBuildSigned - : AndroidQtSupport::DebugBuild).toString(); + m_apkPath = AndroidManager::androidQtSupport(target())->apkPath(target()).toString(); bool result = AbstractProcessStep::init(); if (!result) @@ -169,6 +175,7 @@ bool AndroidBuildApkStep::fromMap(const QVariantMap &map) if (m_buildTargetSdk.isEmpty()) m_buildTargetSdk = AndroidConfig::apiLevelNameFor(AndroidConfigurations::currentConfig().highestAndroidSdk()); m_verbose = map.value(VerboseOutputKey).toBool(); + m_useGradle = map.value(UseGradleKey).toBool(); return ProjectExplorer::BuildStep::fromMap(map); } @@ -179,6 +186,7 @@ QVariantMap AndroidBuildApkStep::toMap() const map.insert(KeystoreLocationKey, m_keystorePath.toString()); map.insert(BuildTargetSdkKey, m_buildTargetSdk); map.insert(VerboseOutputKey, m_verbose); + map.insert(UseGradleKey, m_useGradle); return map; } @@ -195,6 +203,8 @@ QString AndroidBuildApkStep::buildTargetSdk() const void AndroidBuildApkStep::setBuildTargetSdk(const QString &sdk) { m_buildTargetSdk = sdk; + if (m_useGradle) + AndroidManager::updateGradleProperties(target()); } AndroidBuildApkStep::AndroidDeployAction AndroidBuildApkStep::deployAction() const @@ -254,6 +264,18 @@ void AndroidBuildApkStep::setVerboseOutput(bool verbose) m_verbose = verbose; } +bool AndroidBuildApkStep::useGradle() const +{ + return m_useGradle; +} + +void AndroidBuildApkStep::setUseGradle(bool b) +{ + m_useGradle = b; + if (m_useGradle) + AndroidManager::updateGradleProperties(target()); +} + bool AndroidBuildApkStep::runInGuiThread() const { return true; diff --git a/src/plugins/android/androidbuildapkstep.h b/src/plugins/android/androidbuildapkstep.h index 668f5b4b7ea..2d82b7b2617 100644 --- a/src/plugins/android/androidbuildapkstep.h +++ b/src/plugins/android/androidbuildapkstep.h @@ -72,13 +72,19 @@ public: bool openPackageLocation() const; void setOpenPackageLocation(bool open); + bool verboseOutput() const; void setVerboseOutput(bool verbose); + bool useGradle() const; + void setUseGradle(bool b); + bool runInGuiThread() const; QString buildTargetSdk() const; void setBuildTargetSdk(const QString &sdk); + + virtual Utils::FileName androidPackageSourceDir() const = 0; public slots: void setDeployAction(AndroidDeployAction deploy); @@ -95,12 +101,12 @@ protected: ProjectExplorer::BuildStepConfigWidget *createConfigWidget(); bool immutable() const { return true; } void processFinished(int exitCode, QProcess::ExitStatus status); - virtual Utils::FileName androidPackageSourceDir() const = 0; protected: AndroidDeployAction m_deployAction; bool m_signPackage; bool m_verbose; + bool m_useGradle; bool m_openPackageLocation; bool m_openPackageLocationForRun; QString m_buildTargetSdk; diff --git a/src/plugins/android/androidbuildapkwidget.cpp b/src/plugins/android/androidbuildapkwidget.cpp index 6bc769d7ca6..ade9d09bb78 100644 --- a/src/plugins/android/androidbuildapkwidget.cpp +++ b/src/plugins/android/androidbuildapkwidget.cpp @@ -91,6 +91,7 @@ AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step) m_ui->signingDebugWarningLabel->hide(); signPackageCheckBoxToggled(m_step->signPackage()); + m_ui->useGradleCheckBox->setChecked(m_step->useGradle()); m_ui->verboseOutputCheckBox->setChecked(m_step->verboseOutput()); m_ui->openPackageLocationCheckBox->setChecked(m_step->openPackageLocation()); @@ -105,6 +106,8 @@ AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step) connect(m_ui->temporaryQtOption, SIGNAL(clicked()), SLOT(updateDebugDeploySigningWarning())); connect(m_ui->bundleQtOption, SIGNAL(clicked()), SLOT(updateDebugDeploySigningWarning())); + connect(m_ui->useGradleCheckBox, SIGNAL(toggled(bool)), + this, SLOT(useGradleCheckBoxToggled(bool))); connect(m_ui->openPackageLocationCheckBox, SIGNAL(toggled(bool)), this, SLOT(openPackageLocationCheckBoxToggled(bool))); connect(m_ui->verboseOutputCheckBox, SIGNAL(toggled(bool)), @@ -128,7 +131,9 @@ AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step) updateSigningWarning(); updateDebugDeploySigningWarning(); QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(step->target()->kit()); - m_ui->temporaryQtOption->setVisible(qt->qtVersion() >= QtSupport::QtVersionNumber(5, 4, 0)); + bool qt54 = qt->qtVersion() >= QtSupport::QtVersionNumber(5, 4, 0); + m_ui->temporaryQtOption->setVisible(qt54); + m_ui->useGradleCheckBox->setVisible(qt54); } AndroidBuildApkWidget::~AndroidBuildApkWidget() @@ -254,3 +259,7 @@ void AndroidBuildApkWidget::updateDebugDeploySigningWarning() } } +void AndroidBuildApkWidget::useGradleCheckBoxToggled(bool checked) +{ + m_step->setUseGradle(checked); +} diff --git a/src/plugins/android/androidbuildapkwidget.h b/src/plugins/android/androidbuildapkwidget.h index 33215f171cf..708c400883b 100644 --- a/src/plugins/android/androidbuildapkwidget.h +++ b/src/plugins/android/androidbuildapkwidget.h @@ -64,6 +64,7 @@ private slots: void certificatesAliasComboBoxActivated(const QString &alias); void updateSigningWarning(); void updateDebugDeploySigningWarning(); + void useGradleCheckBoxToggled(bool checked); void openPackageLocationCheckBoxToggled(bool checked); void verboseOutputCheckBoxToggled(bool checked); void updateKeyStorePath(const QString &path); diff --git a/src/plugins/android/androidbuildapkwidget.ui b/src/plugins/android/androidbuildapkwidget.ui index bdcaca57c37..13d638b659d 100644 --- a/src/plugins/android/androidbuildapkwidget.ui +++ b/src/plugins/android/androidbuildapkwidget.ui @@ -184,20 +184,27 @@ Advanced Actions - + Verbose output - + Open package location after build + + + + Use Gradle + + + diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 0a2faf9e8b0..76465f24525 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -84,6 +84,7 @@ namespace { const QLatin1String OpenJDKLocationKey("OpenJDKLocation"); const QLatin1String KeystoreLocationKey("KeystoreLocation"); const QLatin1String AutomaticKitCreationKey("AutomatiKitCreation"); + const QLatin1String UseGradleKey("UseGradle"); const QLatin1String MakeExtraSearchDirectory("MakeExtraSearchDirectory"); const QLatin1String DefaultDevice("DefaultDevice"); const QLatin1String PartitionSizeKey("PartitionSize"); @@ -181,6 +182,7 @@ void AndroidConfig::load(const QSettings &settings) m_sdkLocation = FileName::fromString(settings.value(SDKLocationKey).toString()); m_ndkLocation = FileName::fromString(settings.value(NDKLocationKey).toString()); m_antLocation = FileName::fromString(settings.value(AntLocationKey).toString()); + m_useGradle = settings.value(UseGradleKey, true).toBool(); m_openJDKLocation = FileName::fromString(settings.value(OpenJDKLocationKey).toString()); m_keystoreLocation = FileName::fromString(settings.value(KeystoreLocationKey).toString()); m_toolchainHost = settings.value(ToolchainHostKey).toString(); @@ -214,7 +216,8 @@ void AndroidConfig::load(const QSettings &settings) } AndroidConfig::AndroidConfig() - : m_availableSdkPlatformsUpToDate(false), + : m_useGradle(true), + m_availableSdkPlatformsUpToDate(false), m_NdkInformationUpToDate(false) { @@ -230,6 +233,7 @@ void AndroidConfig::save(QSettings &settings) const settings.setValue(SDKLocationKey, m_sdkLocation.toString()); settings.setValue(NDKLocationKey, m_ndkLocation.toString()); settings.setValue(AntLocationKey, m_antLocation.toString()); + settings.setValue(UseGradleKey, m_useGradle); settings.setValue(OpenJDKLocationKey, m_openJDKLocation.toString()); settings.setValue(KeystoreLocationKey, m_keystoreLocation.toString()); settings.setValue(PartitionSizeKey, m_partitionSize); @@ -912,6 +916,16 @@ void AndroidConfig::setAutomaticKitCreation(bool b) m_automaticKitCreation = b; } +bool AndroidConfig::useGrandle() const +{ + return m_useGradle; +} + +void AndroidConfig::setUseGradle(bool b) +{ + m_useGradle = b; +} + /////////////////////////////////// // AndroidConfigurations /////////////////////////////////// diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index 025ca5dced5..4914e37b14b 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -115,6 +115,9 @@ public: bool automaticKitCreation() const; void setAutomaticKitCreation(bool b); + bool useGrandle() const; + void setUseGradle(bool b); + Utils::FileName adbToolPath() const; Utils::FileName androidToolPath() const; Utils::Environment androidToolEnvironment() const; @@ -179,6 +182,7 @@ private: QStringList m_makeExtraSearchDirectories; unsigned m_partitionSize; bool m_automaticKitCreation; + bool m_useGradle; //caches mutable bool m_availableSdkPlatformsUpToDate; diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 333d3e02b53..6a180201b47 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -165,6 +165,8 @@ void AndroidDeployQtStep::ctor() bool AndroidDeployQtStep::init() { + m_androiddeployqtArgs.clear(); + if (AndroidManager::checkForQt51Files(project()->projectDirectory())) emit addOutput(tr("Found old folder \"android\" in source directory. Qt 5.2 does not use that folder by default."), ErrorOutput); @@ -252,12 +254,12 @@ bool AndroidDeployQtStep::init() Utils::QtcProcess::addArg(&m_androiddeployqtArgs, QLatin1String("bundled")); break; } + if (androidBuildApkStep->useGradle()) + Utils::QtcProcess::addArg(&m_androiddeployqtArgs, QLatin1String("--gradle")); } else { m_uninstallPreviousPackageRun = true; pp->setCommand(AndroidConfigurations::currentConfig().adbToolPath().toString()); - m_apkPath = AndroidManager::androidQtSupport(target())->apkPath(target(), AndroidManager::signPackage(target()) - ? AndroidQtSupport::ReleaseBuildSigned - : AndroidQtSupport::DebugBuild).toString(); + m_apkPath = AndroidManager::androidQtSupport(target())->apkPath(target()).toString(); pp->setWorkingDirectory(bc->buildDirectory().toString()); } pp->setMacroExpander(bc->macroExpander()); diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index 6419c6dca81..bace0759ea9 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -595,4 +595,112 @@ AndroidQtSupport *AndroidManager::androidQtSupport(ProjectExplorer::Target *targ return 0; } +bool AndroidManager::useGradle(ProjectExplorer::Target *target) +{ + if (!target) + return false; + AndroidBuildApkStep *buildApkStep + = AndroidGlobal::buildStep(target->activeBuildConfiguration()); + return buildApkStep && buildApkStep->useGradle(); +} + +typedef QMap GradleProperties; + +static GradleProperties readGradleProperties(const QString &path) +{ + GradleProperties properties; + QFile file(path); + if (!file.open(QIODevice::ReadOnly)) + return properties; + + foreach (const QByteArray &line, file.readAll().split('\n')) { + if (line.trimmed().startsWith('#')) + continue; + + QList prop(line.split('=')); + if (prop.size() > 1) + properties[prop.at(0).trimmed()] = prop.at(1).trimmed(); + } + file.close(); + return properties; +} + +static bool mergeGradleProperties(const QString &path, GradleProperties properties) +{ + QFile::remove(path + QLatin1Char('~')); + QFile::rename(path, path + QLatin1Char('~')); + QFile file(path); + if (!file.open(QIODevice::Truncate | QIODevice::WriteOnly | QIODevice::Text)) + return false; + + QFile oldFile(path + QLatin1Char('~')); + if (oldFile.open(QIODevice::ReadOnly)) { + while (!oldFile.atEnd()) { + QByteArray line(oldFile.readLine()); + QList prop(line.split('=')); + if (prop.size() > 1) { + GradleProperties::iterator it = properties.find(prop.at(0).trimmed()); + if (it != properties.end()) { + file.write(it.key() + '=' + it.value() + '\n'); + properties.erase(it); + continue; + } + } + file.write(line); + } + oldFile.close(); + } else { + file.write("## This file is automatically generated by QtCreator.\n" + "#\n" + "# This file must *NOT* be checked into Version Control Systems,\n" + "# as it contains information specific to your local configuration.\n\n"); + + } + + for (GradleProperties::const_iterator it = properties.begin(); it != properties.end(); ++it) + file.write(it.key() + '=' + it.value() + '\n'); + + file.close(); + return true; +} + + +bool AndroidManager::updateGradleProperties(ProjectExplorer::Target *target) +{ + QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target->kit()); + if (!version) + return false; + + AndroidBuildApkStep *buildApkStep + = AndroidGlobal::buildStep(target->activeBuildConfiguration()); + + if (!buildApkStep || !buildApkStep->androidPackageSourceDir().appendPath(QLatin1String("gradlew")).toFileInfo().exists()) + return false; + + GradleProperties localProperties; + localProperties["sdk.dir"] = AndroidConfigurations::currentConfig().sdkLocation().toString().toLocal8Bit(); + if (!mergeGradleProperties(buildApkStep->androidPackageSourceDir().appendPath(QLatin1String("local.properties")).toString(), localProperties)) + return false; + + QString gradlePropertiesPath = buildApkStep->androidPackageSourceDir().appendPath(QLatin1String("gradle.properties")).toString(); + GradleProperties gradleProperties = readGradleProperties(gradlePropertiesPath); + gradleProperties["qt5AndroidDir"] = version->qmakeProperty("QT_INSTALL_PREFIX") + .append(QLatin1String("/src/android/java")).toLocal8Bit(); + gradleProperties["buildDir"] = ".build"; + gradleProperties["androidCompileSdkVersion"] = buildTargetSDK(target).split(QLatin1Char('-')).last().toLocal8Bit(); + if (gradleProperties["androidBuildToolsVersion"].isEmpty()) { + QString maxVersion; + QDir buildToolsDir(AndroidConfigurations::currentConfig().sdkLocation().appendPath(QLatin1String("build-tools")).toString()); + foreach (const QFileInfo &file, buildToolsDir.entryList(QDir::Dirs|QDir::NoDotAndDotDot)) { + QString ver(file.fileName()); + if (maxVersion < ver) + maxVersion = ver; + } + if (maxVersion.isEmpty()) + return false; + gradleProperties["androidBuildToolsVersion"] = maxVersion.toLocal8Bit(); + } + return mergeGradleProperties(gradlePropertiesPath, gradleProperties); +} + } // namespace Android diff --git a/src/plugins/android/androidmanager.h b/src/plugins/android/androidmanager.h index a738555d2bc..a7d36e77e04 100644 --- a/src/plugins/android/androidmanager.h +++ b/src/plugins/android/androidmanager.h @@ -96,6 +96,8 @@ public: static bool checkCertificatePassword(const QString &keystorePath, const QString &keystorePasswd, const QString &alias, const QString &certificatePasswd); static bool checkForQt51Files(Utils::FileName fileName); static AndroidQtSupport *androidQtSupport(ProjectExplorer::Target *target); + static bool useGradle(ProjectExplorer::Target *target); + static bool updateGradleProperties(ProjectExplorer::Target *target); }; } // namespace Android diff --git a/src/plugins/android/androidqtsupport.cpp b/src/plugins/android/androidqtsupport.cpp new file mode 100644 index 00000000000..52c2360d44a --- /dev/null +++ b/src/plugins/android/androidqtsupport.cpp @@ -0,0 +1,67 @@ +/************************************************************************** +** +** Copyright (c) 2014 BogDan Vatra +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "androidbuildapkstep.h" +#include "androidconstants.h" +#include "androidglobal.h" +#include "androidqtsupport.h" + +#include + +Utils::FileName Android::AndroidQtSupport::apkPath(ProjectExplorer::Target *target) const +{ + if (!target) + return Utils::FileName(); + + AndroidBuildApkStep *buildApkStep + = Android::AndroidGlobal::buildStep(target->activeBuildConfiguration()); + + if (!buildApkStep) + return Utils::FileName(); + + QString apkPath; + if (buildApkStep->useGradle()) + apkPath = QLatin1String("/build/outputs/apk/android-build-"); + else + apkPath = QLatin1String("/bin/QtApp-"); + if (buildApkStep->buildConfiguration()->buildType() == ProjectExplorer::BuildConfiguration::Release) { + apkPath += QLatin1String("release-"); + if (!buildApkStep->signPackage()) + apkPath += QLatin1String("un"); + apkPath += QLatin1String("signed.apk"); + } else { + apkPath += QLatin1String("debug"); + if (buildApkStep->signPackage()) + apkPath += QLatin1String("-signed"); + apkPath += QLatin1String(".apk"); + } + return target->activeBuildConfiguration()->buildDirectory() + .appendPath(QLatin1String(Android::Constants::ANDROID_BUILDDIRECTORY)) + .appendPath(apkPath); +} diff --git a/src/plugins/android/androidqtsupport.h b/src/plugins/android/androidqtsupport.h index 2283bf07d0b..7c28878bf85 100644 --- a/src/plugins/android/androidqtsupport.h +++ b/src/plugins/android/androidqtsupport.h @@ -62,10 +62,9 @@ public: virtual bool canHandle(const ProjectExplorer::Target *target) const = 0; virtual QStringList soLibSearchPath(const ProjectExplorer::Target *target) const = 0; virtual QStringList projectTargetApplications(const ProjectExplorer::Target *target) const = 0; - virtual Utils::FileName apkPath(ProjectExplorer::Target *target, BuildType buildType) const = 0; + virtual Utils::FileName apkPath(ProjectExplorer::Target *target) const; virtual Utils::FileName androiddeployqtPath(ProjectExplorer::Target *target) const = 0; virtual Utils::FileName androiddeployJsonPath(ProjectExplorer::Target *target) const = 0; - virtual void resetBuild(const ProjectExplorer::Target *target) = 0; }; diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index 363d1b1a765..67fc53f1050 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -162,6 +162,7 @@ AndroidSettingsWidget::AndroidSettingsWidget(QWidget *parent) m_ui->AntLocationPathChooser->setPromptDialogTitle(tr("Select ant Script")); m_ui->AntLocationPathChooser->setInitialBrowsePathBackup(dir); m_ui->AntLocationPathChooser->setPromptDialogFilter(filter); + m_ui->UseGradleCheckBox->setChecked(m_androidConfig.useGrandle()); m_ui->OpenJDKLocationPathChooser->setFileName(m_androidConfig.openJDKLocation()); m_ui->OpenJDKLocationPathChooser->setPromptDialogTitle(tr("Select JDK Path")); @@ -577,6 +578,11 @@ void AndroidSettingsWidget::createKitToggled() m_androidConfig.setAutomaticKitCreation(m_ui->CreateKitCheckBox->isChecked()); } +void AndroidSettingsWidget::useGradleToggled() +{ + m_androidConfig.setUseGradle(m_ui->UseGradleCheckBox->isChecked()); +} + void AndroidSettingsWidget::checkGdbFinished() { QPair result = m_checkGdbWatcher.future().result(); diff --git a/src/plugins/android/androidsettingswidget.h b/src/plugins/android/androidsettingswidget.h index 8e7aaf5b892..668a0d6b4ea 100644 --- a/src/plugins/android/androidsettingswidget.h +++ b/src/plugins/android/androidsettingswidget.h @@ -91,6 +91,7 @@ private slots: void dataPartitionSizeEditingFinished(); void manageAVD(); void createKitToggled(); + void useGradleToggled(); void checkGdbFinished(); void showGdbWarningDialog(); diff --git a/src/plugins/android/androidsettingswidget.ui b/src/plugins/android/androidsettingswidget.ui index 4b4321f70a8..147d49ed55b 100644 --- a/src/plugins/android/androidsettingswidget.ui +++ b/src/plugins/android/androidsettingswidget.ui @@ -30,7 +30,7 @@ - + @@ -108,7 +108,7 @@ - + Download Ant @@ -119,7 +119,7 @@ - + @@ -157,7 +157,7 @@ - + QFrame::StyledPanel @@ -452,6 +452,19 @@ + + + + + 0 + 0 + + + + Use Gradle instead of Ant + + + @@ -474,8 +487,8 @@ ndkLocationEditingFinished() - 420 - 49 + 605 + 143 352 @@ -490,8 +503,8 @@ sdkLocationEditingFinished() - 420 - 17 + 605 + 82 352 @@ -506,8 +519,8 @@ antLocationEditingFinished() - 420 - 113 + 605 + 315 352 @@ -522,8 +535,8 @@ openJDKLocationEditingFinished() - 420 - 49 + 605 + 31 352 @@ -538,8 +551,8 @@ addAVD() - 693 - 199 + 793 + 394 352 @@ -554,8 +567,8 @@ removeAVD() - 693 - 230 + 793 + 427 352 @@ -570,8 +583,8 @@ startAVD() - 693 - 261 + 793 + 460 352 @@ -586,8 +599,8 @@ avdActivated(QModelIndex) - 309 - 260 + 328 + 605 352 @@ -602,8 +615,8 @@ avdActivated(QModelIndex) - 309 - 260 + 328 + 605 352 @@ -618,8 +631,8 @@ dataPartitionSizeEditingFinished() - 543 - 153 + 614 + 360 352 @@ -634,8 +647,8 @@ manageAVD() - 568 - 268 + 792 + 359 339 @@ -650,8 +663,8 @@ createKitToggled() - 358 - 99 + 543 + 228 339 @@ -666,8 +679,8 @@ openSDKDownloadUrl() - 20 - 20 + 830 + 85 20 @@ -682,8 +695,8 @@ openNDKDownloadUrl() - 20 - 20 + 830 + 141 20 @@ -698,8 +711,8 @@ openAntDownloadUrl() - 20 - 20 + 830 + 313 20 @@ -714,8 +727,8 @@ openOpenJDKDownloadUrl() - 20 - 20 + 830 + 29 20 @@ -723,6 +736,22 @@ + + UseGradleCheckBox + toggled(bool) + AndroidSettingsWidget + useGradleToggled() + + + 395 + 238 + + + 324 + 223 + + + sdkLocationEditingFinished() diff --git a/src/plugins/qmakeandroidsupport/androidpackageinstallationstep.cpp b/src/plugins/qmakeandroidsupport/androidpackageinstallationstep.cpp index 7ab25d14b31..a79ee33e299 100644 --- a/src/plugins/qmakeandroidsupport/androidpackageinstallationstep.cpp +++ b/src/plugins/qmakeandroidsupport/androidpackageinstallationstep.cpp @@ -30,6 +30,7 @@ #include "androidpackageinstallationstep.h" #include +#include #include #include @@ -85,7 +86,14 @@ bool AndroidPackageInstallationStep::init() appendOutputParser(parser); outputParser()->setWorkingDirectory(pp->effectiveWorkingDirectory()); - m_androidDirToClean = dirPath; + m_androidDirsToClean.clear(); + // don't remove gradle's cache, it takes ages to rebuild it. + if (!QFile::exists(dirPath + QLatin1String("/build.xml")) && Android::AndroidManager::useGradle(target())) { + m_androidDirsToClean << dirPath + QLatin1String("/assets"); + m_androidDirsToClean << dirPath + QLatin1String("/libs"); + } else { + m_androidDirsToClean << dirPath; + } return AbstractProcessStep::init(); } @@ -93,14 +101,16 @@ bool AndroidPackageInstallationStep::init() void AndroidPackageInstallationStep::run(QFutureInterface &fi) { QString error; - Utils::FileName androidDir = Utils::FileName::fromString(m_androidDirToClean); - if (!m_androidDirToClean.isEmpty()&& androidDir.toFileInfo().exists()) { - emit addOutput(tr("Removing directory %1").arg(m_androidDirToClean), MessageOutput); - if (!Utils::FileUtils::removeRecursively(androidDir, &error)) { - emit addOutput(error, ErrorOutput); - fi.reportResult(false); - emit finished(); - return; + foreach (const QString &dir, m_androidDirsToClean) { + Utils::FileName androidDir = Utils::FileName::fromString(dir); + if (!dir.isEmpty() && androidDir.toFileInfo().exists()) { + emit addOutput(tr("Removing directory %1").arg(dir), MessageOutput); + if (!Utils::FileUtils::removeRecursively(androidDir, &error)) { + emit addOutput(error, ErrorOutput); + fi.reportResult(false); + emit finished(); + return; + } } } AbstractProcessStep::run(fi); diff --git a/src/plugins/qmakeandroidsupport/androidpackageinstallationstep.h b/src/plugins/qmakeandroidsupport/androidpackageinstallationstep.h index 9f4439c46f4..6b77a08b545 100644 --- a/src/plugins/qmakeandroidsupport/androidpackageinstallationstep.h +++ b/src/plugins/qmakeandroidsupport/androidpackageinstallationstep.h @@ -52,7 +52,7 @@ public: private: AndroidPackageInstallationStep(ProjectExplorer::BuildStepList *bc, AndroidPackageInstallationStep *other); - QString m_androidDirToClean; + QStringList m_androidDirsToClean; static const Core::Id Id; }; diff --git a/src/plugins/qmakeandroidsupport/createandroidmanifestwizard.cpp b/src/plugins/qmakeandroidsupport/createandroidmanifestwizard.cpp index 5c0aead33a5..5db1df253c2 100644 --- a/src/plugins/qmakeandroidsupport/createandroidmanifestwizard.cpp +++ b/src/plugins/qmakeandroidsupport/createandroidmanifestwizard.cpp @@ -29,6 +29,7 @@ #include "createandroidmanifestwizard.h" +#include #include #include @@ -44,6 +45,7 @@ #include +#include #include #include #include @@ -52,6 +54,7 @@ using namespace Android; using namespace QmakeAndroidSupport::Internal; +using namespace Utils; using QmakeProjectManager::QmakeProject; using QmakeProjectManager::QmakeProFileNode; @@ -79,7 +82,7 @@ ChooseProFilePage::ChooseProFilePage(CreateAndroidManifestWizard *wizard, const QFormLayout *fl = new QFormLayout(this); QLabel *label = new QLabel(this); label->setWordWrap(true); - label->setText(tr("Select the .pro file for which you want to create an AndroidManifest.xml file.")); + label->setText(tr("Select the .pro file for which you want to create the Android template files.")); fl->addRow(label); m_comboBox = new QComboBox(this); @@ -131,8 +134,8 @@ ChooseDirectoryPage::ChooseDirectoryPage(CreateAndroidManifestWizard *wizard) fl->addRow(hbox); - m_androidPackageSourceDir = new Utils::PathChooser(this); - m_androidPackageSourceDir->setExpectedKind(Utils::PathChooser::Directory); + m_androidPackageSourceDir = new PathChooser(this); + m_androidPackageSourceDir->setExpectedKind(PathChooser::Directory); fl->addRow(tr("Android package source directory:"), m_androidPackageSourceDir); if (androidPackageDir.isEmpty()) { @@ -144,7 +147,7 @@ ChooseDirectoryPage::ChooseDirectoryPage(CreateAndroidManifestWizard *wizard) connect(m_androidPackageSourceDir, SIGNAL(changed(QString)), this, SLOT(checkPackageSourceDir())); } else { - label->setText(tr("The Android manifest file will be created in the ANDROID_PACKAGE_SOURCE_DIR set in the .pro file.")); + label->setText(tr("The Android template files will be created in the ANDROID_PACKAGE_SOURCE_DIR set in the .pro file.")); m_androidPackageSourceDir->setPath(androidPackageDir); m_androidPackageSourceDir->setReadOnly(true); } @@ -154,6 +157,15 @@ ChooseDirectoryPage::ChooseDirectoryPage(CreateAndroidManifestWizard *wizard) connect(m_androidPackageSourceDir, SIGNAL(pathChanged(QString)), m_wizard, SLOT(setDirectory(QString))); + + if (wizard->copyGradle()) { + QCheckBox *checkBox = new QCheckBox(this); + checkBox->setChecked(true); + connect(checkBox, &QCheckBox::toggled, wizard, &CreateAndroidManifestWizard::setCopyGradle); + checkBox->setText(tr("Copy the Gradle files to Android directory")); + checkBox->setToolTip(tr("It is highly recommended if you are plannig to extend the Java part of your Qt application.")); + fl->addRow(checkBox); + } } void ChooseDirectoryPage::checkPackageSourceDir() @@ -180,12 +192,15 @@ bool ChooseDirectoryPage::isComplete() const // CreateAndroidManifestWizard // CreateAndroidManifestWizard::CreateAndroidManifestWizard(ProjectExplorer::Target *target) - : m_target(target), m_node(0) + : m_target(target), m_node(0), m_copyState(Ask) { - setWindowTitle(tr("Create Android Manifest Wizard")); + setWindowTitle(tr("Create Android Template Files Wizard")); QmakeProject *project = static_cast(target->project()); QList nodes = project->applicationProFiles(); + QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target->kit()); + m_copyGradle = version && version->qtVersion() >= QtSupport::QtVersionNumber(5, 4, 0); + if (nodes.isEmpty()) { // oh uhm can't create anything addPage(new NoApplicationProFilePage(this)); @@ -213,91 +228,121 @@ void CreateAndroidManifestWizard::setDirectory(const QString &directory) m_directory = directory; } -QString CreateAndroidManifestWizard::sourceFolder() const +bool CreateAndroidManifestWizard::copyGradle() { - QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(m_target->kit()); - if (!version) - return QString(); - return version->qmakeProperty("QT_INSTALL_PREFIX"); + return m_copyGradle; } -QString CreateAndroidManifestWizard::sourceFileName() const +void CreateAndroidManifestWizard::setCopyGradle(bool copy) { - QString srcFolder = sourceFolder(); - if (srcFolder.isEmpty()) - return srcFolder; - Utils::FileName srcPath - = Utils::FileName::fromString(srcFolder) - .appendPath(QLatin1String("src/android")); - if (QFile::exists(srcPath.toString() + QLatin1String("/templates/AndroidManifest.xml"))) - srcPath.appendPath(QLatin1String("/templates/AndroidManifest.xml")); - else - srcPath.appendPath(QLatin1String("/java/AndroidManifest.xml")); - return srcPath.toString(); + m_copyGradle = copy; } -void CreateAndroidManifestWizard::createAndroidManifestFile() +bool CreateAndroidManifestWizard::copy(const QFileInfo &src, const QFileInfo &dst, QStringList * addedFiles) +{ + bool copyFile = true; + if (dst.exists()) { + switch (m_copyState) { + case Ask: + { + int res = QMessageBox::question(this, + tr("Overwrite %1 file").arg(dst.fileName()), + tr("Overwrite existing \"%1\"?") + .arg(QDir(m_directory).relativeFilePath(dst.absoluteFilePath())), + QMessageBox::Yes | QMessageBox::YesToAll | + QMessageBox::No | QMessageBox::NoToAll | + QMessageBox::Cancel); + switch (res) { + case QMessageBox::YesToAll: + m_copyState = OverwriteAll; + break; + + case QMessageBox::Yes: + break; + + case QMessageBox::NoToAll: + m_copyState = SkipAll; + copyFile = false; + break; + + case QMessageBox::No: + copyFile = false; + break; + default: + return false; + } + } + break; + case SkipAll: + copyFile = false; + break; + default: + break; + } + if (copyFile) + QFile::remove(dst.filePath()); + } + + if (!dst.absoluteDir().exists()) + dst.absoluteDir().mkpath(dst.absolutePath()); + + if (copyFile && !QFile::copy(src.filePath(), dst.filePath())) { + QMessageBox::warning(this, tr("File Creation Error"), + tr("Could not copy file \"%1\" to \"%2\".") + .arg(src.filePath()).arg(dst.filePath())); + return false; + } + addedFiles->append(dst.absoluteFilePath()); + return true; +} + +void CreateAndroidManifestWizard::createAndroidTemplateFiles() { if (m_directory.isEmpty()) return; - QDir dir; - if (!QFileInfo(m_directory).exists()) - dir.mkpath(m_directory); - QString fileName = m_directory + QLatin1String("/AndroidManifest.xml"); - if (QFileInfo(fileName).exists()) { - if (QMessageBox::question(this, tr("Overwrite AndroidManifest.xml"), - tr("Overwrite existing AndroidManifest.xml?"), - QMessageBox::Yes, QMessageBox::No) - == QMessageBox::Yes) { - if (!QFile(m_directory + QLatin1String("/AndroidManifest.xml")).remove()) { - QMessageBox::warning(this, tr("File Removal Error"), - tr("Could not remove file %1.").arg(fileName)); - return; - } - } else { - return; - } - } + QStringList addedFiles; + QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(m_target->kit()); + if (!version || version->qtVersion() < QtSupport::QtVersionNumber(5, 4, 0)) { + const QString src(version->qmakeProperty("QT_INSTALL_PREFIX") + .append(QLatin1String("/src/android/java/AndroidManifest.xml"))); + FileUtils::copyRecursively(FileName::fromString(src), + FileName::fromString(m_directory + QLatin1String("/AndroidManifest.xml")), + 0, [this, &addedFiles](QFileInfo src, QFileInfo dst, QString *){return copy(src, dst, &addedFiles);}); + } else { + const QString src(version->qmakeProperty("QT_INSTALL_PREFIX") + .append(QLatin1String("/src/android/templates"))); - QString srcFileName = sourceFileName(); + FileUtils::copyRecursively(FileName::fromString(src), + FileName::fromString(m_directory), + 0, [this, &addedFiles](QFileInfo src, QFileInfo dst, QString *){return copy(src, dst, &addedFiles);}); - if (!QFileInfo(srcFileName).exists()) { - QMessageBox::warning(this, tr("File Creation Error"), - tr("\"%1\" is missing.\n" - "Check your Qt installation here:\n" - "\"%2\"").arg(fileName).arg(sourceFolder())); - return; - } + if (m_copyGradle) + FileUtils::copyRecursively(AndroidConfigurations::currentConfig().sdkLocation().appendPath(QLatin1String("/tools/templates/gradle/wrapper")), + FileName::fromString(m_directory), + 0, [this, &addedFiles](QFileInfo src, QFileInfo dst, QString *){return copy(src, dst, &addedFiles);}); - if (!QFile::copy(srcFileName, fileName)) { - QMessageBox::warning(this, tr("File Creation Error"), - tr("Could not create file %1.\n" - "Verify that you have writing rights in your project directory.").arg(fileName)); - return; + AndroidManager::updateGradleProperties(m_target); } + m_node->addFiles(addedFiles); if (m_node->singleVariableValue(QmakeProjectManager::AndroidPackageSourceDir).isEmpty()) { // and now time for some magic - QString dir = QFileInfo(fileName).absolutePath(); QString value = QLatin1String("$$PWD/") - + QDir(m_target->project()->projectDirectory().toString()).relativeFilePath(dir); + + QDir(m_target->project()->projectDirectory().toString()).relativeFilePath(m_directory); bool result = m_node->setProVariable(QLatin1String("ANDROID_PACKAGE_SOURCE_DIR"), QStringList(value)); - QStringList unChanged; - m_node->addFiles(QStringList(fileName), &unChanged); - if (result == false - || !unChanged.isEmpty()) { + if (!result) { QMessageBox::warning(this, tr("Project File not Updated"), tr("Could not update the .pro file %1.").arg(m_node->path())); } } - Core::EditorManager::openEditor(fileName); + Core::EditorManager::openEditor(m_directory + QLatin1String("/AndroidManifest.xml")); } void CreateAndroidManifestWizard::accept() { - createAndroidManifestFile(); + createAndroidTemplateFiles(); Utils::Wizard::accept(); } diff --git a/src/plugins/qmakeandroidsupport/createandroidmanifestwizard.h b/src/plugins/qmakeandroidsupport/createandroidmanifestwizard.h index fa1abca4622..082401f386e 100644 --- a/src/plugins/qmakeandroidsupport/createandroidmanifestwizard.h +++ b/src/plugins/qmakeandroidsupport/createandroidmanifestwizard.h @@ -29,6 +29,7 @@ #ifndef CREATEANDROIDMANIFESTWIZARD_H #define CREATEANDROIDMANIFESTWIZARD_H +#include #include #include @@ -92,18 +93,28 @@ public: QmakeProjectManager::QmakeProFileNode *node() const; void setNode(QmakeProjectManager::QmakeProFileNode *node); - QString sourceFolder() const; - QString sourceFileName() const; - void accept(); + bool copyGradle(); public slots: void setDirectory(const QString &directory); + void setCopyGradle(bool copy); + private: + enum CopyState { + Ask, + OverwriteAll, + SkipAll + }; + bool copy(const QFileInfo &src, const QFileInfo &dst, QStringList *addedFiles); + void createAndroidManifestFile(); + void createAndroidTemplateFiles(); ProjectExplorer::Target *m_target; QmakeProjectManager::QmakeProFileNode *m_node; QString m_directory; + CopyState m_copyState; + bool m_copyGradle; }; } //namespace QmakeAndroidSupport diff --git a/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkstep.cpp b/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkstep.cpp index 7e60d281e1e..9b8b1be0ce6 100644 --- a/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkstep.cpp +++ b/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkstep.cpp @@ -223,8 +223,6 @@ bool QmakeAndroidBuildApkStep::init() << outputDir << QLatin1String("--deployment") << deploymentMethod - << QLatin1String("--ant") - << AndroidConfigurations::currentConfig().antToolPath().toString() << QLatin1String("--android-platform") << AndroidManager::buildTargetSDK(target()) << QLatin1String("--jdk") @@ -233,6 +231,12 @@ bool QmakeAndroidBuildApkStep::init() if (m_verbose) arguments << QLatin1String("--verbose"); + if (m_useGradle) + arguments << QLatin1String("--gradle"); + else + arguments << QLatin1String("--ant") + << AndroidConfigurations::currentConfig().antToolPath().toString(); + if (buildConfiguration()->buildType() == ProjectExplorer::BuildConfiguration::Release) arguments << QLatin1String("--release"); diff --git a/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkwidget.cpp b/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkwidget.cpp index d5d9ffbe3b7..23e2e1c763d 100644 --- a/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkwidget.cpp +++ b/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkwidget.cpp @@ -92,8 +92,8 @@ QmakeAndroidBuildApkWidget::QmakeAndroidBuildApkWidget(QmakeAndroidBuildApkStep connect(m_ui->inputFileComboBox, SIGNAL(currentIndexChanged(int)), SLOT(inputFileComboBoxIndexChanged())); - connect(m_ui->createAndroidManifestButton, SIGNAL(clicked()), - SLOT(createManifestButton())); + connect(m_ui->createAndroidTemplatesButton, SIGNAL(clicked()), + SLOT(createAndroidTemplatesButton())); connect(m_ui->addAndroidExtraLibButton, SIGNAL(clicked()), SLOT(addAndroidExtraLib())); @@ -149,7 +149,7 @@ void QmakeAndroidBuildApkWidget::inputFileComboBoxIndexChanged() m_step->setProFilePathForInputFile(proFilePath); } -void QmakeAndroidBuildApkWidget::createManifestButton() +void QmakeAndroidBuildApkWidget::createAndroidTemplatesButton() { CreateAndroidManifestWizard wizard(m_step->target()); wizard.exec(); diff --git a/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkwidget.h b/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkwidget.h index 155d0321e47..dd0885207ed 100644 --- a/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkwidget.h +++ b/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkwidget.h @@ -62,7 +62,7 @@ public: private slots: void updateInputFileUi(); void inputFileComboBoxIndexChanged(); - void createManifestButton(); + void createAndroidTemplatesButton(); void addAndroidExtraLib(); void removeAndroidExtraLib(); void checkEnableRemoveButton(); diff --git a/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkwidget.ui b/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkwidget.ui index 9e40690678e..48c6d3a5cff 100644 --- a/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkwidget.ui +++ b/src/plugins/qmakeandroidsupport/qmakeandroidbuildapkwidget.ui @@ -29,9 +29,9 @@ - + - Create AndroidManifest.xml + Create Templates diff --git a/src/plugins/qmakeandroidsupport/qmakeandroidsupport.cpp b/src/plugins/qmakeandroidsupport/qmakeandroidsupport.cpp index 4941e13ba8e..32c5c93a88e 100644 --- a/src/plugins/qmakeandroidsupport/qmakeandroidsupport.cpp +++ b/src/plugins/qmakeandroidsupport/qmakeandroidsupport.cpp @@ -88,26 +88,6 @@ QStringList QmakeAndroidSupport::projectTargetApplications(const ProjectExplorer } apps.sort(); return apps; - -} - -Utils::FileName QmakeAndroidSupport::apkPath(ProjectExplorer::Target *target, AndroidQtSupport::BuildType buildType) const -{ - QString packageName = QLatin1String("QtApp"); - QString buildTypeName; - if (buildType == DebugBuild) - buildTypeName = QLatin1String("debug"); - else if (buildType == ReleaseBuildUnsigned) - buildTypeName =QLatin1String("release-unsigned"); - else - buildTypeName = QLatin1String("release"); - - return target->activeBuildConfiguration()->buildDirectory() - .appendPath(QLatin1String(Android::Constants::ANDROID_BUILDDIRECTORY)) - .appendPath(QLatin1String("bin")) - .appendPath(QString::fromLatin1("%1-%2.apk") - .arg(packageName) - .arg(buildTypeName)); } Utils::FileName QmakeAndroidSupport::androiddeployqtPath(ProjectExplorer::Target *target) const diff --git a/src/plugins/qmakeandroidsupport/qmakeandroidsupport.h b/src/plugins/qmakeandroidsupport/qmakeandroidsupport.h index a805ea81f06..17f4f410827 100644 --- a/src/plugins/qmakeandroidsupport/qmakeandroidsupport.h +++ b/src/plugins/qmakeandroidsupport/qmakeandroidsupport.h @@ -38,11 +38,11 @@ namespace Internal { class QmakeAndroidSupport : public Android::AndroidQtSupport { Q_OBJECT + public: bool canHandle(const ProjectExplorer::Target *target) const; QStringList soLibSearchPath(const ProjectExplorer::Target *target) const; QStringList projectTargetApplications(const ProjectExplorer::Target *target) const; - Utils::FileName apkPath(ProjectExplorer::Target *target, BuildType buildType) const; Utils::FileName androiddeployqtPath(ProjectExplorer::Target *target) const; Utils::FileName androiddeployJsonPath(ProjectExplorer::Target *target) const;