Android

4 fev, 2015

Atualizando aplicativos Android-Cordova fora da Google Play Store com AngularJS

Publicidade

Recentemente, tenho trabalhado com aplicativos móveis corporativos. Esses aplicativos não são distribuídos usando qualquer mercado, então eu preciso lidar com o processo de distribuição. Com o Android, você pode compilar seus aplicativos, criar seus arquivos APK e distribuí-los. Você pode enviar os arquivos por e-mail, usar um link para download, enviar o arquivo com bluetooth, ou qualquer outra coisa. Com o iOS é um pouco diferente. Você precisa comprar uma licença da empresa, compilar o aplicativo e distribuir seus arquivos IPA usando padrões da Apple.

OK, mas este artigo não é sobre como distribuir aplicativos fora dos mercados. Este artigo é sobre um grande problema que aparece quando precisamos atualizar nossos aplicativos: como é que o usuário sabe que tem uma nova versão do aplicativo e que precisa fazer o upgrade? Quando trabalhamos dentro da Google Play Store, não precisamos nos preocupar com isso, mas se nós distribuímos nossos aplicativos manualmente precisamos fazer alguma coisa. Podemos enviar notificações push ou e-mails para o usuário para informar sobre a nova versão. Deixe-me mostrar como estou fazendo isso.

Meu problema não é só informar o usuário sobre uma nova versão. Às vezes, eu também preciso garantir que o usuário execute a última versão do app. Imagine um bug crítico (corrigido no último lançamento), mas o usuário não atualiza.

Primeiro, precisamos criar uma página HTML estática, na qual o usuário pode baixar o arquivo APK. Imagine que esta é a URL na qual o usuário pode fazer o download da última versão do app:

http://192.168.1.1:8888/app.apk

Podemos verificar a versão do app em relação ao servidor cada vez que o usuário abre o aplicativo, mas essa verificação significa que a comunicação de rede e é lenta. Precisamos reduzir a comunicação entre o cliente e o servidor para a menor expressão, e somente quando for estritamente necessário. Verificar a versão cada vez pode ser bom para um aplicativo de desktop, mas reduz a experiência do usuário com os aplicativos móveis. Minha abordagem é um pouco diferente. Normalmente usamos a autenticação baseada em tokens dentro de aplicativos móveis. Isso significa que precisamos enviar o nosso token com toda solicitação. Se o enviarmos, podemos também enviar a versão.

Em um app angular, podemos definir a versão e caminho do nosso apk usando um armazenamento valor-chave.

.value('config', {
        version: 4,
        androidAPK: "http://192.168.1.1:8888/app.apk"
    })

Agora precisamos adicionar o parâmetro da versão a cada pedido (que pode criar facilmente um serviço http personalizado para anexar esse parâmetro automaticamente para cada solicitação, na verdade):

$http.get('http://192.168.1.1:8888/api/doSomething', {params: {_version: config.version}})
    .success(function (data) {
        alert("OK");
    })
    .error(function (err, status) {
        switch (status) {
            case 410:
                $state.go('upgrade');
                break;
        }
    });

Podemos criar um backend simples para cuidar da versão e gerar uma exceção HTTP (um erro HTTP 410, por exemplo), caso as versões não coincidam. Aqui você pode ver um exemplo Silex simples:

<?php
 
include __DIR__ . "/../vendor/autoload.php";
 
use Silex\Application;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpException;
 
$app = new Application([
    'debug'   => true,
    'version' => 4,
]);
 
$app->after(function (Request $request, Response $response) {
    $response->headers->set('Access-Control-Allow-Origin', '*');
});
 
$app->get('/api/doSomething', function (Request $request, Application $app) {
    if ($request->get('_version') != $app['version']) {
        throw new HttpException(410, "Wrong version");
    } else {
        return $app->json('hello');
    }
});
 
$app->run();

Como você pode ver, precisamos tomar cuidado com CORS.

Com esse exemplo simples, podemos ver se o usuário tem uma versão errada dentro de cada pedido do servidor. Se as versões não corresponderem, podemos, por exemplo, redirecionar para uma rota específica a fim de informar que o usuário precisa atualizar o aplicativo e fornecer um link para executar a ação.

Com o Android, não podemos criar um link para o arquivo APK. Não funciona. Precisamos fazer o download do APK (usando o plugin FileTransfer) e abrir o arquivo usando o plugin webintent.

O código é muito simples:

var fileTransfer = new FileTransfer();
fileTransfer.download(encodeURI(androidUrl),
    "cdvfile://localhost/temporary/app.apk",
    function (entry) {
        window.plugins.webintent.startActivity({
            action: window.plugins.webintent.ACTION_VIEW,
            url: entry.toURL(),
            type: 'application/vnd.android.package-archive'
        }, function () {
        }, function () {
            alert('Failed to open URL via Android Intent.');
            console.log("Failed to open URL via Android Intent. URL: " + entry.fullPath);
        });
    }, function (error) {
        console.log("download error source " + error.source);
        console.log("download error target " + error.target);
        console.log("upload error code" + error.code);
    }, true);

E, basicamente, isso é tudo. Quando o usuário atualizar o app, ele fecha automaticamente e o usuário precisa abri-lo novamente, mas agora com a versão correta.

***

Artigo traduzido pela Redação iMasters, com autorização do autor. Publicado originalmente em http://gonzalo123.com/2014/07/28/upgrading-android-apps-outside-google-play-store-with-angularjs/