Native Modules | React Native

Bori·2024년 6월 2일

React native

목록 보기
3/3

React Native 앱에서 JavaScript에서 사용할 수 없는 네이티브 플랫폼 API에 접근해야할 때가 있습니다.
Native Modules은 React Native 앱에서 JavaScript 코드와 네이티브 코드 간의 상호 작용을 할 수 있도록 지원합니다.
JavaScript 코드에서 Native Modules을 호출하여, 네이티브 환경에서 수행되는 기능을 실행하고 그 결과를 JavaScript로 반환할 수 있습니다. 이를 통해 React Native 앱에서 네이티브 플랫폼 API에 접근하여 카메라, 위치, 알람 등과 같은 기능을 사용할 수 있습니다.

Native Modules을 작성하는 방법은 여러 가지가 있으나 본 글에서는 React Native 앱의 Android 프로젝트 내부에 직접 구현하는 방법에 대해 알아봅니다.

Android Native Modules

Native Modules을 작성하기에 앞서 안드로이드 스튜디오를 사용해서 코드를 작성하는 것이 좋습니다.

안드로이드 스튜디어를 사용하면 VSCode에서는 나타나지 않던 코드 구문 오류가 나타나고, 누락된 import도 자동완성 기능을 통해 작성할 수 있습니다.

Create A Custom Native Module File

먼저, android/app/src/main/java/com/your-app-name 폴더 내에 Java/Kotlin 파일을 생성합니다.

// android/app/src/main/java/com/mayapp/MyModule.java
package com.mayapp; // 앱 패키지 이름 작성

import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

// MyModule 클래스는 ReactContextBaseJavaModule를 확장하여 JavaScript에서 사용할 기능을 해당 클래스 내부에 구현
public class MyModule extends ReactContextBaseJavaModule {
    MyModule(ReactApplicationContext context) {
        super(context);
    }
}

Java/Kotlin 클래스는 BaseJavaModule 클래스를 확장하거나 NativeModule 인터페이스를 구현하면 React Native에 의해 Native Modules로 간주되지만, ReactContextBaseJavaModule 사용을 추천합니다.

  • ReactContextBaseJavaModule은 ReactApplicationContext (RAC)에 접근할 수 있습니다.
  • RAC에 접근하여 활동 수명 주기 메서드를 사용해야하는 Native Module을 구현할 수 있습니다.

Module Name

Java/Kotlin Native Modules은 getName() 메서드를 구현해야 합니다.
getName() 메서드를 통해 Native Modules의 이름을 반환하고, 반환된 이름으로 JavaScript에서 해당 모듈에 접근할 수 있습니다.

// android/app/src/main/java/com/mayapp/MyModule.java
public class MyModule extends ReactContextBaseJavaModule {
    MyModule(ReactApplicationContext context) {
        super(context);
    }
  
    @Override
    public String getName() {
        return "MyModule";
    }
}
// Component.js
import { NativeModules } from 'react-native';

// JavaScript에서 Native Modules에 접근
const { MyModule } = NativeModules;

Export a Native Method to JavaScript

JavaScript에서 호출할 수 있는 메서드를 Native Modules 내부에 추가합니다.
JavaScript에서 Native Modules 메서드를 호출하기 위해서는 반드시 @ReactMethod 주석이 필요합니다.

// android/app/src/main/java/com/mayapp/MyModule.java
public class MyModule extends ReactContextBaseJavaModule {
    MyModule(ReactApplicationContext context) {
        super(context);
    }
  
    @Override
    public String getName() {
        return "MyModule";
    }

    @ReactMethod
    public void testEvent(String title String description) {
      ...
    }
}
// Component.js
import { NativeModules } from 'react-native';

const Component = () => {
  const { MyModule } = NativeModules; 
  
  const handlePressButton = () => {
    MyModule.testEvent('test', 'It is test!')
  }
  
  ...
}
  
export default Component;

Register the Module (Android Specific)

Native Modules을 작성 후 React Native에 등록합니다.

  • 작성한 Native Modules을 ReactPackage에 추가
  • ReactPackage를 React Native에 등록

초기화 중 React Native는 모든 패키지를 반복하며 각 ReactPackage 내부의 Native Modules을 등록합니다.

Native Modules을 ReactPackage에 추가하기 위해 android/app/src/main/java/com/your-app-name 폴더 내 ReactPackage를 구현하는 새로운 Java/Kotlin 클래스를 생성합니다.

// android/app/src/main/java/com/mayapp/MyAppPackage.java
package com.mayapp;

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

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class MyAppPackage implements ReactPackage {
    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }

    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();

        modules.add(new MyModule(reactContext));

        return modules;
    }
}``

위 파일은 작성된 Native Modules인 MyModule을 가져옵니다.
createNativeModules() 함수 내에서 MyModule을 인스턴스화 하고, React Native에 등록할 NativeModule의 리스트로 반환합니다.

MyModule 패키지를 등록하려면 ReactNativeHostgetPackages() 메서드에서 반환하는 패키지 목록에 MyAppPackage를 추가합니다.

android/app/src/main/java/com/your-app-name 폴더 내의 MainApplication.java 파일을 엽니다.
ReactNativeHostgetPackages() 메서드를 찾아 패키지 목록에 MyAppPackage`를 추가합니다:

@Override
protected List<ReactPackage> getPackages() {
    List<ReactPackage> packages = new PackageList(this).getPackages();
    // 자동 연결이 되지 않은 패키지는 수동으로 추가할 수 있습니다. 예시:
    // packages.add(new MyReactNativePackage());
    packages.add(new MyAppPackage());
    return packages;
}

안드로이드용 기본 모듈 등록 완료!

Test What You Have Built

JavaScript에서 Native Modules에 접근하여 export 된 메서드를 호출합니다.

// Component.js
import React from 'react';
import { NativeModules, Button } from 'react-native';

const Component = () => {
  // NativeModules에서 MyModule에 접근
  const { MyModule } = NativeModules; 
  
  const handlePressButton = () => {
    // MyModule의 testEvent() 메서드 호출
    MyModule.testEvent('test', 'It is test!')
  }

  return (
    <Button
      title="Click to invoke your native module!"
      color="#222222"
      onPress={handlePressButton}
    />
  );
};

export default Component;

마지막으로 새로운 Native Modules이 포함된 최신 네이티브 코드를 사용할 수 있도록 React Native 앱을 다시 빌드합니다.

npm run android

Building as You Iterate

Native Modules를 개발하고 반복 작업할 때, JavaScript에서 최신 변경 사항을 적용하려면 앱을 다시 빌드해야 합니다.
React Native의 메트로 번들러는 JavaScript의 변경사항을 감지하고 실시간으로 다시 빌드할 수 있지만, 네이티브 코드에 대해서는 그렇게 하지 않습니다.
Native Modules은 코드가 네이티브에 위치하기 때문에 네이티브의 최신 변경사항을 적용하기 위해 다시 빌드해야 합니다.

참고

1개의 댓글

comment-user-thumbnail
2025년 2월 3일

아니... 온세상이 보리님이네요

답글 달기