Статьи

Кроссплатформенное хранилище и синхронизация с Ionic Framework, Couchbase и PouchDB

Ionic Framework по-прежнему является одним из лидеров в разработке гибридных мобильных приложений. Он позволяет создавать приложения для Android и iOS, используя только HTML, JavaScript и CSS.

Ранее я писал о том, как использовать Couchbase в мобильном приложении Android и iOS для Ionic Framework , но он использовал Couchbase Lite в качестве встроенной базы данных NoSQL. На этот раз мы рассмотрим замену Couchbase Lite на PouchDB. Должны ли вы использовать один метод над другим? Нет, все сводится к предпочтениям.

Если вы еще не видели мой пост, касающийся PouchDB и AngularJS с Couchbase , я рекомендую вам взглянуть, так как в этом руководстве будут использоваться многие из тех же концепций и кода.

Что нам нужно

Есть несколько требований к приложению, которое мы собираемся создать. Мы увидим, как получить их по пути, но вот вкус, чтобы вы знали, во что вы ввязываетесь.

  • Couchbase Sync Gateway
  • PouchDB 4
  • Ionic Framework 1

Получение Couchbase Sync Gateway

Этот проект потребует Couchbase Sync Gateway для успеха. Если вы незнакомы, Couchbase Sync Gateway — это посредническая служба, которая обрабатывает данные между локальным приложением (вашим приложением Ionic Framework) и сервером Couchbase. В этом примере мы не будем использовать Couchbase Server, поэтому Sync Gateway будет выступать в качестве нашего решения для хранения в памяти в облаке.

Шлюз Couchbase Sync Gateway можно найти в разделе загрузок Couchbase .

Создание нашего проекта Ionic Framework

Прежде чем идти дальше, стоит отметить, что если вы не используете Mac, вы не можете добавлять и собирать для платформы iOS. Компьютеры под управлением Windows, Mac и Linux могут собираться для Android, но только iOS может собирать для iOS.

Из командной строки (Windows) или терминала (Mac и Linux) выполните следующую команду, чтобы создать новый проект Ionic Framework:


ionic start PouchProject blank
cd PouchProject
ionic platform add android
ionic platform add ios

Наш пустой шаблонный проект теперь готов к работе.

Включая зависимости

Если вы еще этого не сделали, загрузите PouchDB 4 и запишите файл min.js, так как мы будем использовать его в проекте. Скопируйте файл PouchDB min.js в каталог вашего проекта Ionic www / js .

Когда файл на месте, откройте файл вашего проекта www / index.html и включите в него следующее:


<script src="js/pouchdb-4.0.3.min.js"></script>

Эта строка сценария должна отображаться над строкой включения app.js, и информация о версии должна соответствовать информации о вашем файле, а не о версии, которую я включил здесь.

Модификация индексного файла

Прежде чем мы перейдем к коду AngularJS, нам нужно сделать окончательную ревизию в файле проекта www / index.html . Откройте его и замените теги <body> следующим:


<body ng-app="starter">
    <ion-pane>
        <ion-nav-bar class="bar-stable"></ion-nav-bar>
        <ion-nav-view></ion-nav-view>
    </ion-pane>
</body>

Поскольку мы используем UI-маршрутизатор AngularJS, который поставляется с Ionic Framework, нам нужен только базовый файл www / index.html .

Создание нашего сервиса PouchDB AngularJS

Перед тем, как мы начнем использовать PouchDB, нам нужно создать для него оболочку, чтобы она прекрасно подходила для AngularJS и Ionic Framework. Из коробки PouchDB — это ванильная библиотека JavaScript, поэтому ее не обязательно проще всего использовать, когда дело доходит до AngularJS.

В файле www / js / app.js вашего проекта включите следующий сервисный код:


.service("$pouchDB", ["$rootScope", "$q", function($rootScope, $q) {

    var database;
    var changeListener;

    this.setDatabase = function(databaseName) {
        database = new PouchDB(databaseName);
    }

    this.startListening = function() {
        changeListener = database.changes({
            live: true,
            include_docs: true
        }).on("change", function(change) {
            if(!change.deleted) {
                $rootScope.$broadcast("$pouchDB:change", change);
            } else {
                $rootScope.$broadcast("$pouchDB:delete", change);
            }
        });
    }

    this.stopListening = function() {
        changeListener.cancel();
    }

    this.sync = function(remoteDatabase) {
        database.sync(remoteDatabase, {live: true, retry: true});
    }

    this.save = function(jsonDocument) {
        var deferred = $q.defer();
        if(!jsonDocument._id) {
            database.post(jsonDocument).then(function(response) {
                deferred.resolve(response);
            }).catch(function(error) {
                deferred.reject(error);
            });
        } else {
            database.put(jsonDocument).then(function(response) {
                deferred.resolve(response);
            }).catch(function(error) {
                deferred.reject(error);
            });
        }
        return deferred.promise;
    }

    this.delete = function(documentId, documentRevision) {
        return database.remove(documentId, documentRevision);
    }

    this.get = function(documentId) {
        return database.get(documentId);
    }

    this.destroy = function() {
        database.destroy();
    }

}])

