Android: Fix signing of APKs that are generated when an AAB is also built

To simplify matters, this removes the support for signing APKs with
just jarsigner. apksigner is always used for APKs, and jarsigner is
used for AABs. I consider that to be just fine, you _have_ to start
using apksigner eventually, and the time for that is long past.

Pick-to: 6.4 6.2 5.15
Task-number: QTBUG-91255
Change-Id: I211ae796db0f2619265deb1f30ab3cc5d1ecfbc9
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
This commit is contained in:
Ville Voutilainen 2022-10-26 13:48:37 +03:00
parent 528b03d6b6
commit b82c5f9b7f

View File

@ -93,7 +93,6 @@ struct Options
, internalSf(false)
, sectionsOnly(false)
, protectedAuthenticationPath(false)
, jarSigner(false)
, installApk(false)
, uninstallApk(false)
, qmlImportScannerBinaryPath()
@ -191,7 +190,6 @@ struct Options
bool internalSf;
bool sectionsOnly;
bool protectedAuthenticationPath;
bool jarSigner;
QString apkPath;
// Installation information
@ -366,7 +364,6 @@ Options parseOptions()
} else if (argument.compare("--aab"_L1, Qt::CaseInsensitive) == 0) {
options.buildAAB = true;
options.build = true;
options.jarSigner = true;
} else if (!options.buildAAB && argument.compare("--no-build"_L1, Qt::CaseInsensitive) == 0) {
options.build = false;
} else if (argument.compare("--install"_L1, Qt::CaseInsensitive) == 0) {
@ -501,8 +498,6 @@ Options parseOptions()
options.sectionsOnly = true;
} else if (argument.compare("--protected"_L1, Qt::CaseInsensitive) == 0) {
options.protectedAuthenticationPath = true;
} else if (argument.compare("--jarsigner"_L1, Qt::CaseInsensitive) == 0) {
options.jarSigner = true;
} else if (argument.compare("--aux-mode"_L1, Qt::CaseInsensitive) == 0) {
options.auxMode = true;
} else if (argument.compare("--qml-importscanner-binary"_L1, Qt::CaseInsensitive) == 0) {
@ -594,8 +589,7 @@ 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"
" --jarsigner: Deprecated, ignored.\n"
"\n"
" NOTE: To conceal the keystore information, the environment variables\n"
" QT_ANDROID_KEYSTORE_PATH, and QT_ANDROID_KEYSTORE_ALIAS are used to\n"
@ -2846,7 +2840,7 @@ static QString zipalignPath(const Options &options, bool *ok)
return zipAlignTool;
}
bool jarSignerSignPackage(const Options &options)
bool signAAB(const Options &options)
{
if (options.verbose)
fprintf(stdout, "Signing Android package.\n");
@ -2900,7 +2894,7 @@ bool jarSignerSignPackage(const Options &options)
if (options.protectedAuthenticationPath)
jarSignerTool += " -protected"_L1;
auto signPackage = [&](const QString &file) {
auto jarSignPackage = [&](const QString &file) {
fprintf(stdout, "Signing file %s\n", qPrintable(file));
fflush(stdout);
QString command = jarSignerTool + " %1 %2"_L1.arg(shellQuote(file))
@ -2928,49 +2922,15 @@ bool jarSignerSignPackage(const Options &options)
return true;
};
if (!signPackage(packagePath(options, UnsignedAPK)))
if (options.buildAAB && !jarSignPackage(packagePath(options, AAB)))
return false;
if (options.buildAAB && !signPackage(packagePath(options, AAB)))
return false;
bool ok;
QString zipAlignTool = zipalignPath(options, &ok);
if (!ok)
return false;
zipAlignTool = "%1%2 -f 4 %3 %4"_L1.arg(shellQuote(zipAlignTool),
options.verbose ? " -v"_L1 : QLatin1StringView(),
shellQuote(packagePath(options, UnsignedAPK)),
shellQuote(packagePath(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;
}
return QFile::remove(packagePath(options, UnsignedAPK));
return true;
}
bool signPackage(const Options &options)
{
const QString apksignerTool = batSuffixAppended(options.sdkPath + "/build-tools/"_L1 +
options.sdkBuildToolsVersion + "/apksigner"_L1);
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.
@ -3075,6 +3035,9 @@ bool signPackage(const Options &options)
"%1 verify --verbose %2"_L1
.arg(shellQuote(apksignerTool), shellQuote(packagePath(options, SignedAPK)));
if (options.buildAAB && !signAAB(options))
return false;
// Verify the package and remove the unsigned apk
return apkSignerRunner(apkVerifyCommand, true) && QFile::remove(packagePath(options, UnsignedAPK));
}