Build an Ionic Plugin with Couchbase Lite on iOS

In this tutorial, you will learn how to use Couchbase Lite in a Cordova application.

The sample project is a Cordova web application that allows users to query for and display a list of hotels stored in a Couchbase Lite database.

ionic listing hotels ios

Architecture

The user Interface is a web app written in Javascript using Ionic and is rendered within a WebView. The business logic and data model is written in native Swift. The data model uses Couchbase Lite as the embedded data persistence layer. The Cordova Plugin API acts as the bridging layer between the JavaScript and the native Swift worlds . The plugin exposes a Javascript API to the web app.

This architecture allows you to write the User Interface code once for both iOS and Android apps while leveraging Couchbase Lite’s native iOS framework for data management.

arch android

Data Model

The data model for the app is very straightforward. There is one type of document: the "hotel" document which contains the details of each hotel. Those documents have a "type": "hotel" property.

data model

Pre-requisites

This tutorial requires the following components and versions to run successfully.

  • Xcode 10 or above

  • Swift 4.2

  • Couchbase Lite 2.1.1

The tutorial also assumes that the reader has a basic understanding of developing apps with Cordova and Swift.

Getting Started

The User Interface has already been implemented in the starter project. You will add the code to persist and query data.

  1. Install the Ionic and Cordova CLIs which are tools that are required for building and managing Ionic and Cordova based apps.

    npm install -g ionic cordova
  2. Download the starter project.

  3. Unzip starter-project.zip.

  4. Open the starter-project/ directory in the JavaScript editor of your choice (for example, Visual Studio Code or WebStorm).

  5. The User Interface code is located in HotelLister/src/pages/home/.

  6. Run the following commands in your Terminal.

    cd HotelLister
    npm install

    The npm install command installs dependencies.

  7. To deploy the app to an iOS simulator, run the following.

    ionic cordova platform add ios
    ionic cordova emulate --list

    Then, use the --target option to specify the simulator to deploy the app to.

    ionic cordova emulate ios --target "iPhone-XR, 12.0" -- --buildFlag="-UseModernBuildSystem=0"
  8. You should see an empty list view as shown below.

    ionic empty list ios

In the next section, you will setup the Cordova plugin which is the first step for establishing communication between native code and JavaScript.

Cordova Plugin Setup

With Cordova Plugins, you can write native code and have access to it from JavaScript. Plugins provide access to device and platform functionality that is ordinarily unavailable to web-based apps.

In this section you will create a new plugin called cordova-plugin-hotel-lister to implement data persistence using Couchbase Lite’s Swift API.

The plugin code will be added to the cordova-plugin-hotel-lister folder which resides alongside the HotelLister folder.