Вы можете подумать, что код выглядит знакомым. Ну, это именно тот код, который я использовал в предыдущем примере PouchDB для AngularJS . Теперь мы можем легко использовать PouchDB в нашем проекте.

Создание локальной базы данных и начало синхронизации

Цель здесь — создать локальную базу данных при запуске нашего приложения (если оно еще не существует), а затем начать синхронизацию с Couchbase Sync Gateway. Это можно сделать в функции run () AngularJS нашего файла www / js / app.js :


.run(function($ionicPlatform, $pouchDB) {
    $ionicPlatform.ready(function() {
        if(window.cordova && window.cordova.plugins.Keyboard) {
            cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
        }
        if(window.StatusBar) {
            StatusBar.styleDefault();
        }
    });
    $pouchDB.setDatabase("nraboy-test");
    if(ionic.Platform.isAndroid()) {
        $pouchDB.sync("http://192.168.57.1:4984/test-database");
    } else {
        $pouchDB.sync("http://localhost:4984/test-database");
    }
})

IP-адреса, которые я использовал, могут отличаться для вас с точки зрения симуляторов, но для производства они, вероятно, будут соответствовать как для iOS, так и для Android.

Разработка контроллера для ваших представлений

Мы еще не создали наши представления, но давайте продолжим и создадим для них логику контроллера. Откройте файл вашего проекта www / js / app.js и включите следующий контроллер:


.controller("MainController", function($scope, $rootScope, $state, $stateParams, $ionicHistory, $pouchDB) {

    $scope.items = {};

    $scope.save = function(firstname, lastname, email) { }

    $scope.delete = function(id, rev) { }

    $scope.back = function() { }

})

На данный момент у нас есть основной контроллер. Мы знаем, что будем сохранять и удалять элементы, поэтому мы определили функцию для таких задач. У нас также есть функция с именем back () , которая вставляет элемент (возвращается) в стек истории.

Давайте начнем с функции back () . Он должен содержать следующий код:


$scope.back = function() {
    $ionicHistory.goBack();
}

Когда дело доходит до удаления элементов из базы данных, нам нужно предоставить конкретный идентификатор документа для удаления, а также конкретную ревизию, которую мы хотим удалить. Все это будет передано из представлений, но логика будет следующей:


$scope.delete = function(id, rev) {
    $pouchDB.delete(id, rev);
}

Функция delete (id, rev) вызывает созданный нами сервис PouchDB.

Это оставляет нас с функцией save () . Исходя из простоты нашего приложения, мы сохраняем только три свойства данных, но их можно легко изменить, если потребуется. Внутри вашего контроллера сделайте функцию save () примерно так:


$scope.save = function(firstname, lastname, email) {
    var jsonDocument = {
        "firstname": firstname,
        "lastname": lastname,
        "email": email
    };
    if($stateParams.documentId) {
        jsonDocument["_id"] = $stateParams.documentId;
        jsonDocument["_rev"] = $stateParams.documentRevision;
    }
    $pouchDB.save(jsonDocument).then(function(response) {
        $state.go("list");
    }, function(error) {
        console.log("ERROR -> " + error);
    });
}

Эта функция делает две вещи. Он подготовит вставку или подготовит обновление, если будут доступны идентификатор документа и редакция документа.

Мы еще не совсем закончили. Несмотря на то, что мы завершили все наши функции, нам все равно нужно обрабатывать изменения. Когда мы вызываем $ pouchDB.startListening (); в нашем контроллере наш сервис PouchDB начнет использовать трансляцию AngularJS $ . Во время вещания мы можем прослушивать эти передачи, используя что-то вроде:


$rootScope.$on("$pouchDB:change", function(event, data) {
    $scope.items[data.doc._id] = data.doc;
    $scope.$apply();
});

$rootScope.$on("$pouchDB:delete", function(event, data) {
    delete $scope.items[data.doc._id];
    $scope.$apply();
});

Наша логика контроллера представления теперь хороша!

Определение ваших ионных рамочных представлений

Последняя часть нашего файла www / js / app.js предназначена для определения наших представлений. Это делается в функции config () AngularJS следующим образом:


.config(function($stateProvider, $urlRouterProvider) {
    $stateProvider
        .state("list", {
            "url": "/list",
            "templateUrl": "templates/list.html",
            "controller": "MainController"
        })
        .state("item", {
            "url": "/item/:documentId/:documentRevision",
            "templateUrl": "templates/item.html",
            "controller": "MainController"
        });
    $urlRouterProvider.otherwise("list");
})

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

Вся наша логика AngularJS завершена. Мы инициализировали нашу базу данных, начали синхронизацию, определили наши представления и запланировали взаимодействие с нашими представлениями.

Создание представления списка

