Android

4 fev, 2015

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

100 visualizações
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/