The starter project contains a file at cordova-plugin-hotel-lister/src/android/Utils.java that will be used in a later section to unzip the pre-built database.

  1. Create a new file at cordova-plugin-hotel-lister/plugin.xml with the following.

    <?xml version="1.0" encoding="UTF-8"?>
    <plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
            xmlns:android="http://schemas.android.com/apk/res/android"
            id="cordova-plugin-hotel-lister" version="0.0.1">
      <name>cordova-plugin-hotel-lister</name>
      <description>An Cordova plugin for the Hotel Lister application to implement data persistence using Couchbase Lite.</description>
      <license>Couchbase CE / https://www.couchbase.com/binaries/content/assets/website/legal/ce-license-agreement.pdf</license>
    
      <engines>
        <engine name="cordova" version=">=3.0.0"/>
      </engines>
    
      <js-module src="www/hotel-lister.js" name="HotelLister">
        <clobbers target="window.plugins.HotelLister" />
      </js-module>
    
      <platform name="ios">
        <config-file target="config.xml" parent="/*">
          <feature name="HotelLister">
            <param name="ios-package" value="HotelLister"/>
          </feature>
        </config-file>
    
        <source-file
          src="src/ios/HotelLister.swift"/>
      </platform>
    </plugin>
    • The id="cordova-plugin-hotel-lister" attribute is the plugin name which will be used later to import it in the Ionic project.

    • The <js-module></js-module> XML tag declares the location of the file that will declare the JavaScript interface.

    • The <platform name="ios"></platform> XML tag declares the location of the Swift files to hold the native code.

  2. Create a new file at cordova-plugin-hotel-lister/package.json with the following.

    {
      "name": "cordova-plugin-hotel-lister",
      "version": "0.0.1",
      "description": "A Cordova plugin for the Hotel Lister app.",
      "cordova": {
        "id": "cordova-plugin-hotel-lister",
        "platforms": [
          "android",
          "ios"
        ]
      },
      "engines": [
        {
          "name": "cordova",
          "version": ">=3.0.0"
        }
      ],
      "author": "Couchbase <mobile@couchbase.com>",
      "license": "Couchbase CE / https://www.couchbase.com/binaries/content/assets/website/legal/ce-license-agreement.pdf"
    }

    This file describes the plugin.

  3. Create a new file at cordova-plugin-hotel-lister/www/hotel-lister.js. This file defines the JS API with which a Cordova/Ionic web app may interact with this plugin. Generally, this means that the plugin binds to the window element and by doing so, grants access to its parent project through simple JavaScript references. Add the following to your hotel-lister.js file:

    var exec = require('cordova/exec');
    
    var hotelLister = {
      /* code will be added here later */
    };
    
    module.exports = hotelLister;
  4. Create a new file at cordova-plugin-hotel-lister/src/ios/HotelLister.swift with the following. This file provides the native Swift implementation corresponding to the APIs defined in hotel-lister.js.

    @objc(HotelLister) class HotelLister : CDVPlugin {
    
        override func pluginInitialize() {
    
        }
    }

    The Cordova Plugin is instantiated when it is first called in the JavaScipt WebView app. The pluginInitialized() method includes the startup code. Refer to the Plugin Lifecycle documentation for more details.

  5. To verify that your plugin is ready to work as expected, you have to install it in your HotelLister project. To do so, run the following commands from the root of the starter-project folder.

    cd HotelLister
    cordova platform rm ios
    cordova plugin add ../cordova-plugin-hotel-lister/
    cordova platform add ios

    If successful, you should see the following in the output.

    Adding cordova-plugin-hotel-lister to package.json
    Saved plugin info for "cordova-plugin-hotel-lister" to config.xml

Couchbase Lite Setup

Next, you will import Couchbase Lite as a dependency in the Xcode project.

  1. Download Couchbase Lite from here.

  2. Unzip the file.

  3. Open the Xcode project located at HotelLister/platforms/ios/HotelLister.xcodeproj.

  4. Drag CouchbaseLiteSwift.framework from the downloaded folder to the Xcode project navigator. Be sure to select the Copy items if needed checkbox.

    drag framework
  5. Navigate to Project > General > Embedded Binary and drag CouchbaseLiteSwift.framework over the list.

    drag embedded

Database Setup

In our example, we will start with a pre-built Couchbase Lite database that contains a bunch of hotel documents. We will make our queries against the documents in this database. Note that in a real world application, the data could be synced down from other Couchbase Lite clients or from Sync Gateway in the cloud.

