forked from qt-creator/qt-creator
Move qmake specific part to qmake plugin, generalize android support
- Split up androiddeployqt into two steps: One building the apk, and one deploying it to the device. - The build apk step base class AndroidBuildApkStep is ihneritaged by the qmake specific class QmakeAndroidBuildApkStep. - The deployment step is still called androiddeployqt - Move all qmake specific code to the qmakeprojectmanager plguin - Flip the depencency between the android and qmake plugin, now the qmake plugin depends on the android plugin, implementing a interface the android plugin provides. - Note: This removes the debug deployment for now. Change-Id: I1c386640159ed14b637668abde8eb3b9009ab803 Reviewed-by: BogDan Vatra <bogdan@kde.org>
This commit is contained in:
committed by
Daniel Teske
parent
4657ac7452
commit
64e5a543a8
313
src/plugins/android/androidbuildapkstep.cpp
Normal file
313
src/plugins/android/androidbuildapkstep.cpp
Normal file
@@ -0,0 +1,313 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** Copyright (c) 2014 BogDan Vatra <bog_dan_ro@yahoo.com>
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** 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 "androidbuildapkwidget.h"
|
||||
#include "androidconfigurations.h"
|
||||
#include "androidconstants.h"
|
||||
#include "androidmanager.h"
|
||||
#include "androidqtsupport.h"
|
||||
#include "certificatesmodel.h"
|
||||
|
||||
#include "javaparser.h"
|
||||
|
||||
#include <coreplugin/fileutils.h>
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <projectexplorer/buildconfiguration.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/target.h>
|
||||
|
||||
#include <qtsupport/qtkitinformation.h>
|
||||
|
||||
#include <utils/qtcprocess.h>
|
||||
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace Android {
|
||||
using namespace Internal;
|
||||
|
||||
const QLatin1String DeployActionKey("Qt4ProjectManager.AndroidDeployQtStep.DeployQtAction");
|
||||
const QLatin1String KeystoreLocationKey("KeystoreLocation");
|
||||
const QLatin1String BuildTargetSdkKey("BuildTargetSdk");
|
||||
const QLatin1String VerboseOutputKey("VerboseOutput");
|
||||
|
||||
AndroidBuildApkStep::AndroidBuildApkStep(ProjectExplorer::BuildStepList *parent, const Core::Id id)
|
||||
: ProjectExplorer::AbstractProcessStep(parent, id),
|
||||
m_deployAction(BundleLibrariesDeployment),
|
||||
m_signPackage(false),
|
||||
m_verbose(false),
|
||||
m_openPackageLocation(false),
|
||||
m_buildTargetSdk(AndroidConfig::apiLevelNameFor(AndroidConfigurations::currentConfig().highestAndroidSdk()))
|
||||
{
|
||||
//: AndroidBuildApkStep default display name
|
||||
setDefaultDisplayName(tr("Build Android APK"));
|
||||
}
|
||||
|
||||
AndroidBuildApkStep::AndroidBuildApkStep(ProjectExplorer::BuildStepList *parent,
|
||||
AndroidBuildApkStep *other)
|
||||
: ProjectExplorer::AbstractProcessStep(parent, other),
|
||||
m_deployAction(other->deployAction()),
|
||||
m_signPackage(other->signPackage()),
|
||||
m_verbose(other->m_verbose),
|
||||
m_openPackageLocation(other->m_openPackageLocation),
|
||||
m_buildTargetSdk(other->m_buildTargetSdk)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool AndroidBuildApkStep::init()
|
||||
{
|
||||
ProjectExplorer::BuildConfiguration *bc = buildConfiguration();
|
||||
|
||||
if (m_signPackage) {
|
||||
// check keystore and certificate passwords
|
||||
while (!AndroidManager::checkKeystorePassword(m_keystorePath.toString(), m_keystorePasswd)) {
|
||||
if (!keystorePassword())
|
||||
return false; // user canceled
|
||||
}
|
||||
|
||||
while (!AndroidManager::checkCertificatePassword(m_keystorePath.toString(), m_keystorePasswd, m_certificateAlias, m_certificatePasswd)) {
|
||||
if (!certificatePassword())
|
||||
return false; // user canceled
|
||||
}
|
||||
|
||||
|
||||
if (bc->buildType() == ProjectExplorer::BuildConfiguration::Debug)
|
||||
emit addOutput(tr("Warning: Signing a debug package."), BuildStep::ErrorMessageOutput);
|
||||
}
|
||||
|
||||
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target()->kit());
|
||||
if (!version)
|
||||
return false;
|
||||
|
||||
JavaParser *parser = new JavaParser;
|
||||
parser->setProjectFileList(target()->project()->files(ProjectExplorer::Project::AllFiles));
|
||||
parser->setSourceDirectory(androidPackageSourceDir());
|
||||
parser->setBuildDirectory(Utils::FileName::fromString(bc->buildDirectory().appendPath(QLatin1String(Constants::ANDROID_BUILDDIRECTORY)).toString()));
|
||||
setOutputParser(parser);
|
||||
|
||||
m_openPackageLocationForRun = m_openPackageLocation;
|
||||
m_apkPath = AndroidManager::androidQtSupport(target())->apkPath(target(), m_signPackage ? AndroidQtSupport::ReleaseBuildSigned
|
||||
: AndroidQtSupport::DebugBuild).toString();
|
||||
|
||||
bool result = AbstractProcessStep::init();
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AndroidBuildApkStep::showInGraphicalShell()
|
||||
{
|
||||
Core::FileUtils::showInGraphicalShell(Core::ICore::instance()->mainWindow(), m_apkPath);
|
||||
}
|
||||
|
||||
ProjectExplorer::BuildStepConfigWidget *AndroidBuildApkStep::createConfigWidget()
|
||||
{
|
||||
return new AndroidBuildApkWidget(this);
|
||||
}
|
||||
|
||||
void AndroidBuildApkStep::processFinished(int exitCode, QProcess::ExitStatus status)
|
||||
{
|
||||
AbstractProcessStep::processFinished(exitCode, status);
|
||||
if (m_openPackageLocationForRun && status == QProcess::NormalExit && exitCode == 0)
|
||||
QMetaObject::invokeMethod(this, "showInGraphicalShell", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
bool AndroidBuildApkStep::fromMap(const QVariantMap &map)
|
||||
{
|
||||
m_deployAction = AndroidDeployAction(map.value(DeployActionKey, BundleLibrariesDeployment).toInt());
|
||||
if ( m_deployAction == DebugDeployment
|
||||
&& QtSupport::QtKitInformation::qtVersion(target()->kit())->qtVersion() < QtSupport::QtVersionNumber(5, 4, 0)) {
|
||||
m_deployAction = BundleLibrariesDeployment;
|
||||
}
|
||||
|
||||
m_keystorePath = Utils::FileName::fromString(map.value(KeystoreLocationKey).toString());
|
||||
m_signPackage = false; // don't restore this
|
||||
m_buildTargetSdk = map.value(BuildTargetSdkKey).toString();
|
||||
if (m_buildTargetSdk.isEmpty())
|
||||
m_buildTargetSdk = AndroidConfig::apiLevelNameFor(AndroidConfigurations::currentConfig().highestAndroidSdk());
|
||||
m_verbose = map.value(VerboseOutputKey).toBool();
|
||||
return ProjectExplorer::BuildStep::fromMap(map);
|
||||
}
|
||||
|
||||
QVariantMap AndroidBuildApkStep::toMap() const
|
||||
{
|
||||
QVariantMap map = ProjectExplorer::AbstractProcessStep::toMap();
|
||||
map.insert(DeployActionKey, m_deployAction);
|
||||
map.insert(KeystoreLocationKey, m_keystorePath.toString());
|
||||
map.insert(BuildTargetSdkKey, m_buildTargetSdk);
|
||||
map.insert(VerboseOutputKey, m_verbose);
|
||||
return map;
|
||||
}
|
||||
|
||||
Utils::FileName AndroidBuildApkStep::keystorePath()
|
||||
{
|
||||
return m_keystorePath;
|
||||
}
|
||||
|
||||
QString AndroidBuildApkStep::buildTargetSdk() const
|
||||
{
|
||||
return m_buildTargetSdk;
|
||||
}
|
||||
|
||||
void AndroidBuildApkStep::setBuildTargetSdk(const QString &sdk)
|
||||
{
|
||||
m_buildTargetSdk = sdk;
|
||||
}
|
||||
|
||||
AndroidBuildApkStep::AndroidDeployAction AndroidBuildApkStep::deployAction() const
|
||||
{
|
||||
return m_deployAction;
|
||||
}
|
||||
|
||||
void AndroidBuildApkStep::setDeployAction(AndroidDeployAction deploy)
|
||||
{
|
||||
m_deployAction = deploy;
|
||||
}
|
||||
|
||||
void AndroidBuildApkStep::setKeystorePath(const Utils::FileName &path)
|
||||
{
|
||||
m_keystorePath = path;
|
||||
m_certificatePasswd.clear();
|
||||
m_keystorePasswd.clear();
|
||||
}
|
||||
|
||||
void AndroidBuildApkStep::setKeystorePassword(const QString &pwd)
|
||||
{
|
||||
m_keystorePasswd = pwd;
|
||||
}
|
||||
|
||||
void AndroidBuildApkStep::setCertificateAlias(const QString &alias)
|
||||
{
|
||||
m_certificateAlias = alias;
|
||||
}
|
||||
|
||||
void AndroidBuildApkStep::setCertificatePassword(const QString &pwd)
|
||||
{
|
||||
m_certificatePasswd = pwd;
|
||||
}
|
||||
|
||||
bool AndroidBuildApkStep::signPackage() const
|
||||
{
|
||||
return m_signPackage;
|
||||
}
|
||||
|
||||
void AndroidBuildApkStep::setSignPackage(bool b)
|
||||
{
|
||||
m_signPackage = b;
|
||||
}
|
||||
|
||||
bool AndroidBuildApkStep::openPackageLocation() const
|
||||
{
|
||||
return m_openPackageLocation;
|
||||
}
|
||||
|
||||
void AndroidBuildApkStep::setOpenPackageLocation(bool open)
|
||||
{
|
||||
m_openPackageLocation = open;
|
||||
}
|
||||
|
||||
void AndroidBuildApkStep::setVerboseOutput(bool verbose)
|
||||
{
|
||||
m_verbose = verbose;
|
||||
}
|
||||
|
||||
bool AndroidBuildApkStep::runInGuiThread() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AndroidBuildApkStep::verboseOutput() const
|
||||
{
|
||||
return m_verbose;
|
||||
}
|
||||
|
||||
QAbstractItemModel *AndroidBuildApkStep::keystoreCertificates()
|
||||
{
|
||||
QString rawCerts;
|
||||
QProcess keytoolProc;
|
||||
while (!rawCerts.length() || !m_keystorePasswd.length()) {
|
||||
QStringList params;
|
||||
params << QLatin1String("-list") << QLatin1String("-v") << QLatin1String("-keystore") << m_keystorePath.toUserOutput() << QLatin1String("-storepass");
|
||||
if (!m_keystorePasswd.length())
|
||||
keystorePassword();
|
||||
if (!m_keystorePasswd.length())
|
||||
return 0;
|
||||
params << m_keystorePasswd;
|
||||
params << QLatin1String("-J-Duser.language=en");
|
||||
keytoolProc.start(AndroidConfigurations::currentConfig().keytoolPath().toString(), params);
|
||||
if (!keytoolProc.waitForStarted() || !keytoolProc.waitForFinished()) {
|
||||
QMessageBox::critical(0, tr("Error"),
|
||||
tr("Failed to run keytool."));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (keytoolProc.exitCode()) {
|
||||
QMessageBox::critical(0, tr("Error"),
|
||||
tr("Invalid password."));
|
||||
m_keystorePasswd.clear();
|
||||
}
|
||||
rawCerts = QString::fromLatin1(keytoolProc.readAllStandardOutput());
|
||||
}
|
||||
return new CertificatesModel(rawCerts, this);
|
||||
}
|
||||
|
||||
bool AndroidBuildApkStep::keystorePassword()
|
||||
{
|
||||
m_keystorePasswd.clear();
|
||||
bool ok;
|
||||
QString text = QInputDialog::getText(0, tr("Keystore"),
|
||||
tr("Keystore password:"), QLineEdit::Password,
|
||||
QString(), &ok);
|
||||
if (ok && !text.isEmpty()) {
|
||||
m_keystorePasswd = text;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AndroidBuildApkStep::certificatePassword()
|
||||
{
|
||||
m_certificatePasswd.clear();
|
||||
bool ok;
|
||||
QString text = QInputDialog::getText(0, tr("Certificate"),
|
||||
tr("Certificate password (%1):").arg(m_certificateAlias), QLineEdit::Password,
|
||||
QString(), &ok);
|
||||
if (ok && !text.isEmpty()) {
|
||||
m_certificatePasswd = text;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Android
|
||||
Reference in New Issue
Block a user