@bubblewrap/cli
Version:
CLI tool to Generate TWA projects from a Web Manifest
157 lines (156 loc) • 7.71 kB
JavaScript
"use strict";
/*
* Copyright 2019 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.build = void 0;
const core_1 = require("@bubblewrap/core");
const path = require("path");
const fs = require("fs");
const strings_1 = require("../strings");
const Prompt_1 = require("../Prompt");
const validator_1 = require("@bubblewrap/validator");
const pwaValidationHelper_1 = require("../pwaValidationHelper");
const inputHelpers_1 = require("../inputHelpers");
class Build {
constructor(args, androidSdkTools, keyTool, gradleWrapper, jarSigner, log = new core_1.ConsoleLog('build'), prompt = new Prompt_1.InquirerPrompt()) {
this.args = args;
this.androidSdkTools = androidSdkTools;
this.keyTool = keyTool;
this.gradleWrapper = gradleWrapper;
this.jarSigner = jarSigner;
this.log = log;
this.prompt = prompt;
}
/**
* Checks if the keystore password and the key password are part of the environment prompts the
* user for a password otherwise.
*
* @returns {Promise<SigningKeyPasswords} the password information collected from enviromental
* variables or user input.
*/
async getPasswords(signingKeyInfo) {
// Check if passwords are set as environment variables.
const envKeystorePass = process.env['BUBBLEWRAP_KEYSTORE_PASSWORD'];
const envKeyPass = process.env['BUBBLEWRAP_KEY_PASSWORD'];
if (envKeyPass !== undefined && envKeystorePass !== undefined) {
this.prompt.printMessage(strings_1.enUS.messageUsingPasswordsFromEnv);
return {
keystorePassword: envKeystorePass,
keyPassword: envKeyPass,
};
}
// Ask user for the keystore password
this.prompt.printMessage(strings_1.enUS.messageEnterPasswords(signingKeyInfo.path, signingKeyInfo.alias));
const keystorePassword = await this.prompt.promptPassword(strings_1.enUS.promptKeystorePassword, inputHelpers_1.createValidateString(6));
const keyPassword = await this.prompt.promptPassword(strings_1.enUS.promptKeyPassword, inputHelpers_1.createValidateString(6));
return {
keystorePassword: keystorePassword,
keyPassword: keyPassword,
};
}
async runValidation() {
try {
const manifestFile = path.join(process.cwd(), 'twa-manifest.json');
const twaManifest = await core_1.TwaManifest.fromFile(manifestFile);
const pwaValidationResult = await validator_1.PwaValidator.validate(new URL(twaManifest.startUrl, twaManifest.webManifestUrl));
return core_1.Result.ok(pwaValidationResult);
}
catch (e) {
return core_1.Result.error(e);
}
}
async generateAssetLinks(twaManifest, passwords) {
try {
const digitalAssetLinksFile = './assetlinks.json';
const keyInfo = await this.keyTool.keyInfo({
path: twaManifest.signingKey.path,
alias: twaManifest.signingKey.alias,
keypassword: passwords.keyPassword,
password: passwords.keystorePassword,
});
const sha256Fingerprint = keyInfo.fingerprints.get('SHA256');
if (!sha256Fingerprint) {
this.prompt.printMessage(strings_1.enUS.messageSha256FingerprintNotFound);
return;
}
const digitalAssetLinks = core_1.DigitalAssetLinks.generateAssetLinks(twaManifest.packageId, sha256Fingerprint);
await fs.promises.writeFile(digitalAssetLinksFile, digitalAssetLinks);
this.prompt.printMessage(strings_1.enUS.messageDigitalAssetLinksSuccess(digitalAssetLinksFile));
}
catch (e) {
this.prompt.printMessage(strings_1.enUS.errorAssetLinksGeneration);
}
}
async buildApk(signingKey, passwords) {
await this.gradleWrapper.assembleRelease();
await this.androidSdkTools.zipalign('./app/build/outputs/apk/release/app-release-unsigned.apk', // input file
'./app-release-unsigned-aligned.apk');
const outputFile = './app-release-signed.apk';
await this.androidSdkTools.apksigner(signingKey.path, passwords.keystorePassword, signingKey.alias, passwords.keyPassword, './app-release-unsigned-aligned.apk', // input file path
outputFile);
this.prompt.printMessage(strings_1.enUS.messageApkSucess(outputFile));
}
async buildAppBundle(signingKey, passwords) {
await this.gradleWrapper.bundleRelease();
const inputFile = 'app/build/outputs/bundle/release/app-release.aab';
const outputFile = './app-release-bundle.aab';
await this.jarSigner.sign(signingKey, passwords.keystorePassword, passwords.keyPassword, inputFile, outputFile);
this.prompt.printMessage(strings_1.enUS.messageAppBundleSuccess(outputFile));
}
async build() {
if (!await this.androidSdkTools.checkBuildTools()) {
this.prompt.printMessage(strings_1.enUS.messageInstallingBuildTools);
await this.androidSdkTools.installBuildTools();
}
let validationPromise = null;
if (!this.args.skipPwaValidation) {
validationPromise = this.runValidation();
}
const twaManifest = await core_1.TwaManifest.fromFile('./twa-manifest.json');
const passwords = await this.getPasswords(twaManifest.signingKey);
// Builds the Android Studio Project
this.prompt.printMessage(strings_1.enUS.messageBuildingApp);
await this.buildApk(twaManifest.signingKey, passwords);
await this.buildAppBundle(twaManifest.signingKey, passwords);
await this.generateAssetLinks(twaManifest, passwords);
if (validationPromise !== null) {
const result = await validationPromise;
if (result.isOk()) {
const pwaValidationResult = result.unwrap();
pwaValidationHelper_1.printValidationResult(pwaValidationResult, this.log);
if (pwaValidationResult.status === 'FAIL') {
this.prompt.printMessage(strings_1.enUS.warnPwaFailedQuality);
}
}
else {
const e = result.unwrapError();
this.log.debug(e.message);
this.prompt.printMessage(strings_1.enUS.errorFailedToRunQualityCriteria);
}
}
return true;
}
}
async function build(config, args, log = new core_1.ConsoleLog('build'), prompt = new Prompt_1.InquirerPrompt()) {
const jdkHelper = new core_1.JdkHelper(process, config);
const androidSdkTools = await core_1.AndroidSdkTools.create(process, config, jdkHelper, log);
const keyTool = new core_1.KeyTool(jdkHelper, log);
const gradleWrapper = new core_1.GradleWrapper(process, androidSdkTools);
const jarSigner = new core_1.JarSigner(jdkHelper);
const build = new Build(args, androidSdkTools, keyTool, gradleWrapper, jarSigner, log, prompt);
return build.build();
}
exports.build = build;