The pre-built database needs to be added to the Xcode project.

  1. Download travel-sample.cblite2.zip.

  2. Unzip it.

  3. Drag it over the Xcode project navigator. Be sure to select the Copy items if needed checkbox.

  4. We will use the singleton pattern to setup the database instance. Create a new file at cordova-plugin-hotel-lister/src/ios/DatabaseManager.swift and insert the following.

    import CouchbaseLiteSwift
    
    class DatabaseManager {
    
        private static var privateSharedInstance: DatabaseManager?
    
        var database: Database
    
        let DB_NAME = "travel-sample"
    
        class func sharedInstance() -> DatabaseManager   {
            guard let privateInstance = DatabaseManager.privateSharedInstance else {
                DatabaseManager.privateSharedInstance = DatabaseManager()
                return DatabaseManager.privateSharedInstance!
            }
            return privateInstance
        }
    
        private init() {
            let path = Bundle.main.path(forResource: self.DB_NAME, ofType: "cblite2")!
            if !Database.exists(withName: self.DB_NAME) {
                do {
                    try Database.copy(fromPath: path, toDatabase: self.DB_NAME, withConfig: nil)
                } catch {
                    fatalError("Could not copy database")
                }
            }
            do {
                self.database = try Database(name: "travel-sample")
            } catch {
                fatalError("Could not copy database")
            }
        }
    
    }

    You first check if a database named "travel-sample" exists. If it doesn’t exist, the travel-sample.cblite2 database file that was bundled with the app is copied to the default Couchbase Lite directory. The database is then opened and the database instance is set.

  5. When adding a new Swift file, it must be referenced in the plugin’s configuration file. Insert the following as a child to the <platform name="ios"></platform> element in cordova-plugin-hotel-lister/plugin.xml.

    <source-file
    	src="src/ios/DatabaseManager.swift"/>
  6. Next, add the following import statement to the top of HotelLister.swift.

    import CouchbaseLiteSwift

    Add the following instance variable to the HotelLister class in HotelLister.swift.

    var database: Database?

    Import the Couchbase Lite framework in HotelLister.swift.

  7. Then, update the pluginInitialize() method in HotelLister.swift with the following to set the database instance property.

    override func pluginInitialize() {
        self.database = DatabaseManager.sharedInstance().database
    }
  8. To test your changes, you must re-install the Cordova plugin from cordova-plugin-hotel-lister to HotelLister. Run the following commands from the root of the starter-project folder.

    cd HotelLister
    cordova plugin rm cordova-plugin-hotel-lister
    cordova plugin add ../cordova-plugin-hotel-lister/
  9. Build the project.

    ionic cordova emulate ios --target "iPhone-XR, 12.0" -- --buildFlag="-UseModernBuildSystem=0"

    The application should run successfully. You will still see an empty screen because at this stage, the Couchbase Lite database is initialized but you haven’t run any queries to fetch data from the database.

In the next section, you will use this Database variable to query hotels from the pre-built database.

Listing Hotels

In this section, you will add the functionality to list hotels from the database.

  1. Add the implementation of the queryHotels method to cordova-plugin-hotel-lister/src/ios/HotelLister.swift.

    @objc(queryHotels:)
    func queryHotels(command: CDVInvokedUrlCommand) {
        let DOC_TYPE = "hotel";
    
        let query = QueryBuilder
            .select(
                SelectResult.expression(Meta.id),
                SelectResult.property("address"),
                SelectResult.property("phone"),
                SelectResult.property("name")
            )
            .from(DataSource.database(database!))
            .where(
                Expression.property("type")
                    .equalTo(Expression.string(DOC_TYPE))
        )
    
        do {
            let resultSet = try query.execute()
            let resultSetArray = resultSet.allResults()
            var array = [Any]()
            for item in resultSetArray {
                array.append(item.toDictionary())
            }
            let pluginResult = CDVPluginResult(status: CDVCommandStatus_OK, messageAs: array)
            self.commandDelegate.send(pluginResult, callbackId: command.callbackId)
        } catch {
            fatalError(error.localizedDescription);
        }
    }

    This method queries for the address, phone and name properties of documents where the type property is hotel.

  2. Next, you will update the plugin’s JavaScript interface. In cordova-plugin-hotel-lister/www/hotel-lister.js, replace /* code will be added here later */ with the following code snippet.

    queryHotels: function(successCallback, errorCallback) {
      exec(successCallback, errorCallback, 'HotelLister', 'queryHotels');
    },
  3. You can now call the queryHotels method in the Ionic project. Add the following to the constructor method in HotelLister/src/pages/home/home.ts.

    this.platform.ready().then(() => {
      window.plugins.HotelLister.queryHotels((hotels) => {
        console.log(hotels);
        this.hotels = hotels;
      });
    });
  4. To test your changes, you must re-install the Cordova plugin from cordova-plugin-hotel-lister to HotelLister. Run the following commands from the root of the start-project folder

    cd HotelLister
    cordova plugin rm cordova-plugin-hotel-lister
    cordova plugin add ../cordova-plugin-hotel-lister/
  5. Build and run.

    ionic cordova emulate ios --target "iPhone-XR, 12.0" -- --buildFlag="-UseModernBuildSystem=0"
  6. You should now see the list of hotels.

    ionic listing hotels ios

Conclusion

Well done! You have learned how to create a Cordova plugin to use Couchbase Lite’s native APIs and import the plugin in an Ionic project!

You can find a working copy of the completed project in the final project zip file. To build and run the final project:

  1. Follow the instructions outlined in the Getting Started section,

  2. and the instructions in the Couchbase Lite Setup section to integrate Couchbase Lite into the final project.