Gulp + Ionic: Automatizando Release no Android

Todos que já finalizaram um projeto em ionic, tiveram que passar pelo “Publishing your app” e quando você tem que lançar suas atualizações constantemente fica chato ter que ficar repetindo esses procedimentos, por isso resolvi fazer esse post para mostrar como vocês podem automatizar não só esse, como qualquer outro processo usando o Gulp + Ionic.

Gulp

O Gulp é um kit de ferramentas para automatizar tarefas massantes/demoradas no fluxo de trabalho do desenvolvimento, com ele é possível automatizar essas tarefas de maneira simples e confiável.

Preparando o ambiente

[wp_ad_camp_3]

Primeiro você deve instalar em seu projeto ionic as dev-dependencies abaixo:


npm install --save-dev gulp run-sequence shelljs

Criando sua KeyStore

A keystore é única, ela é quem garante que você e somente você consiga fornecer uma atualização segura para seus usuários.

Como a KeyStore é gerada uma única vez, não vejo motivos para automatizar no processo do Gulp. A Keystore é o segundo passo do “Publishing your app“. Entre no diretório de sua aplicação e na mesma pasta de seu package.json, execute o comando abaixo informando os seus dados e criando uma senha que você vai usar depois na nossa tarefa do Gulp. Mantenha a mesma senha, tanto para o keystore quanto para o alias.

keytool -genkey -v -keystore chave-distribuicao.keystore -alias ID_DO_SEU_CONFIG_XML -keyalg RSA -keysize 2048 -validity 10000

Note que no comando acima tem a informação ID_DO_SEU_CONFIG_XML essa informação deve ser substituída pelo id que você colocou no seu config.xml, o padrão para os id do config.xml é br.com.seuappsite.app.

Package.Json

[wp_ad_camp_2]

Agora vamos editar nosso package.json, e vamos adicionar um novo valor dentro dos scripts. Crie uma nova chave com o nome “build:release” com o valor “gulp release“.

Gulpfile

Agora precisamos criar um arquivo chamado gulpfile.js no mesmo diretório do seu package.json ele é quem vai fazer todo o trabalho de executar o “ionic cordova build –prod –release”, e os outros passos para assinar e alinhar o seu aplicativo. E o resultado final vai ser o seu APK pronto para distribuição na pasta dist.

Conteúdo do Gulpfile.js:

const gulp = require('gulp'),
      fs = require('fs'),
      path = require('path'),
      runSequence = require('run-sequence'),
      shelljs = require('shelljs'),
      config = {
           pwd: "SENHA_ESCOLHIDA_NA_CHAVE",
           alias: "ID_DO_SEU_CONFIG_XML",
           keystore: "chave-distribuicao.keystore"
      };

gulp.task('release', function () {

    const apks = fs.readdirSync('./dist');
    for(apk of apks) {
        // verificando apks não assinados
        if(apk.indexOf('.apk') > -1) {
            fs.unlinkSync(`./dist/${apk}`);
        }
    }

    if(config.pwd === 'keystore_password' || config.pwd === '') {
        console.error('Edite o gulpfile.js e informe a senha de sua keystore.');
        return shelljs.exit(1);
    }

    runSequence('compilar-release', 'assinar-apk', 'alinhar-apk', function () {

    });
});

/**
 * Compilo com a flag --prod e --release no ionic
 */
gulp.task('compilar-release', function () {
    const out = shelljs.exec('ionic cordova build android --release --prod --no-interactive', {silent:true}).stdout;
    const buildReturn = out.split('Built the following apk(s):');

    // verifico se o build deu certo
    if(buildReturn.length > 1) {
        const apks = buildReturn[1].replace(/\r/, '').replace(/\t/, '').split('\n'),
              realApks = [];
        for(apk of apks) {
            // recupero os apks releases gerados
            if(apk.indexOf('release-unsigned.apk') > -1) {
                realApks.push(apk);
            }
        }

        // verificando se a pasta dist existe.
        if(!fs.existsSync('./dist')) {
            fs.mkdirSync('./dist');
        }

        // movendo apks para a dist
        for(apk of realApks) {
            let splitter = "/";
            if(apk.indexOf("\\") > -1) {
                splitter = "\\";
            }

            let fileName = apk.split(splitter);
            fileName = fileName[fileName.length - 1];

            fs.copyFileSync(apk, './dist/' + fileName);
            fs.unlinkSync(apk);
        }
    } else {
        // erro no build
        shelljs.exit(1);
    }
});

/**
 * Assina o APK com release
 */
gulp.task('assinar-apk', function () {
    const apks = fs.readdirSync('./dist');
    for(apk of apks) {
        // verificando apks não assinados
        if(apk.indexOf('release-unsigned.apk') > -1) {
            let signCommand = `jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ${config.keystore} -storepass ${config.pwd} -keypass ${config.pwd} ./dist/${apk} ${config.alias}`;
            const signCommandResult = shelljs.exec(signCommand, {silent:true}).stdout;
            console.log(signCommandResult);
        }
    }
});

/**
 * Assina o APK com release
 */
gulp.task('alinhar-apk', function () {
    let bdtools = process.env.ANDROID_HOME + path.sep + 'build-tools' + path.sep + fs.readdirSync(process.env.ANDROID_HOME + path.sep + 'build-tools')[0] + path.sep;
    console.log(bdtools);
    const apks = fs.readdirSync('./dist');
    for(apk of apks) {
        // verificando apks não assinados
        if(apk.indexOf('release-unsigned.apk') > -1) {
            let alignCommand = `"${bdtools}zipalign" -v 4 ./dist/${apk} ./dist/${apk.replace('-release-unsigned.apk', '')}.apk`;
            const alignCommandResult = shelljs.exec(alignCommand, {silent:true}).stdout;
            fs.unlinkSync(`./dist/${apk}`);
            console.log(alignCommandResult);
        }
    }
});

Testando

[wp_ad_camp_1]

Agora para gerar e assinar seus apks basta você executar o comando abaixo:


npm run build:release

Obrigado pessoal, espero que o conteúdo seja útil para vocês.

[27/11/2018] Edição: Adicionei na linha 32 do Gulpfile.js o parâmetro –no-interactive para corrigir o problema de travar a compilação pelo fato da CLI do ionic perguntar se você deseja fazer a atualização.

Comments

    1. Post
      Author
    1. Post
      Author
  1. CAIO VINICIUS RODRIGUES

    root@caio-Aspire-E1-572:/home/caio/Documentos/ionic/codin-mobile# sudo npm run build:release
    npm ERR! missing script: build:release

    npm ERR! A complete log of this run can be found in:
    npm ERR! /root/.npm/_logs/2018-11-09T13_05_33_249Z-debug.log
    root@caio-Aspire-E1-572:/home/caio/Documentos/ionic/codin-mobile# vi /root/.npm/_logs/2018-11-09T13_05_33_249Z-debug.log
    root@caio-Aspire-E1-572:/home/caio/Documentos/ionic/codin-mobile# sudo npm run build:release
    npm ERR! missing script: build:release

    Fiz os passos e refiz e so fica nesse erro

    1. Post
      Author
      Hiago Souza

      Olá Caio, tudo bem?

      Esse erro ocorre porque ele não encontrou o build:release em seu arquivo package.json. Dentro da chave “scripts” no package.json deve ser adicionado uma nova chave com o nome “build:release” tendo como valor “gulp release”. Fazendo isso acredito que vá funcionar.

      Caso já tenha feito isso, envie o conteúdo do seu package.json aqui e se possível tente executar o comando sem o sudo. Dê as permissões necessárias para seu usuário no linux que deve funcionar 😉

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *