Combining the best of two cross-platform frameworks to build the ultimate multiplatform development experience.
React Native Kotlin Multiplatform Toolkit
AI Generated Video Summary
The Talk discusses the combination of React Native and Kotlin Multiplatform for cross-platform app development. Challenges with native modules in React Native are addressed, and the potential improvements of using Kotlin Multiplatform Mobile are explored. The integration of Kotlin Multiplatform with React Native streamlines native implementation and eliminates boilerplate code. Questions about architecture and compatibility, as well as the possibility of supporting React Native Web, are discussed. The React Native toolkit works with native animations and has potential for open-source development.
1. Introduction to React Native and Native Modules
We will discuss the combination of React Native and Kotlin Multiplatform to create a cross-platform setup for developing iOS and Android apps. Voice is a company that has built speech recognition for healthcare. Our app is powered by custom speech recognition and has already created over one million medical records. Native modules are important in React Native for accessing native functionality and communicating between native and JS code. However, few people write native modules due to the good ecosystem and library support in React Native, as well as the complexity of implementing them in both Android and iOS.
Okay, thank you for the nice introduction. As I said earlier, I'm Eric and with me is Leon and we want to talk about the combination of React Native and Kotlin Multiplatform to create the ultimate cross-platform setup for developing iOS and Android apps. So first let me start to introduce Voice a little bit. Voice is the company that's built speech recognition for healthcare. We have an application where healthcare workers can speak freely into our application. We transcribe the text and create structured medical records from the transcription. Then we are able to use an integration into the existing infrastructure and the facility to sync this record into the existing Electronic Healthcare Records systems. This is what we do, and you can see it in the GIF. And this way we already created over one million medical records and our app is powered by state-of-the-art custom speech recognition that we fine-tuned for the healthcare use case and all our models run on device, offline, so a facility does not have to have full Wi-Fi coverage to use our application.
2. Challenges with Native Modules and React Native
React Native projects face challenges with maintaining interfaces between native modules and keeping code bases in sync. Our team has encountered these issues and has developed over 20 custom native modules to facilitate communication between JS and native code. We need a better solution to avoid boilerplate code and improve the integration of native functionality in React Native projects. Leon will discuss the current status quo and potential improvements, including the use of Kotlin Multiplatform Mobile.
And you have so much boilerplate to just expose the functionality that you've just written in native. And also there's nothing inherent about native modules that keeps the interfaces in sync so you are fully responsible for keeping the interfaces Android, iOS, and JAS in sync so everything works together. And if you have an existing code basis in iOS and Android, it's pretty hard to use React Native in the first place because they maybe are maintained by different teams or in different repositories, and it's hard for those teams to kind of make an agreement on the interface native module that can then be used in a shared project which has React Native components.
So these issues lie at our heart because apart from the libraries that exist that have native modules in them, we also have over 20 custom native modules that we've written to do communication between JAS and native because we do our autoprocessing in native and we need to communicate data around it. We do all our model inference obviously in native managing model artifacts, downloading stuff, and doing background work in general. So this is why we need a solution for this. If you do so many native modules and expose so much native functionality, you need to have a better way than doing all this boilerplate and Leon will tell you more about the status quo and what we can do to improve.
So this is a typical React Native project setup. You have actually three sub projects for Android, iOS, and React, and each of these projects use their own language and own ecosystem and their own tools. So if you want to expose native code, you would have to write it twice for each native platform, and when you write React Native modules, the API to expose it is very low level and platform-dependent. So imagine you have to write 20 React Native modules to expose your native logic. There must be a better way to leverage native concurrency and native performance improvements in your React Native app.
3. Introduction to Kotlin Multiplatform Mobile
Kotlin Multiplatform allows running Kotlin code on iOS and Android, directly compiled to platform specifics without the need for runtime. It enables the use of platform-specific APIs without additional libraries. A demo will showcase how Kotlin Multiplatform works with React Native. The common main folder contains platform-agnostic code that compiles natively for Android and iOS. The name manager class uses platform-specific implementations through the expect identifier. Android-specific APIs can be accessed, such as share preferences, while iOS-specific APIs, like user defaults, can also be imported. The expect class allows mixing cross-platform and platform-specific code. The common code class can be exposed to React Native using the React Native Module annotation.
So let's introduce Kotlin Multiplatform Mobile. With Kotlin Multiplatform, you are able to run your Kotlin code on iOS and Android. Unlike JS code with React Native, it is able to run on multiple platforms. But unlike React Native, Kotlin is compiled directly, natively to the platform specifics. So it has no runtime in between. And therefore, because it's compiled to the platform, it also allows you to use platform specific APIs directly without needing extra libraries which create a wrap for the native platform specific APIs.
To get a better understanding how Kotlin Multiplatform can be used together with React Native, Eric will show you a demo. Okay, so let's switch to the demo. Here we have a Kotlin file, and this Kotlin file is within a Kotlin Multiplatform project. So here we are in the common main folder, and in the Kotlin Multiplatform project, this is a special folder also called a source set, and everything that we write here is platform agnostic. So it's cross-platform code that is written in Kotlin, and like Leon said, will be compiled natively to JVM on Android and to native for iOS.
So what we have here is a name manager that has two methods, setName and getName, and setName will throw an exception if the name is not one of the valid ones, Eric or Leon. And internally, it uses persistent config to set this in a persistent way in native. So let's look at persistent config, and you can see persistent config is just like kind of an interface, but there is the expect identifier there, and this means that we expect that there is an actual platform-specific implementation for this class on iOS and on Android. And let's look into this. So I can go here and look into the Android one, and you can see now we are in the Android main source set. And this means we can access Android-specific APIs. So I can just import from Android, and if I want to have a key-value store on Android, that's pretty simple. I just use share preferences, and I can import from Android, get from the context of share preferences for our bundle, and then implement our methods that are defined by the expect class.
Similarly, I can go to the iOS implementation, and this is where it gets interesting, because now we are in the iOS main store set, and we can access platform-specific APIs from iOS. And this is kind of remarkable, because imports like import from foundation are usually imports you only have in Objective-C or Swift, but with Kotlin Multiplatform, you can just import and it's user defaults, and what it does, it will have, it will ultimately generate an inter-op interface to this native API. So we can just code against this native API in Kotlin, and Kotlin Multiplatform will do the rest, and link and compile against this native platform. So key-value store on iOS, we just use NSUserDefaults, and implement our methods. So back to our common code, and now we can understand how this works, we have common code, and whenever we need platform-specific code, we define an expect class that is actual implementations on both platforms, and in common code, we can do like whatever we want in cross-platform. And that's super cool, we can kind of mix cross-platform and platform-specific code. So now we have this cross-platform name manager that's super cool that writes into native state, but how do we get this super cool cross-platform class into React Native, where we need it? So what we've built is you can just add an annotation, it's called React Native Module, and give a name. And this automatically exposes this common code class to React Native. And you can see we import from our toolkit, which is named react-native-gudwit with a K for Kotlin. That's a joke. And now we expose the common code class.
4. Implementing Native Modules in Kotlin
We expose our complete common Kotlin class and switch to JS. In the basic app, we can set the name and refresh to get the name from Native. We implement the common class via the native module setup and handle exceptions. We expose the get config and make it work on iOS. We explore a better solution to automatically get the name from native in the Kotlin code using the persistent config class.
So, but we're not done yet, we need to also expose the methods that we need. So let's export the method here. And now we exposed our complete common Kotlin class. And this is super cool. And now let's switch to JS.
This is a basic app, where I can set the name with an input field, I can, and a button, and I can refresh to get the name from Native. So, currently, this doesn't work at all because it doesn't really do anything when I say get name or set name. But you can see that this works because what we're loading is to its thing.
And now we want to implement our common class that we just exposed. And we can do this via the native module setup. So we just say name manager is from native modules. And say okay let's do the set name implementation. And we have a promise that we await set name from input. Okay. You remember, when we input a name that's not ErgoLeon, it will throw an exception. So let me just say Adam. And you can see the exception that was thrown in Kotlin code is now mapped to promise rejection. So let's set a name that's valid. Nice.
But we still don't have any get config. So we expose the get config so we just set our name here to await name manager get name and now we can refresh. And have Leon. So we use this, the methods that we just exposed also should work on iOS. Fine. And when I say something different, yeah. Okay. So, but now we always have to press refresh to get the name from native and maybe we can do better. So let's go back to our Kotlin code. And what's hidden here underneath is name is flow. And this uses the persistent config class, which defines get config as flow.
5. Using Kotlin Flows and the React Native Toolkit
6. Combining Kotlin Multiplatform with React Native
We saw Kotlin multiplatform in action, combining common code and platform-specific code. The React Native toolkit allows direct exposure of common code classes to React Native. Combining Kotlin multiplatform with React Native streamlines native implementation and eliminates boilerplate code. The project structure now has a single Kotlin codebase, with common code shared between platforms. React Native modules only need to be defined once in common code. The React Native toolkit GitHub repository provides a guide for getting started with React Native toolkit and Kotlin Multiplatform.
Okay, so this was a demo, switch back. Quick recap, we saw Kotlin multiplatform in action. We have common code, platform-specific code, we can mix them, and we can use expect actual to create kind of an interface to have, and create an abstraction on platform-specific implementations. And we can use the React Native toolkit to directly expose common code classes to React Native via a Native module, and use kind of toReact and use flow and utilities to make our lives easier to work with Kotlin code.
So what problems are solved by combining Kotlin multiplatform with React Native? First and for all, it's to streamline a native implementation via KMM. And also we would use the boilerplate code using our toolkit because you don't have to yourself create in native modules, but they are just generated using the annotation. Also using Kotlin multiplatform it's guaranteed that the interfaces for the different platforms stay in sync. And what also is nice is that we can now migrate native code to Kotlin multiplatform and then directly and easily expose it to React Native.
And let's have a look at how the project structure changed with this setup. Now we have a single codebase which is in Kotlin for our native code. And in this project there are three source sets. One common code source set which should contain the most of your business logic which you are sharing between all platform. And the only small portions of your code are actually platform-specific for Android and iOS. And now we can also see that React Native modules only have to be defined once in a common code and not for both platforms. And we think that this is the ultimate bus platform set up for mobile development because you can write your UI with React and implement your business logic natively with Kotlin Multiplatform. And between you have the React Native toolkit which helps you move between them. And how do you get started? We created the React Native toolkit GitHub repository. There's a nice guide which helps you set up and get started with React Native toolkit but also helps you in using Kotlin Multiplatform with React Native project.
So, thank you very much for listening. Please check out the repository I just mentioned. It's fresh off the press like released like two weeks ago and leave us a star and also if you think it's interesting what we're doing like bridging the gap React, Kotlin and machine learning and doing something for healthcare workers, please consider reaching out to us. We are hiring for React and Kotlin engineers. You can check us out on voice.de and we are happy to get your questions. Really nice presentation. I mean I'm blown away. I didn't know about this package. Thank you very much for first creating it. It seems like it's really easy to just integrate everything, which is yeah, really nice. But I would like to invite you here. Maybe we can go through some questions.
Questions about Architecture and Compatibility
We have some questions about the new architecture and its compatibility with the library. We discussed adapting the library to generate modules for the new architecture. Independent native modules can be created and imported in a bare React Native project. However, manual linking is required for multiple modules. Supporting React Native Web with Kotlin to JS or Wasm compilation is an interesting possibility. The toolkit's compatibility with building native animations was briefly mentioned.
We do have some questions. That's nice. But meanwhile, while I'm going through them, could you please add more about the new architecture and the old one? Have you ever thought about it or what do you think it's like? Is there a good fit for this library?
Yeah. So we just had the talk about the new architecture for Nicola and it's super amazing what the React Native team has done. And we're kind of going a little bit different approach. But we've talked to Nicola and to the React Native team to kind of adapt this library to also generate modules that are more fitted to the new architecture. Also Nicola said that all the modules that we generate now are still backwards compatible still in the new architecture, but we can go further and also kind of generate code from Kotlin that's compatible with the really with the new architecture.
Yeah, thank you very much. There is another one. What do you think about the new native modules API from Xpo? Let's leave this question for later. Can an independent native module be created to be imported in a bare React Native project? Or does this whole project needs to be created with this, I think it's referring to the library itself?
I can answer this question. So if you generate native React Native modules, you can import them in other projects. And we're actually doing this with our app. And you have to keep in mind that by generating multiple React Native modules, they cannot be auto-linked. So you have to manually link them in your code. But that's also a nice feature to have, because then you can inject dependencies into React Native modules, which would not be possible if they are auto-linked, because they are the constructor. You have to be calling yourself, you can then give some extra arguments in there.
All right, Ian. There is another one. Would it be possible to support React Native Web, too, either with Kotlin to JS or Wasm compilation? Difficult, because this is only for React Native. I don't think if React Native is also supported for the web.
Yeah, there's also React Native Web. OK. But we haven't looked into it. But it's probably interesting, because Kotlin, as you said, the multiplatform can also compile to JS. So maybe it's interesting if something could be done there to kind of interop with more browser-specific stuff, and kind of write native modules for browser-specific stuff.
Native Animations and Open Source Plans
The toolkit works with building native animations, but it's not recommended for heavy animations. There are currently no open-source libraries built with the React Native toolkit. The 20 custom native modules we built are tightly coupled to our application's business logic. We are not familiar with Expo's native modules.
And how does this toolkit work with building native animations? I think this is like a vague question in one way or another, but maybe leveraging like native modules that have animations pre-built, I think. Yeah, I think what I would imagine that you have maybe some flow that does an animation. But you have to remember that we are still going over the bridge, and you will still have a render update if you receive something from useflow. So doing like super heavy animations over this useflow is still not really, doesn't really do it. You should still use kind of react, reanimated it a little bit differently. So you don't have this, these problems. So it's more basically, as a use case fire and forget, not to get back any info from the native side. It's for both sides, but you shouldn't rely on it to do like rapid fire information from native. It's just for business logic, normal state updates, all the stuff that you would normally write like with a Kotlin.
I'm curious to see if there are any open source libraries built with react native toolkit out there already. Currently not, because it's like we said, it's fresh from the press and we released it two weeks ago. And do you have any plans on open sourcing some of those 20 different native modules, except the business logic of course and give it to public? The thing about these 20 native modules, they are very tightly coupled to our application business logic inside our application. So that's why we have built these custom modules because they are exposing, especially this logic we have in our code and cannot use some public off-the-shelf library because they don't integrate so well with our own business logic we have already in native Kotlin code. This is also what Leon talked about dependency ejection is a super important topic. Most of the natures that we have have dependency ejections of dependencies that are super tailored to our application, our model manager, our processing and inferences and stuff.
Someone is saying greetings from the office. I totally agree, it was like a mind blowing presentation, I'll definitely give it a try. There is another question, what do you think about the new native modules from Expo and what do you think might be the difference? Do you mean React Native? Expo Native Modules. We are not familiar with Expo at all. Ok, that kind of makes sense. It's good to live in your own world in a way or another to come up with different solutions and not be influenced by others. I think this is what you have presented today. It's something new, something fresh from my opinion. Because I have been in this React Native ecosystem for a while. I have never seen anything like this. I'm really happy to be here in the first row to see it actually in action. I would like to say congrats once again and yeah, it was an amazing talk. Thank you so much for giving this presentation and we're looking forward to see where this package is going to go to. Thanks, thanks.