728x90

 

Native Module은 Native 코드를 javascript 코드로 연동하는 작업이다.

해당 작업을 하는 이유는 반드시 사용해야 할 SDK 및 라이브러리가 네이티브인 경우가 대다수이다. 

다른 이유는 성능 때문일 수도 있겠다. 성능에 관해 무거운 작업일 경우 네이티브로 작업을 하는 경우 아무대로 번들링 되는 과정이 없다 보니 그럴 수도 있겠는데.. (이 경우로 직접 모듈화를 해보지는 않아 개인적인 지표는 없어, 혹시 경험하신 분 있으시면 공유주시면 감사하겠습니다. ㅎㅎ)

 

 

간단하게 모듈화하는 과정을 Android부터 해보자.

 

// android/app/src/main/java/com
// ModuleTest.java

package com.reactnativenativemodulesample; // 앱 패키지 네임으로 변경할 것
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.util.Map;
import java.util.HashMap;

import android.util.Log;

// 모듈화하여 보낼 패키지

public class ModuleTest extends ReactContextBaseJavaModule {
    ModuleTest(ReactApplicationContext context) {
        super(context);
    }

//    모듈 네이밍 선언
    @Override
    public String getName() {
        return "ModuleTest";
    }

//    아래 이하로 함수 선언문s
    @ReactMethod
    public void onHandleNativeEvent() {
        Log.d("ModuleTest", "Create event called with name");
    }

    @Override
    public Map<String, Object> getConstants() {
        final Map<String, Object> constants = new HashMap<>();
        constants.put("DEFAULT_EVENT_NAME", "New Event");
        return constants;
    }

}

네이티브 코드의 구현부이다. 샘플이니까 간단히 구현하였다..

getName()에서 return이 해당 Module의 이름이다. js로 따지면 export한 거라고 생각하면 된다.

 

 

 

// android/app/src/main/java/com
// MyAppPackage.java

package com.reactnativenativemodulesample; // 앱 패키지 네임으로 수정할 것

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 ModuleTest(reactContext));

        return modules;
    }
}

만든 모듈화들을 패키지화시키는 과정이다.

여러개가 된다면 ArrayList에 여러개를 묶어 보낼 수 있다.

 

 

 

 

// android/app/src/main/java/com
// MainApplication.java

package com.reactnativenativemodulesample;

import android.app.Application;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.defaults.DefaultReactNativeHost;
import com.facebook.soloader.SoLoader;
import java.util.List;

public class MainApplication extends Application implements ReactApplication {

  private final ReactNativeHost mReactNativeHost =
      new DefaultReactNativeHost(this) {
        @Override
        public boolean getUseDeveloperSupport() {
          return BuildConfig.DEBUG;
        }

        @Override
        protected List<ReactPackage> getPackages() {
          @SuppressWarnings("UnnecessaryLocalVariable")
          List<ReactPackage> packages = new PackageList(this).getPackages();
          // 패키지한 부분을 MainApplication에 연결
            packages.add(new MyAppPackage());
          return packages;
        }

        @Override
        protected String getJSMainModuleName() {
          return "index";
        }

        @Override
        protected boolean isNewArchEnabled() {
          return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
        }

        @Override
        protected Boolean isHermesEnabled() {
          return BuildConfig.IS_HERMES_ENABLED;
        }
      };

  @Override
  public ReactNativeHost getReactNativeHost() {

    return mReactNativeHost;
  }

  @Override
  public void onCreate() {
    super.onCreate();
    SoLoader.init(this, /* native exopackage */ false);
    if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
      // If you opted-in for the New Architecture, we load the native entry point for this app.
      DefaultNewArchitectureEntryPoint.load();
    }
    ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
  }
}

주석의 설명대로 MainApplication에 모듈화된 패키지를 연결해준다.

이러면 React Native단으로 연동이 되었다.

 

 

 

import React, {useState, useEffect} from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  View,
  NativeModules,
  Button,
  Text,
} from 'react-native';

import {Header} from 'react-native/Libraries/NewAppScreen';

function AosContainer() {
  const [testState, setTestState] = useState('');

  const {ModuleTest} = NativeModules;

  const onHandleNativeEvent = () => {
    // 단순한 Log가 찍히는 함수
    // 동작 권한만 RN단으로 전달한 것이기 때문에 네이티브에서 동작한다. 때문에 Log가 네이티브단에서 확인 가능함
    ModuleTest.onHandleNativeEvent();
  };

  const onHandlePropsValue = () => {
    // 네이티브단에서 객체를 만들어 RN단으로 전달
    // 때문에 console로 찍었을 때 값이 전달되어 console 시에 값이 전달된 것이 확인 가능
    console.log(ModuleTest.getConstants().DEFAULT_EVENT_NAME);
  };

  // 랜더링 시점과 네이티브 모듈 관련 데이터를 들고 올 때 테스트
  // 네이티브 모듈로 들고 온 데이터에 대해서 useEffect를 하여도 이상 없음
  useEffect(() => {
    setTestState(ModuleTest.getConstants().DEFAULT_EVENT_NAME);
  }, [ModuleTest]);

  return (
    <SafeAreaView>
      <StatusBar />
      <ScrollView contentInsetAdjustmentBehavior="automatic">
        <Header />
        <View>
          <Text style={{textAlign: 'center'}}>{testState}</Text>
          <Button title="Call In Native Code" onPress={onHandleNativeEvent} />
          <Button
            title="Call In React Native Code"
            onPress={onHandlePropsValue}
          />
        </View>
      </ScrollView>
    </SafeAreaView>
  );
}

export default AosContainer;

 

NativeModules를 import하여 내부를 뜯어보면 모듈들이 담아져있을 것이다.

이를 확인하는 코드들이고 주석이 설명해주고 있다.

 

 

 

 

 

 

다음 포스팅에는 iOS를 모듈화해보자.

 

 

(아래는 전체 구현 코드 github 주소입니다. 도움 되셨으면 좋겠습니다!)

 

https://github.com/bluetg2001/RN_NativeModule_SampleApp/settings

 

728x90
복사했습니다!