Статьи

Обновление приложений Cordova-Android вне Google Play Store с AngularJS

В последние месяцы я работал с корпоративными мобильными приложениями. Эти приложения не распространяются на каком-либо рынке, поэтому мне нужно справиться с процессом распространения. С Android вы можете компилировать свои приложения, создавать APK-файлы и распространять их. Вы можете отправлять файлы по электронной почте, использовать ссылку для скачивания, отправить файл через Bluetooth или что-то еще. С iOS все немного по-другому. Вам необходимо приобрести одну лицензию Enterprise, скомпилировать приложение и распространять файлы IPA, используя стандарты Apple.

Хорошо, но этот пост не о том, как распространять приложения за пределами рынков. Этот пост посвящен одной большой проблеме, которая возникает, когда нам нужно обновить наши приложения. Как пользователь узнает, что есть новая версия приложения, и ему нужно обновить? Когда мы работаем в Google Play Store, нам не нужно об этом беспокоиться, но если мы распространяем наши приложения вручную, нам нужно что-то делать. Мы можем отправить push-уведомления или электронное письмо пользователю, чтобы сообщить о новой версии. Позвольте мне показать вам, как я это делаю.

Моя проблема не только в том, чтобы сообщить пользователю о новой версии. Иногда мне также нужно убедиться, что пользователь запускает последнюю версию приложения. Представьте себе критическую ошибку (решенную в последнем выпуске), но пользователь не обновляется.

Сначала нам нужно создать статическую HTML-страницу, где пользователь может скачать APK-файл. Представьте, что это URL, по которому пользователь может загрузить последнюю версию приложения:

http://192.168.1.1:8888/app.apk

Мы можем проверять версию приложения на сервере каждый раз, когда пользователь открывает приложение, но эта проверка означает связь по сети, и она медленная. Нам нужно уменьшить связь между клиентом и сервером до минимального выражения и только тогда, когда это строго необходимо. Проверка версии каждый раз может быть полезной в настольном приложении, но это снижает удобство работы с мобильными приложениями. Мой подход немного отличается. Обычно мы используем аутентификацию на основе токенов в мобильных приложениях. Это означает, что мы должны отправить наш токен со всеми запросами. Если мы отправляем токен, мы также можем отправить версию.

В угловом приложении мы можем определить версию и путь нашего apk, используя хранилище значений ключей.

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

Теперь нам нужно добавить параметр версии к каждому запросу (мы можем легко создать пользовательский http-сервис для автоматического добавления этого параметра к каждому запросу)

$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;
        }
    });

Мы можем создать простой бэкэнд, чтобы заботиться о версии и генерировать исключение HTTP (например, одну ошибку 410 HTTP), если версии не совпадают. Здесь вы можете увидеть простой пример Silex:

<?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();

Как видите, нам нужно позаботиться о CORS

С помощью этого простого примера мы можем понять, имеет ли пользователь неверную версию в каждом запросе к серверу. Если версия не совпадает, мы можем, например, перенаправить на определенный маршрут, чтобы сообщить, что пользователь должен обновить приложение, и предоставить ссылку для выполнения действия.

С Android мы не можем создать ссылку на файл APK. Не работает Нам нужно скачать APK (с помощью плагина FileTransfer ) и открыть файл с помощью плагина webintent .

Код очень прост:

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);

И в основном это все. Когда пользователь самостоятельно обновляет приложение, оно закрывается автоматически, и ему нужно открыть его снова, но теперь с правильной версией.