Developing Kotlin Multiplatform Mobile Apps using VIPER Architecture

Nilay Dagdemir
MirsadTech
Published in
6 min readFeb 14, 2022

Hello developers đź‘‹

This blog post will explain briefly kotlin multiplatform mobile and VIPER architectural pattern, and get into details about how do we develop our mobile apps on kotlin multiplatform mobile using VIPER architecture. Feel free to share your thoughts.

Let’s dive in!

Image source bitrise

Technology is growing fast and as developers, we need to follow the latest technologies and continually adapt to changing technology, if we don’t want to fall behind.

One of the latest technology for cross-platform development is Kotlin Multiplatform Mobile (KMM) which went Alpha in August 2020. KMM was a revolution in tech world for both native and hybrid mobile developers since it creates native apps by sharing the common logic including business logic, view logic, data objects, and so on. Consequently, KMM provides developers all the combined benefits of native and cross-platform apps.

It is trusted in production by many of the world’s leading companies, including Philips, Netflix, Leroy Merlin, and VMWare. — kotlinlang.org

In order to take a full advantage of this blog post, basic understanding about KMM, dependency injection, and VIPER architectural pattern may be needed since this blog post will explain them only briefly. This post will mainly focus on developing KMM apps using VIPER architecture.

What is KMM?

Kotlin Multiplatform Mobile (KMM) is an SDK with an evolving echosystem for cross-platform mobile development. KMM allows developers to use a shared codebase for both iOS and Android apps. Hence, developers only need to implement platform-specific code when a platform-specific API is needed or creating a native UI. As a result, KMM creates fully native apps by sharing the common logic.

Image source kotlinlang

This article will not cover how to create KMM projects, if you want to learn how to start using KMM, kindly visit: KMM start from scratch.

What is VIPER?

VIPER is a design pattern which provides clearer separation of concerns than the other architectural patterns. The word VIPER stands for View, Interactor, Presenter, Entity, and Router. To briefly mention about these layers;

  • View: UI layer. Sends the user actions to the presenter and shows whatever the presenter tells it.
  • Interactor: Networking layer. Class that mediates between the presenter and the data. It takes direction from the presenter.
  • Presenter: “Traffic cop” of the architecture. Connects all layers together. Directing data between the view and interactor, taking user actions and calling router to navigate the user between views.
  • Entity: Data layer. Models that are used by interactor.
  • Router: Navigation layer. Handles navigation between screens.
Image source raywenderlich

VIPER architectural pattern is well suited for large-scale projects with complexity since it allows developers to create a modular and easily maintainable project which is easy to understand. Also it makes identifying bugs and writing unit tests simple because of its modular structure.

Consequently, we wanted to create native apps by using KMM for sharing the common logic between iOS and Android to avoid duplicate codes and combine this feature with the power of VIPER’s clean modular structure. Hence, you can create easily maintainable, highly readable source code including simplified process of identifying bugs and writing unit tests.

Creating KMM Apps Using VIPER Architecture

Before we deep dive into developing KMM apps using VIPER, let’s have a quick look some basic concepts and the dependencies we used:

  • Koin: A pragmatic and lightweight dependency injection framework which supports KMM. Dependency injection is a programming technique that makes a class independent of its dependencies.
  • Ktor: A multiplatform asynchronous HTTP client, which allows you to make requests and handle responses, extend its functionality with plugins, such as authentication, JSON serialization, and so on.

So, we created our KMM project, we installed Kotlin Multiplatform Mobile plugin in order to run the iOS part of our project, connected the KMM module we created to the iOS part of our project by using integrated gradle taskembedAndSignAppleFrameworkForXcode from Xcode and made the initial setups. Finally, we’re good to go!

After creating a KMM project and adding the dependencies mentioned, we need to create VIPER modules for each screen which the app needs. For instance, let’s create a Login screen. Modules needed to be created:

  • For shared part:
    1. LoginContract.kt
    2. LoginKoinModule.kt
    3. LoginInteractor.kt
    4. LoginPresenter.kt
    5. LoginRouter.kt
  • For View:
    6. Login.storyboard for iOS, fragment_login.xml for Android
    7. LoginViewController.swift for iOS, LoginFragment.kt for Android

Now, let’s get into the details…

  • LoginContract:
    This contract will have all the interfaces needed for the communication between VIPER modules. LoginContract.kt should be look like this:

Nice!

We created our interfaces that will be needed for communication between VIPER modules. Also see that we have additional interface called ILoginRouterToView. Normally we would not need this interface but since we’re using KMM and inject our views from different platforms (iOS & Android); we needed to add an additional protocol that contains same functions as ILoginRouter in order to switch screens.

  • LoginKoinModule:
    Each interface should be provided by dependency injection, so module specifications should be added into corresponding viper module package. LoginKoinModule.kt should be look like this:
  1. This is where we use koin framework to inject necessary classes.
  2. WeakReference class we created is used in order not to create any memory leak. This is an except/actual class which implementation needed to change for iosMain and androidMain part.
    This is our WeakReference.kt expect class:

Actual implementation for iosMain:

Actual implementation for androidMain:

3. HTTPClientProvider object is created to perform network requests in the interactor class.

  • LoginInteractor:
    Networking layer. LoginInteractor.kt should be look like this:

Here we perform network requests, and return the results to the presenter by using ILoginInteractorToPresenter interface.

  • LoginPresenter:
    Let’s connect all layers together. LoginPresenter.kt should be look like this:

Here we create communication between modules.

  • LoginRouter:
    Switch between screens. LoginRouter.kt should be look like this:

Update koin modules and call view in order to navigate to the dashboard. For more information about koin modules, please refer to: koin

We finally finished implementing the shared part. Now let’s create the UI! Since we are using KMM, we want to keep the design completely native. Hence;

  • For iOS part, Xcode will be used to create the UI. For our example, we created a Login Screen using storyboard, created a LoginViewController class which inherits from UIViewController, and connected this storyboard to this class. KMM shared framework should be imported in order to use shared code from Xcode. LoginViewController should be look like this:
  • For Android part, Android Studio will be used to create the UI. For our example, we created a Login Screen using xml, created a LoginFragment class and connected them. LoginFragment should be look like this:

That’s it!

We created a Login Screen for both Android and iOS platforms. Shared code implemented only once in Kotlin using KMM, UI design created separately for both platforms, and we used the shared code from our view classes; LoginViewController.swift and LoginFragment.kt.

At first glance, it may seem like a lot of work in order to create a VIPER implementation. However, implementing additional functionalities to these modules is very straightforward since it is based on a Single Responsibility Principle.

Finally, we created VIPER modules on KMM step by step. In our upcoming articles, we will explain more in details on how we are using dependency injection with koin framework.

Thank you for your contributions Göksun ÖNAL, Berkay Turancı, and Yaşar Can Kakdaş.

--

--