summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBogDan Vatra <bogdan@kdab.com>2016-11-01 17:53:29 +0200
committerAndré Klitzing <aklitzing@gmail.com>2017-02-03 15:07:17 +0000
commiteeb7b8745a4249b515f0981337dabfde16a5c1e7 (patch)
tree7fa4e0589eb364e68b49f3f508a90a8b6631de48
parent7a065401b67d134651fde872d9127fa705dd2e65 (diff)
Use apksigner by default if available to sign the APKs
apksigner is smart enough to know which techique to use to sign the apk based on apk's manifest file. People that really want to use jarsigner they need to pass --jarsigner argument Task-number: QTBUG-56702 Change-Id: I3acd26576c5b0b312d5f2424b1c0a52e48fb920e Reviewed-by: André Klitzing <aklitzing@gmail.com> Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
-rw-r--r--src/androiddeployqt/main.cpp110
1 files changed, 109 insertions, 1 deletions
diff --git a/src/androiddeployqt/main.cpp b/src/androiddeployqt/main.cpp
index c1fd13061..fc1cb940c 100644
--- a/src/androiddeployqt/main.cpp
+++ b/src/androiddeployqt/main.cpp
@@ -102,6 +102,7 @@ struct Options
, internalSf(false)
, sectionsOnly(false)
, protectedAuthenticationPath(false)
+ , jarSigner(false)
, gdbServer(Auto)
, installApk(false)
, uninstallApk(false)
@@ -181,6 +182,7 @@ struct Options
bool internalSf;
bool sectionsOnly;
bool protectedAuthenticationPath;
+ bool jarSigner;
// Gdbserver
TriState gdbServer;
@@ -446,6 +448,8 @@ Options parseOptions()
options.sectionsOnly = true;
} else if (argument.compare(QLatin1String("--protected"), Qt::CaseInsensitive) == 0) {
options.protectedAuthenticationPath = true;
+ } else if (argument.compare(QLatin1String("--jarsigner"), Qt::CaseInsensitive) == 0) {
+ options.jarSigner = true;
} else if (argument.compare(QLatin1String("--no-generated-assets-cache"), Qt::CaseInsensitive) == 0) {
options.generateAssetsFileList = false;
}
@@ -519,6 +523,8 @@ void printHelp()
" --internalsf: Include the .SF file inside the signature block.\n"
" --sectionsonly: Don't compute hash of entire manifest.\n"
" --protected: Keystore has protected authentication path.\n"
+ " --jarsigner: Force jarsigner usage, otherwise apksigner will be\n"
+ " used if available.\n"
" --gdbserver: Adds the gdbserver to the package. By default the gdbserver\n"
" is bundled for debug pacakges.\n"
" --no-gdbserver: Prevents the gdbserver from being added to the package\n"
@@ -2554,7 +2560,7 @@ bool copyGnuStl(Options *options)
return true;
}
-bool signPackage(const Options &options)
+bool jarSignerSignPackage(const Options &options)
{
if (options.verbose)
fprintf(stdout, "Signing Android package.\n");
@@ -2680,6 +2686,108 @@ bool signPackage(const Options &options)
return QFile::remove(apkPath(options, UnsignedAPK));
}
+bool signPackage(const Options &options)
+{
+ QString apksignerTool = options.sdkPath + QLatin1String("/build-tools/") + options.sdkBuildToolsVersion + QLatin1String("/apksigner");
+#if defined(Q_OS_WIN32)
+ apksignerTool += QLatin1String(".bat");
+#endif
+
+ if (options.jarSigner || !QFile::exists(apksignerTool))
+ return jarSignerSignPackage(options);
+
+ // APKs signed with apksigner must not be changed after they're signed, therefore we need to zipalign it before we sign it.
+
+ QString zipAlignTool = options.sdkPath + QLatin1String("/tools/zipalign");
+#if defined(Q_OS_WIN32)
+ zipAlignTool += QLatin1String(".exe");
+#endif
+
+ if (!QFile::exists(zipAlignTool)) {
+ zipAlignTool = options.sdkPath + QLatin1String("/build-tools/") + options.sdkBuildToolsVersion + QLatin1String("/zipalign");
+#if defined(Q_OS_WIN32)
+ zipAlignTool += QLatin1String(".exe");
+#endif
+ if (!QFile::exists(zipAlignTool)) {
+ fprintf(stderr, "zipalign tool not found: %s\n", qPrintable(zipAlignTool));
+ return false;
+ }
+ }
+
+ zipAlignTool = QString::fromLatin1("%1%2 -f 4 %3 %4")
+ .arg(shellQuote(zipAlignTool))
+ .arg(options.verbose ? QString::fromLatin1(" -v") : QString())
+ .arg(apkPath(options, UnsignedAPK))
+ .arg(apkPath(options, SignedAPK));
+
+ FILE *zipAlignCommand = openProcess(zipAlignTool);
+ if (zipAlignCommand == 0) {
+ fprintf(stderr, "Couldn't run zipalign.\n");
+ return false;
+ }
+
+ char buffer[512];
+ while (fgets(buffer, sizeof(buffer), zipAlignCommand) != 0)
+ fprintf(stdout, "%s", buffer);
+
+ int errorCode = pclose(zipAlignCommand);
+ if (errorCode != 0) {
+ fprintf(stderr, "zipalign command failed.\n");
+ if (!options.verbose)
+ fprintf(stderr, " -- Run with --verbose for more information.\n");
+ return false;
+ }
+
+ QString apkSignerCommandLine = QString::fromLatin1("%1 sign --ks %2")
+ .arg(shellQuote(apksignerTool)).arg(shellQuote(options.keyStore));
+
+ if (!options.keyStorePassword.isEmpty())
+ apkSignerCommandLine += QString::fromLatin1(" --ks-pass pass:%1").arg(shellQuote(options.keyStorePassword));
+
+ if (!options.keyStoreAlias.isEmpty())
+ apkSignerCommandLine += QString::fromLatin1(" --ks-key-alias %1").arg(shellQuote(options.keyStoreAlias));
+
+ if (!options.keyPass.isEmpty())
+ apkSignerCommandLine += QString::fromLatin1(" --key-pass pass:%1").arg(shellQuote(options.keyPass));
+
+ if (options.verbose)
+ apkSignerCommandLine += QLatin1String(" --verbose");
+
+ apkSignerCommandLine += QString::fromLatin1(" %1")
+ .arg(apkPath(options, SignedAPK));
+
+ auto apkSignerRunner = [&] {
+ FILE *apkSignerCommand = openProcess(apkSignerCommandLine);
+ if (apkSignerCommand == 0) {
+ fprintf(stderr, "Couldn't run apksigner.\n");
+ return false;
+ }
+
+ char buffer[512];
+ while (fgets(buffer, sizeof(buffer), apkSignerCommand) != 0)
+ fprintf(stdout, "%s", buffer);
+
+ errorCode = pclose(apkSignerCommand);
+ if (errorCode != 0) {
+ fprintf(stderr, "apksigner command failed.\n");
+ if (!options.verbose)
+ fprintf(stderr, " -- Run with --verbose for more information.\n");
+ return false;
+ }
+ return true;
+ };
+
+ // Sign the package
+ if (!apkSignerRunner())
+ return false;
+
+ apkSignerCommandLine = QString::fromLatin1("%1 verify --verbose %2")
+ .arg(shellQuote(apksignerTool)).arg(apkPath(options, SignedAPK));
+
+ // Verify the package and remove the unsigned apk
+ return apkSignerRunner() && QFile::remove(apkPath(options, UnsignedAPK));
+}
+
bool copyGdbServer(const Options &options)
{
if (options.verbose)