Skip to content

Instantly share code, notes, and snippets.

@RaschidJFR
Last active April 13, 2019 23:59
Show Gist options
  • Save RaschidJFR/8e2f3f7d79dc9c100e5f1c81a8e2c5e7 to your computer and use it in GitHub Desktop.
Save RaschidJFR/8e2f3f7d79dc9c100e5f1c81a8e2c5e7 to your computer and use it in GitHub Desktop.
Automatically sign and align apk built with Ionic v3
#!/usr/bin/env node
// ## Automatically sign and align apk ##
// Just run this script `$ node sign_apk.js`
const CONFIG_FILE_NAME = 'sign-apk.json';
const configFileStruct = {
"keystorePath": "relative/path/to/file.keystore",
"zipalignPath": "C:/Program Files (x86)/Android/android-sdk/build-tools/26.0.2/zipalign",
"apkPath": "C:/your-ionic-project-root/platforms/android/build/outputs/apk/android-release-unsigned.apk",
"alias": "keystore_alias",
"password": "keystore_password",
"output": "C:/your-ionic-project-root/platforms/android/build/outputs/apk/your_apk.apk"
}
// Load configuration
let configFile = {};
const configFilePath = `${require.main.paths[0].replace('node_modules', '')}\\${CONFIG_FILE_NAME}`;
try {
configFile = require(configFilePath)
} catch (e) {
const json = JSON.stringify(configFileStruct, null, 2);
const msg = `The file '${configFilePath}' file has not been found.\nPlease create it with the following structure:\n\n${json}\n`;
console.error(e);
throw msg;
}
const KEYSTORE_PATH = configFile.keystorePath;
const ZIPALIGN_PATH = configFile.zipalignPath;
const APK_PATH = configFile.apkPath;
const ALIAS = configFile.alias;
const PWD = configFile.password;
const OUTPUT_PATH = configFile.output;
// ===================================
startJob();
function signAndAlignApk(output) {
const { spawn } = require('child_process');
let command = 'jarsigner';
let args = ['-verbose', '-sigalg', 'SHA1withRSA', '-digestalg', 'SHA1', '-keystore', KEYSTORE_PATH, APK_PATH, ALIAS];
console.log('Sign apk: %s', 'jarsigner ' + args.join(' '));
const p = APK_PATH.split('/');
p.pop();
let child = spawn(command, args);
// Enter password
child.stdin.setEncoding('utf-8');
child.stdin.write(PWD + "\n");
child.stdin.end();
child.stdout.on('data', (data) => {
console.log(`SignApk stdout: ${data}`);
});
child.stderr.on('data', (data) => {
console.log(`SignApk stderr: ${data}`);
});
child.on('close', (code) => {
console.log(`Apk Signed`);
alignApk(output);
});
}
function alignApk(output) {
const { exec } = require('child_process');
let command = '"' + ZIPALIGN_PATH + '" -v 4 "' + APK_PATH + '" "' + output + '"';
console.log("Align apk: %s\n", command);
exec(command,
(err, stdout, stderr) => {
if (err) {
console.error(err);
return;
}
console.log("stdout");
console.log("Apk signed and aligned!");
});
}
function getVersion(callback) {
console.log('Get version:');
try {
var fs = require('fs');
var xml2js = require('xml2js');
// Read config.xml
fs.readFile('config.xml', 'utf8', function (err, data) {
if (err) {
console.log(err);
callback(null);
return;
}
// Get XML
var xml = data;
// Parse XML to JS Obj
xml2js.parseString(xml, function (err, result) {
if (err) {
console.log(err);
callback(null);
return;
}
// Get version inside widget attributes or create it
var obj = result;
var version = obj['widget']['$']['version'];
console.log(version);
callback(version);
return;
})
})
} catch (e) {
console.warn("Couldn't read version from config.xml file. Make sure you've node installed 'fs' and 'xml2js' if you wish to also add version number to your ouput filename ");
callback(null);
}
}
function startJob() {
getVersion(v => {
let output = OUTPUT_PATH;
if (v) output = output.replace('.apk', '') + '_r' + v + '.apk';
signAndAlignApk(output);
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment