Different stages of mobile app development and using KMM features to optimize it.

Idea : Stop duplicating the same code for different platforms. 

What are the exiting mobile cross platform framework solutions ? 

  • React Native 
  • Flutter 
  • Xamarin Forms 
  • Xamarin Native 
  • JavaScript + JavaScript Core 
  • C++ 


Which best fit for our need ?

Most of this cross platform framework solutions are UI centric i.e. it is focused mainly on developing UI components. 

  • React Native 
  • Flutter 
  • Xamarin Forms 
Then when you decide to write something more complicated than just sending HTTP requests, you will be almost alone in the wild west cross-platform world because of the libraries and practices. 
However, these technologies allow you to create similar interfaces for you apps very quickly. So this approach is absolutely justified when you have simple apps, thin clients or if you just want to make an MVP to test your product assumptions. 
But when your product will start to grow the UI quality and responsiveness requirements get stricter and the business logic becomes too complicated for a UI-centric approach. 

  • Xamarin Native 
  • JavaScript + JavaScript Core 
  • C++ 
This is where the business logic approach is justified. 
But one of the disadvantage is we have to add the one new language to the  code base of the project. 
Together with its own Tooling, Ecosystem and rules. 

Example: 
My Friend already have an existing project, with complex logic. 
I have plan to build a new mobile app but I have big ambitions for it. 
He doesn't want to find himself rewriting his entire application one day. 
So we both want to share only a specific part of their code and we don't have time to learn new language and deep dive into an unfamiliar ecosystem. 
We can all achieve this with KMM 
We can immediately start sharing the business logic between iOS and Android Application in any project without any limitations on the UI development process and in their favourite language Kotlin. 
 

Because the choice we make will greatly affect the architecture of our existing application and any that we create in the future. 

What is the standard architecture of any app ? 

  • UI : Views 
  • Presentation : Presenters, View Models, Controllers 
  • Business/ Domain : Entities, Use Cases, Interactors 
  • Data/ Core : Repositories, HTTP Clients, Cache 

KMM = Kotlin Multiplatform + Mobile Features 

KMM is an SDK for cross-platform mobile development. It uses the multiplatform capabilities of Kotlin and includes various tools and features designed to make the end-to-end experience of building easier, efficient and enjoyable. 
  • It allows to use the single codebase for the business logic of iOS and Android Apps 
  • You only need to write platform-specific code where it's necessary. Eg. To implement the native UI or when working with platform-specific APIs. 
  • Whenever you want to use iOS or Android features, you can use the expect/actual pattern to write platform-specific code with shared logic in the KMM module. 
  • KMM is seamlessly integrated with your mobile project. Shared code writeen in Kotlin, compiled to JVM bytecode with Kotlin/JVM and to native binaries with Kotlin/Native so you can use your KMM business-logic modules just like any other regular mobile library and KMM does not impose any restrictions on how you develop your app's UI. 


What kind of projects are suitable for integrating KMM ?
When your company do not care of whichever architecture and any technologies you choose we don't mind. 
But My Friend has an existing project. So he doesn't want to wait for a new one to start reusing the code. 

Do we need to go back to the drawing board to start sharing code between platforms? NO
KMM is seemlessly integrated with any mobile project. Shared code written in Kotlin, is compiled to JVM bytecode for Android and to native binaries for iOS. 
So we can use our KMM business-logic modules just like any other regular mobile library. 
So technical details of KMM integration are the same in both new and existing projects, just like adding a dependency. 

The only difference is : the process. 
For a new project, you can start developing new features in the shared code, then write native UI, and connect it with your shared business logic. 

There are different strategies for integrating with an existing project. You can take Kotlin code that has already been written for Android and refactor it by using only pure Kotlin libraries and make it compatible with iOS. 
Or we can take new feature from the Backlog (exisiting project) and then the process will be the same as for a new project. 


Lets Analyze our completely new project that we want to build. 
I want to build a mobile app called StockMarket which will get information about Stock Market prices, store in local database and display it in a list. Well yes, it's a quite simple app but it's always, just a beginning of the big-big story. 
As the integration of KMM is almost the same for both new and existing projects. 
So we develop the app that retrieves the data from the API, displays it in the list, and caches it in a local database. 
On the first architecture design stage, we need to decide, what part will be shared and what part will remain native ? 
KMM is designed to allow to share the business and core layers of your app. 

When we are creating a new mobile app we don't want to spend a lot of time thinking about organizing the data layer. It's such a common task. So there should be definitely be some building blocks to do it quickly. 
KMM provides exactly these building blocks. 
The ability to use platform-specific APIs along with the expect/actual pattern allows you to create them without reinventing the wheel. 

Eg. 
  • The Ktor HTTP Client is a good example of such a block. Like all multi platform libraries, it provides several artifacts one with common logic for all platforms and drivers for different platforms, which allows you to use the platform's native capabilities to perform HTTP requests. 
  • The other building block we need is kotlinx.serialization which we will use to deserialize JSON responses into objects of entity classes. 
  • SQLDelight : it will generate Kotlin code from SQL queries to create a type-safe database API which we will use to communicate with database on iOS and Android devices. 
  • As a Ktor library besides the core artifact, SQLDelight also provides platform-specific database drivers one for Android, and one for iOS. 
  • For the domain layer let's add a couple of entities. Eg. in our StockMarket app case there should be entities for Business and it's Stock Price 
  • Let's also add the wrappers for Ktor and SQLDelight libraries, that will allow us to get the data as business entities and hide some core details. 
  • The entry point to the KMM shared module will be the StockMarketSDK class a facade over our networking and caching services. 
  • Now we have the mobile SDK, which could be used in our application. 
  • It also can be easily distributed as a separate mobile library to allow other developers to create clients for our web service. 
  • We can write more layout of abstractions to make our code more cleaner. 

How should we configure our project. 
There are 3 parts of any Kotlin Multiplatform project. 
  1. Targets 
  2. Source Sets 
  3. Compilation 
A target is a part of the build that is responsible for building, testing, and packaging the application for a specific platform. 

Source sets are collections of Kotlin code files, along with their resources, dependencies, and language settings. A source set can be used in Kotlin compilations for one or more target platforms. 

Each target can have one or more compilations. For Eg. Production and Test purposal 
In our cross platform mobile project we need to declare two targets Android and iOS. 

The common dependencies that are used in all targets, need to be declared in the common source set. 
In our case : ktor, kotlinx.serilization, ktor's serialization feature, sqldelight runtime 

Since Kotlin 1.4 Stdlib is added by default to any Kotlin Gradle project, so no need to declare it explicitly. 

The new multiplatform libraries publishing format, since Kotlin 1.4 you should specify a dependency on the multiplatform library only once in the shared source set, instead of specifying dependencies on different library variants, in all source sets where it is used. 
So we can declare a dependency on kotlinx libraries or on the Ktor feature as in this example just once in the common source-set. 
However we still need to explicitly specify dependencies on ktor engines/ SQLDelight drivers because there are many of them and it's impossible to determine automatically which of them to use. 
This tiny iOS() declaration hides some tricky KMM module configuration details for the iOS target. 
The thing is that the iOS simulator and iOS devices, currently have different processor architectures. 
ARM and x86, so to be able to run and test our app on both of them we need to compile our shared code for two targets, not for one. 
Starting from 1.4, Kotlin Multiplatform supports a hierarchical project structure. That allows you to have intermediate source sets and use platform-specific APIs in them. 
You really don't need to think about it while you are working on the shared code for your mobile apps. 
Everything just works out of the box. 
But if you want to know more details about how all this works under the hood, and what engineering challenges we overcome to make everything work as it's supposed to, read the official documentation. 

Now about App Development 
Do we need to share the presentation layers ?
We definitely can do this, and there are already many community libraries, that allow you to do this and have plenty of examples of their usage. 
But you need to think carefully like do your apps look similar enough to have one presenter/view model/controller for both of them? Could this change ? So you can make the decision based on this things. 
Also it's never too late so whenever in future you want to share the code by doing some refactoring and move more layers to the shared module if we are sure that it's worth it. 


KMM Provides Tight integration with the iOS development process. 
  • Call Kotlin code from Objective-C/Swift and use iOS libraries from Kotlin (Kotlin/Native bidirectional interoperability with Objective-C/Swift)
  • Integrate KMM module in iOS project through CocoaPods dependency manager 
  • Write, run, test, debug shared code all in Android Studio : we do not need to switch the IDEs while working on the shared code. 

Bidirectional Interoperability with Objective-C/Swift 
  • It supports all fundamental concepts and doesn't require additional setup allowing you to integrate with KMM modules in iOS applications wihout a headache. 
  • Supports all basic concepts, including Companion objects, Data Class, Extensions, Objective-C generics, ecc... 
  • There is no concept like suspend function in Swift but it is simply an function with callbacks. 
  • There is also a fundamental difference in error handling between Kotlin and Swift. All Kotlin exceptions are unchecked while Swift has only checked errors. Thus, to make Swift code aware of expected exceptions. Kotlin functions should be marked with a @Throws annotation specifying a list of potential exception classes as parameters of @Throw annotations. Now we can handle all exceptions in our completion handler in Swift code. 

Kotlin/Native also provides integration with the CocoaPods dependency manager 
You can use KMM modules as a CocoaPods dependency or you can add dependencies on Pod libraries stored locally or in the CocoaPods repository. 
You can manage Pod dependencies directly in Android Studio, enjoying full coding support. 

























 


 



































Comments

Popular Posts