Здесь мы определим, как данные представлены в списке. В файле вашего проекта www / templates / list.html добавьте следующий код:


<ion-view title="Couchbase with PouchDB">
    <ion-nav-buttons side="right">
        <button class="right button button-icon icon ion-plus" ui-sref="item"></button>
    </ion-nav-buttons>
    <ion-content>
        <ion-list show-delete="false" can-swipe="true">
            <ion-item ng-repeat="(key, value) in items" ui-sref="item({documentId: key, documentRevision: value._rev})">
                {{value.firstname}} {{value.lastname}}
                <ion-option-button class="button-assertive icon ion-trash-a" ng-click="delete(key, value._rev)"></ion-option-button>
            </ion-item>
        </ion-list>
    </ion-content>
</ion-view>

При перелистывании элемента списка нам предоставляется кнопка удаления, которая вызывает функцию delete () нашего контроллера.

Создание представления формы

Здесь мы определим, какие документы будут вставлены или обновлены в нашей базе данных. По сути, это мнение только форма. В файле вашего проекта www / templates / item.html добавьте следующий код:


<ion-view title="Couchbase with PouchDB">
    <ion-nav-buttons side="left">
        <button class="left button button-icon icon ion-arrow-left-c" ng-click="back()"></button>
    </ion-nav-buttons>
    <ion-content>
        <div class="list">
            <label class="item item-input">
                <input type="text" ng-model="inputForm.firstname" placeholder="First Name">
            </label>
            <label class="item item-input">
                <input type="text" ng-model="inputForm.lastname" placeholder="Last Name">
            </label>
            <label class="item item-input">
                <input type="text" ng-model="inputForm.email" placeholder="Email">
            </label>
        </div>
        <div class="padding">
            <button class="button button-block button-positive" ng-click="save(inputForm.firstname, inputForm.lastname, inputForm.email)">
                Save
            </button>
        </div>
    </ion-content>
</ion-view>

Конфигурация Sync Gateway

PouchDB и Ionic Framework — это только половина истории. Конечно, они создадут хорошее локально работающее приложение, но мы хотим, чтобы вещи синхронизировались. Шлюз Couchbase Sync Gateway является нашей конечной точкой для этого, и, конечно, PouchDB прекрасно с ним работает.

В файле sync-gateway-config.json вашего проекта добавьте следующее:


{
    "log":["CRUD+", "REST+", "Changes+", "Attach+"],
    "databases": {
        "test-database": {
            "server":"walrus:data",
            "sync":`
                function (doc) {
                    channel (doc.channels);
                }
            `,
            "users": {
                "GUEST": {
                    "disabled": false,
                    "admin_channels": ["*"]
                }
            }
        }
    },
    "CORS": {
        "Origin": ["http://localhost:9000"],
        "LoginOrigin": ["http://localhost:9000"],
        "Headers": ["Content-Type"],
        "MaxAge": 17280000
    }
}

Это одна из самых основных конфигураций. Несколько замечаний по этому поводу:

  • Для хранения используется морж: данные хранятся в памяти и не сохраняются. Не использовать для производства.
  • Все данные синхронизируются через пользователя GUEST, поэтому здесь не происходит аутентификация, но она может быть.
  • Мы исправляем проблемы с CORS, разрешая запросы на localhost: 9000, если вы хотите использовать Python для тестирования браузера.

Тестирование приложения

На данный момент весь наш код на месте, и наш Sync Gateway готов к запуску. Запустите Sync Gateway, выполнив в командной строке или в терминале следующую команду:


/path/to/sync/gateway/bin/sync-gateway /path/to/project/sync-gateway-config.json

Теперь Sync Gateway должен быть запущен, и вы можете проверить это, посетив http: // localhost: 4984 в вашем веб-браузере.

Тестирование для Android

При подключенном устройстве или работающем симуляторе из командной строки или терминала выполните следующие две команды, чтобы создать и установить файл APK:


ionic build android
adb install -r platforms/android/build/outputs/apk/android-debug.apk

Тестирование для iOS

Есть два хороших способа сделать это. Вы можете либо построить проект и открыть его с помощью XCode, либо вы можете создать и эмулировать приложение без запуска XCode. Первое можно сделать так:


ionic build ios

Затем откройте каталог платформы платформы / ios / и запустите файл проекта Xcode.

Если вы установили пакет Node Package Manager (NPM) ios-sim, вы можете сделать следующее:


ionic build ios
ionic emulate ios

Вывод

Теперь вы увидели, что есть два способа использования Couchbase в вашем мобильном приложении для Android и iOS от Ionic Framework. Вы можете использовать плагин Apache Cordova Couchbase, как показано в предыдущей серии блогов , или PouchDB. Обе эти возможности очень удобны, когда речь идет о межплатформенном хранении данных и синхронизации в вашем приложении.

Вы можете получить полный рабочий исходный код к этому сообщению в блоге через наш репозиторий Couchbase Labs GitHub .