Continuous Native Generation(CNG) in React Native: Easing the Development Process With Boilerplate code

Continuous Native Generation(CNG) in React Native: Easing the Development Process With Boilerplate code

React Native has revolutionized mobile app development by enabling developers to build applications for both iOS and Android using a single codebase written in JavaScript. However, bridging the gap between native modules and JavaScript can sometimes be complex and error-prone. This is where Continuous Native Generation (CNG) comes into play, simplifying the integration and management of native code within React Native projects.

Understanding Continuous Native Generation

Continuous Native Generation is a concept and tooling approach aimed at automating the creation and integration of native modules in React Native applications. By continuously generating and updating native code, CNG streamlines the development workflow, reduces manual coding errors, and ensures that native modules are always in sync with the JavaScript code.

How CNG Eases Development Challenges

  1. Automated Native Module Creation: Traditionally, creating native modules requires manually writing code in Java/Kotlin for Android and Objective-C/Swift for iOS. CNG automates this process, generating the necessary boilerplate code and ensuring consistency across platforms.
  2. Synchronization: CNG ensures that any changes made to the JavaScript code are reflected in the native modules automatically. This reduces the risk of discrepancies and bugs that can arise from manual updates.
  3. Improved Productivity: By automating repetitive and error-prone tasks, developers can focus more on building features and less on the intricacies of native code integration.
  4. Consistency: Automated generation ensures that the native modules adhere to best practices and conventions, leading to more maintainable and robust code.
  5. Simplified Debugging: With CNG, the auto-generated code is usually well-structured and easier to understand, making debugging more straightforward.

Simple Example of Continuous Native Generation

To demonstrate how Continuous Native Generation (CNG) can be used to open a native camera and gallery in a React Native application, let’s walk through a complete example. We’ll assume that CNG automates the creation of the necessary bridging code.

For this example, we’ll configure a native module to open the camera and gallery, generate the required native code, and then use it in a React Native app.

Step-by-Step Example

Step 1: Setting Up the Project

First, create a new React Native project:

npx react-native init CameraGalleryExample
cd CameraGalleryExample

Step 2: Install CNG Tool

Assuming we are using a hypothetical CNG tool named react-native-cng, install it via npm or yarn:

npm install react-native-cng --save-dev

Step 3: Define Native Modules in JavaScript

Create a configuration file, cng.config.js, to define the native modules for opening the camera and gallery. Here’s an example configuration:

module.exports = {
  nativeModules: [
    {
      name: 'MediaModule',
      methods: [
        {
          name: 'openCamera',
          returnType: 'void',
          params: []
        },
        {
          name: 'openGallery',
          returnType: 'void',
          params: []
        }
      ]
    }
  ]
};

This configuration specifies that we want to create a native module named MediaModule with two methods: openCamera and openGallery.

Step 4: Generate Native Modules

Run the CNG tool to generate the native modules:

npx react-native-cng generate

This command will generate the necessary native code for both Android and iOS based on the configuration provided.

Step 5: Implement Native Code

Although CNG generates the boilerplate, you’ll need to implement the actual functionality in the native code.

For Android (Java/Kotlin):

  1. Open MediaModule.java in android/src/main/java/com/cameragalleryexample and add the following code

package com.cameragalleryexample;
import android.app.Activity;
import android.content.Intent;
import android.provider.MediaStore;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
public class MediaModule extends ReactContextBaseJavaModule {
    private static final int CAMERA_REQUEST = 1888;
    private static final int GALLERY_REQUEST = 1889;
    MediaModule(ReactApplicationContext context) {
        super(context);
    }
    @Override
    public String getName() {
        return "MediaModule";
    }
    @ReactMethod
    public void openCamera() {
        Activity activity = getCurrentActivity();
        if (activity != null) {
            Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            activity.startActivityForResult(cameraIntent, CAMERA_REQUEST);
        }
    }
    @ReactMethod
    public void openGallery() {
        Activity activity = getCurrentActivity();
        if (activity != null) {
            Intent galleryIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
            activity.startActivityForResult(galleryIntent, GALLERY_REQUEST);
        }
    }
}

For iOS (Objective-C/Swift):

  1. Open MediaModule.m in ios/CameraGalleryExample and add the following code:

#import <React/RCTBridgeModule.h>
#import <UIKit/UIKit.h>
@interface MediaModule : NSObject <RCTBridgeModule>
@end
@implementation MediaModule
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(openCamera) {
  dispatch_async(dispatch_get_main_queue(), ^{
    UIViewController *rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
    UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
    imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
    [rootViewController presentViewController:imagePicker animated:YES completion:nil];
  });
}
RCT_EXPORT_METHOD(openGallery) {
  dispatch_async(dispatch_get_main_queue(), ^{
    UIViewController *rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
    UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
    imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    [rootViewController presentViewController:imagePicker animated:YES completion:nil];
  });
}
@end

Step 6: Use the Generated Module in React Native

With the native modules generated and implemented, you can now use them in your React Native application:

import React from 'react';
import { Button, View } from 'react-native';
import { NativeModules } from 'react-native';
const { MediaModule } = NativeModules;
const App = () => {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Button title="Open Camera" onPress={() => MediaModule.openCamera()} />
      <Button title="Open Gallery" onPress={() => MediaModule.openGallery()} />
    </View>
  );
};
export default App;

Step 7: Build and Run

Finally, build and run your React Native application to see the native camera and gallery modules in action:

npx react-native run-android
npx react-native run-ios

By automating the creation of the bridging code, Continuous Native Generation simplifies the integration of native functionality into React Native applications. This example demonstrates how CNG can be used to create and use native modules for opening the camera and gallery, reducing the need for manual coding and ensuring consistency across platforms.

Reach Out to me!

DISCUSS A PROJECT OR JUST WANT TO SAY HI? MY INBOX IS OPEN FOR ALL