Implementing Native Code in React Native
Tags: kotlin, swift, reactnative, javascript
Published: 2024-06-04 23:57:18

Hey devs!

React Native is an excellent tool for building mobile applications with a single codebase that can run on both iOS and Android. However, sometimes we need to access platform-specific functionalities that are not available in the standard React Native library. In these situations, we can turn to native code implementations.

In this post, we will explore how to add native functionalities to your React Native application using native packages. We will use the example of a Gallery library, which already has native implementations in Swift for iOS and Kotlin for Android.

### Why Use Native Code?

- **Performance**: Native code can be optimized for the specific platform, offering better performance.
- **Access to Specific APIs**: Some functionalities are only available through native APIs.
- **Integration with Native Libraries**: Use of libraries or SDKs that only exist in native form.

### Setting Up the Environment

Before we start, make sure you have your environment set up for React Native development, including Xcode for iOS and Android Studio for Android.

### Project Structure

Assume we have the following basic structure of a React Native project:

```
my-react-native-app
├── android
├── ios
├── src
│   ├── components
│   ├── screens
│   ├── App.js
├── package.json
```

### Adding Native Code

#### Creating the Native Module

Let's create a native module that exposes gallery functionalities. We'll start with Android using Kotlin.

#### Android (Kotlin)

1- **Create a new Kotlin module:**
   Navigate to `android/app/src/main/java/com/myreactnativeapp/` and create a new directory `gallery`.

2- **Add the Kotlin class:**
   Create a `GalleryModule.kt` file inside the `gallery` directory:

   ```kotlin
   package com.myreactnativeapp.gallery

   import com.facebook.react.bridge.ReactApplicationContext
   import com.facebook.react.bridge.ReactContextBaseJavaModule
   import com.facebook.react.bridge.ReactMethod
   import com.facebook.react.bridge.Promise

   class GalleryModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {

       override fun getName(): String {
           return "GalleryModule"
       }

       @ReactMethod
       fun openGallery(promise: Promise) {
           // Implementation to open the gallery
           promise.resolve("Gallery opened successfully!")
       }
   }
   ```

3- **Register the module:**
   In the same directory, create a `GalleryPackage.kt` file:

   ```kotlin
   package com.myreactnativeapp.gallery

   import com.facebook.react.ReactPackage
   import com.facebook.react.bridge.ReactApplicationContext
   import com.facebook.react.uimanager.ViewManager
   import com.facebook.react.bridge.NativeModule

   class GalleryPackage : ReactPackage {
       override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
           return listOf(GalleryModule(reactContext))
       }

       override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
           return emptyList()
       }
   }
   ```

4- **Update `MainApplication.java`:**
   Add the new package to the list of registered packages:

   ```java
   import com.myreactnativeapp.gallery.GalleryPackage;  // Import the package

   @Override
   protected List<ReactPackage> getPackages() {
       @SuppressWarnings("UnnecessaryLocalVariable")
       List<ReactPackage> packages = new PackageList(this).getPackages();
       packages.add(new GalleryPackage());  // Add the new package
       return packages;
   }
   ```

#### iOS (Swift)

1- **Create the Swift module:**
   Navigate to `ios` and open the project in Xcode. In `ios`, create a new Swift file `GalleryModule.swift` inside the `Libraries` directory.

   ```swift
   import Foundation
   import React

   @objc(GalleryModule)
   class GalleryModule: NSObject {

       @objc
       func openGallery(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
           // Implementation to open the gallery
           resolve("Gallery opened successfully!")
       }
   }
   ```

2- **Update the bridge header:**
   Open `ios/YourProjectName-Bridging-Header.h` and add:

   ```objc
   #import "React/RCTBridgeModule.h"
   ```

3- **Register the module:**
   Open `AppDelegate.m` and add the module registration:

   ```objc
   #import <React/RCTBridge.h>
   #import <React/RCTBridgeModule.h>

   @implementation AppDelegate

   - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
   {
     RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
     [bridge registerModuleForName:@"GalleryModule" withClass:[GalleryModule class]];
     // Rest of the code
   }
   ```

### Using the Native Module in React Native

Now that we have our native modules set up, we can use them in our JavaScript code.

1- **Create a JavaScript file for the module:**
   ```javascript
   // src/nativeModules/GalleryModule.js
   import { NativeModules } from 'react-native';
   const { GalleryModule } = NativeModules;

   const openGallery = async () => {
     try {
       const result = await GalleryModule.openGallery();
       console.log(result);
     } catch (error) {
       console.error(error);
     }
   };

   export { openGallery };
   ```

2- **Use the module in your component:**
   ```javascript
   // src/screens/GalleryScreen.js
   import React from 'react';
   import { View, Button } from 'react-native';
   import { openGallery } from '../nativeModules/GalleryModule';

   const GalleryScreen = () => {
     return (
       <View>
         <Button title="Open Gallery" onPress={openGallery} />
       </View>
     );
   };

   export default GalleryScreen;
   ```

### Conclusion

Adding native code to your React Native application can seem challenging at first, but with the right steps, you can easily extend your app's capabilities to include platform-specific functionalities. This guide has shown how to create and integrate simple native modules for both Android and iOS. With this foundation, you can explore further and add complex functionalities as needed.

### References

1. [React Native Documentation on Native Modules](https://reactnative.dev/docs/native-modules-setup)
2. [React Native Documentation on Integrating with Swift](https://reactnative.dev/docs/native-modules-ios)
3. [React Native Documentation on Integrating with Kotlin](https://reactnative.dev/docs/native-modules-android)

This guide should provide a solid foundation for you to start working with native code in React Native. If you have any questions or run into issues, the React Native community is very active and can be an excellent resource for additional support.