React Native - Android Native Modules

조각 스터디·2023년 2월 15일

ReactNative

목록 보기
2/2

react native Android Native module은 React Native module이 따로 없을 때, 사용하는 Native moudle

-바로 React Native application Android projects에 작성, 아니면 NPM package설치

이 과정은 JS에서 Android CalendarModule로 접근하기 위해서 CalendarModule을 만드는 과정임
Native module을 작성할 때에는 Android studio를 사용하는 것이 code syntax error도 잡을 수 있고 좋음

com.yourAppName 에 java class파일을 하나 만들고

package com.your-app-name; // replace com.your-app-name with your app’s name
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;
import java.util.Map;
import java.util.HashMap;

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

기본 모듈은 ReactContextBaseJavaModule로 확장하고, 필요한 기능을 구현

Module Name
모든 기본 모듈은 getName() 메서드를 구현해야 함

// add to CalendarModule.java
@Override
public String getName() {
   return "CalendarModule";
}
const {CalendarModule} = ReactNative.NativeModules;

 다음과 같이 JS에서 접근 가능

javascript에서 접근할 수 있는 메서드를 만들기

Javascript에서 호출되는 모든 기본 모듈 메서드에 @ReactMethod 주석이 추가

import android.util.Log;

@ReactMethod
public void createCalendarEvent(String name, String location) {
   Log.d("CalendarModule", "Create event called with name: " + name
   + " and location: " + location);
}

동기 메서드로 표시하는 방법으로 isBlockingSynchronousMethod=true 전달

@ReactMethod(isBlockingSynchronousMethod = true)

Native Module이 작성되면 이 모듈을 React Native에 등록해야 된다.
com.yourAppName 에 javaPackage.java 파일을 하나 만들고 그 안에 코드를 작성해 준다.

package com.your-app-name; // replace your-app-name with your app’s name
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 CalendarModule(reactContext));

       return modules;
   }

}

createNativeModules() 함수 내에서 calendarModule을 인스턴스화하고 등록할 NativeModules목록으로 반환, 여기에 추가할 네이티브 모듈을 작성

그리고, CalendarModule Package 를 MainApplication.java 에 등록

@Override
  protected List<ReactPackage> getPackages() {
    @SuppressWarnings("UnnecessaryLocalVariable")
    List<ReactPackage> packages = new PackageList(this).getPackages();
    // below MyAppPackage is added to the list of packages returned
    packages.add(new MyAppPackage());
    return packages;
  }

JS에서 호출해서 사용하는 법!!

import React from 'react';
import {NativeModules, Button} from 'react-native';
const {CalendarModule} = NativeModules;

const NewModuleButton = () => {
  const onPress = () => {
    console.log('We will invoke the native module here!');
    CalendarModule.createCalendarEvent('testName', 'testLocation');
  };

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

export default NewModuleButton;

terminal에 입력

npx react-native run-android
  • JS에서 수정된 사항의 경우에는 저장해주고 다시 빌드하는 것이 가능하지만, native code는 불가능하기 때문에 명령어를 사용하여 재빌드해야함

JAVA로부터 상수 받기

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

JS에서

const {DEFAULT_EVENT_NAME} = CalendarModule.getConstants();
console.log(DEFAULT_EVENT_NAME);

Callback도 사용 가능

import com.facebook.react.bridge.Callback;

@ReactMethod
public void createCalendarEvent(String name, String location, Callback callBack) {
       Integer eventId = ...
       callBack.invoke(eventId);
}

callback은 비동기메서드를 위해 java 에서 javascript로 데이터를 전달하는데 사용

const onPress = () => {
  CalendarModule.createCalendarEvent(
    'Party',
    'My House',
    (eventId) => {
      console.log(`Created a new event with id ${eventId}`);
    }
  );
};

Promise도 사용 가능

import com.facebook.react.bridge.Promise;

@ReactMethod
public void createCalendarEvent(String name, String location, Promise promise) {
    try {
        Integer eventId = ...
        promise.resolve(eventId);
    } catch(Exception e) {
        promise.reject("Create Event Error", e);
    }
}
import com.facebook.react.bridge.Promise;

@ReactMethod
public void createCalendarEvent(String name, String location, Promise promise) {
    try {
        Integer eventId = ...
        promise.resolve(eventId);
    } catch(Exception e) {
        promise.reject("Create Event Error", e);
    }
}

Javscript로 이벤트 보내기

네이티브 모듈 호출 없이 JS로 이벤트 신호를 보낼 수 있음
->RCTDeviceEventEmitter을 사용
-Java-

...
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.Arguments;
...
private void sendEvent(ReactContext reactContext,
                      String eventName,
                      @Nullable WritableMap params) {
 reactContext
     .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
     .emit(eventName, params);
}

private int listenerCount = 0;

@ReactMethod
public void addListener(String eventName) {
  if (listenerCount == 0) {
    // Set up any upstream listeners or background tasks as necessary
  }

  listenerCount += 1;
}

@ReactMethod
public void removeListeners(Integer count) {
  listenerCount -= count;
  if (listenerCount == 0) {
    // Remove upstream listeners, stop unnecessary background tasks
  }
}
...
WritableMap params = Arguments.createMap();
params.putString("eventProperty", "someValue");
...
sendEvent(reactContext, "EventReminder", params);

-JS-

import {NativeEventEmitter, NativeModules} from 'react-native';
...

 componentDidMount() {
   ...
   const eventEmitter = new NativeEventEmitter(NativeModules.ToastExample);
   this.eventListener = eventEmitter.addListener('EventReminder', event => {
      console.log(event.eventProperty) // "someValue"
   });
   ...
 }

 componentWillUnmount() {
   this.eventListener.remove(); //Removes the listener
 }
profile
매일 하나씩 개발 블로그

0개의 댓글