Taking React Native to the next level with Kotlin and Swift

Hector Javier Gordin
5 min readOct 24, 2020

Hello react native developers. In these times, it is a bit complicated to develop native functionalities, rather bridges in React Native in the native programming languages ​​proposed by each of the platforms and that are established by default in React Native, say Java for Android and Objective C for IOs. Not being able to use by default Kotlin and Swift respectively.

Given this situation we will show you how to use Kotlin and Swift in your projects instead of Java and ObjectiveC.

Initializing the project

In this case we will use Typescript.
For this reason we will execute this command in the terminal to create our project from a typescript template that will already have all the basic configurations of our project

npx react-native init KotlinSwift — template react-native-template-typescript

After creating the project we go to package.json and add this in the scripts part:

“clean”: “watchman watch-del-all && rm -rf $TMPDIR/react-native-packager-cache-* && rm -rf $TMPDIR/metro-bundler-cache-* && rm -rf node_modules/ && yarn cache clean”

This command will allow to remove all the temporary instances that reac-native creates in case we are running different projects and thus there are no conflicts with the metro instance, it will also eliminate all the node_modules and the cache.

After running this script we will always have to run:

yarn install

Android

In the android / build.gradle file we add:

ext {

kotlin_version = ‘VERSION’

}

and

dependencies {

classpath (“org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version”)

}

We should change Version to the Kotlin version to use. ex: 1.3.72

In the file android / app / build.gralde we add at the top

apply plugin: “kotlin-android”

apply plugin: “kotlin-android-extensions”

Now it only remains to change the Java code to kotlin. Go to android / app / src / main and locate the MainActivity.java and delete it. Create a new file called MainActivity.kt with the following code:

import com.facebook.react.ReactActivity

class MainActivity : ReactActivity() {

/**

* Returns the name of the main component registered from JavaScript. This is used to schedule

* rendering of the component.

*/

override fun getMainComponentName(): String? {

return “KotlinSwift”

}

}

The same with the MainApplication.java file, replace it with MainApplication.kt

import android.app.Application

import android.content.Context

import com.facebook.react.*

import com.facebook.soloader.SoLoader

import java.lang.reflect.InvocationTargetException

class MainApplication : Application(), ReactApplication {

private val mReactNativeHost: ReactNativeHost = object : ReactNativeHost(this) {

override fun getUseDeveloperSupport(): Boolean {

return BuildConfig.DEBUG

}

override fun getPackages(): List<ReactPackage> {

// Packages that cannot be autolinked yet can be added manually here, for example:

// packages.add(new MyReactNativePackage());

return PackageList(this).packages

}

override fun getJSMainModuleName(): String {

return “index”

}

}

override fun getReactNativeHost(): ReactNativeHost {

return mReactNativeHost

}

override fun onCreate() {

super.onCreate()

SoLoader.init(this, /* native exopackage */false)

initializeFlipper(this, reactNativeHost.reactInstanceManager)

}

companion object {

/**

* Loads Flipper in React Native templates. Call this in the onCreate method with something like

* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());

*

* @param context

* @param reactInstanceManager

*/

private fun initializeFlipper(

context: Context, reactInstanceManager: ReactInstanceManager) {

if (BuildConfig.DEBUG) {

try {

/*

We use reflection here to pick up the class that initializes Flipper,

since Flipper library is not available in release mode

*/

val aClass = Class.forName(“com.kotlinswift.ReactNativeFlipper”)

aClass

.getMethod(“initializeFlipper”, Context::class.java, ReactInstanceManager::class.java)

.invoke(null, context, reactInstanceManager)

} catch (e: ClassNotFoundException) {

e.printStackTrace()

} catch (e: NoSuchMethodException) {

e.printStackTrace()

} catch (e: IllegalAccessException) {

e.printStackTrace()

} catch (e: InvocationTargetException) {

e.printStackTrace()

}

}

}

}

}

In case of having android studio you can open the project, locate these files and go to code / convert java file to kotlin and this will update all the java code to kotlin. This way is simpler but it is always good to check the autogenerated code since it may have some errors in case of more complex implementations.

IOS

In IOs it is advisable to do it from XCode since it is much easier
The first thing is to create a new file with the name AppDelegate.swift in the following way

After placing the name we must click on Create Bridging Header

This will create a file which will allow us to create a bridge between ObjectiveC and swift to be able to use the APIs implemented in ObjC.

It is a file which will be created automatically and will have the name of the following form:

PROYECT_NAME0-Bridging-Header.h

we will add the following code:

#import “React/RCTBridgeModule.h”

#import “React/RCTBridge.h”

#import “React/RCTEventDispatcher.h”

#import “React/RCTRootView.h”

#import “React/RCTUtils.h”

#import “React/RCTConvert.h”

#import “React/RCTBundleURLProvider.h”

#import “React/RCTViewManager.h”

#import “React/RCTLinkingManager.h”

and in the AppDelegate.swift file we will write the following

import Foundation

import UIKit

@UIApplicationMain

class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

var bridge: RCTBridge!

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

initializeFlipper(with: application)

let bridge = RCTBridge(delegate: self, launchOptions: launchOptions)

let rootView = RCTRootView(bridge: bridge!, moduleName: “KotlinSwift”, initialProperties: nil)

let rootViewController = UIViewController()

rootViewController.view = rootView

self.window = UIWindow(frame: UIScreen.main.bounds)

self.window?.rootViewController = rootViewController

self.window?.makeKeyAndVisible()

return true

}

private func initializeFlipper(with application: UIApplication) {

#if DEBUG

#if FB_SONARKIT_ENABLED

let client = FlipperClient.shared()

let layoutDescriptorMapper = SKDescriptorMapper(defaults: ())

FlipperKitLayoutComponentKitSupport.setUpWith(layoutDescriptorMapper)

client?.add(FlipperKitLayoutPlugin(rootNode: application, with: layoutDescriptorMapper!))

client?.add(FKUserDefaultsPlugin(suiteName: nil))

client?.add(FlipperKitReactPlugin())

client?.add(FlipperKitNetworkPlugin(networkAdapter: SKIOSNetworkAdapter()))

client?.add(FlipperReactPerformancePlugin.sharedInstance())

client?.start()

#endif

#endif

}

}

extension AppDelegate:RCTBridgeDelegate{

func sourceURL(for bridge: RCTBridge!) -> URL! {

return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: “index”, fallbackResource: nil)

}

}

Then we will delete the files:

AppDelegate.h

AppDelegate.m

main.m

we will recompile the app

Product / Clean Build Folder

and later

Product / Build

and that’s it.

we have our ios and android application with swift and kotlin respectively.

repo where you can found the code:

https://github.com/hectorjdgdev/rn_kotlinswift

--

--