Building A Messaging Highway For Our iOS Apps

How we built a Courier library for iOS with MQTT.

Introduction

Every time an order is made on GoFood, customers see an Active Order Screen, which looks like this:

GoFood Active Order Screen

Background of Courier iOS Library

Courier iOS High Level Architecture
  1. The communication protocol should be agnostic and hidden from the client. With this, we should be able to switch to any communication protocol without much change from the client. (MQTT, WebSocket, etc).
  2. The library used should be agnostic, so we can switch to any library without much effort (CocoaMQTT, MQTTClientFramework, etc).

MQTT Libraries on iOS

There are 2 most used open source libraries that we can use to integrate MQTT:

  1. CocoaMQTT is a MQTT v3.1.1 client library for iOS written with Swift 5. It uses CocoaAsyncSocket for networking and currently has no disk persistence support as of v1.2.5.
CocoaMQTT & MQTTClientFramework Comparison

Courier iOS Library Features

Courier is not just a simple wrapper on top of MQTTClientFramework. It also provides several main features to increase robustness and reliability for the iOS client app to communicate with the broker. Let me walk you through of all the main features of iOS Courier library.

Clean and Reactive API

Courier provides clean and simple API to connect, subscribe, and receive stream of messages from subscribed topic. With the nature of persistent realtime long run connection that process messages asynchronously, we designed Courier API to be reactive using Combine Publisher and Subscriber pattern.

// Method to get publisher for a subscribed topic
func
messagePublisher<D>(topic: String) -> AnyPublisher<D, Never>
// Usage (type of model is generic using type inference)
courier.subscribe(topic: topic, qos: qos)
courier.messagePublisher(topic: topic)
.sink { [weak self] (message: Message) in
self?
.handleMessageReceiveEvent(.success(message))
}
.store(in: &cancellables)

Multi Message Adapter Support

Courier provides multi message adapters that supports various serialisation formats such as JSON, Protobuf, XML, or anything else that can be serialised into data and deserialised into model.

import SwiftProtobufclass ProtobufMessageAdapter: MessageAdapter {
func fromMessage<T>(_ message: Data) throws -> T {
// Deserialize to Protobuf Message
}
func toMessage<T>(data: T) throws -> Data {
//Serialize Protobuf Message to Data
}
}

Subscription Store

Courier provides subscription store to manage currently subscribed topics and pending unsubscribe topics. This is super useful to avoid stale subscriptions in broker when the user connects with clean session flag set to false.

Fallback Policies

Courier provides several built in fallback policies for various Courier lifecycle system events (connection lost, connection failure, subscribe failure, and many more). User can react and provide their fallback logic in case of failure (for example fallback to HTTP polling). The user can also implements their own custom fallback policy and react to various Courier system events accordingly.

Database Persistence and Offline Message Buffer

MQTTClientFramework provides this feature to persist QoS 1 and QoS 2 messages in case the user is offline when sending those messages. It will retry to send the messages maintaining the order when the internet connection is back.

Automatic Reconnect

Courier provides the reconnect mechanism to handle the case where the internet connection is lost and whether it should retry to connect when the internet connection is reachable.

Custom Authentication Provider

In case, the user needs to be authenticated when connecting to the broker using username and password. Courier provides API to delegate the authentication handling from the user side. The user should be able to implement their own custom authentication to get the username and password used for making connection to the broker.

Event Provider

The user can optionally listen to Courier system events such as connection success, connection lost, message received from a topic, and many more). This is pretty useful in case they want to add analytics and metrics for their use case.

Conclusion

Courier is our solution to provide a realtime, lightweight, and high efficient messaging highway between mobile apps and server using MQTT.

  1. Realtime app metrics & analytics.
  2. Any realtime bi-directional data sharing (e.g collaborative cart sharing, etc)

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Alfian Losari

Mobile Developer and Lifelong Learner. Currently building super app @ Go-Jek. Xcoding with Alfian at https://alfianlosari.com