Pull to refresh

Как подружить React Native и Java код на Android

Reading time4 min
Views5.3K
Необходимость работы с нативной частью приложения React Native обычно возникает тогда, когда какой-либо сервис не имеет специального api для RN. Таким образом, хороший разработчик должен уметь, как минимум, представление того, как работает нативная часть приложения. В данной статье будут приведены примеры работы взаимодействия приложения React Native c Android.

Нативный модуль


Для начала создадим новый класс в папке android/app/src/main/java класс CustomModule:

package com.awesomeproject;
import android.widget.Toast;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

import java.util.Map;
import java.util.HashMap;

public class CustomModule extends ReactContextBaseJavaModule {
    CustomModule (ReactApplicationContext context) {
        super(context);
        reactContext = context;
    }

    @Override
    public String getName() {
        return "CustomModule";
    }

    private static ReactApplicationContext context;
}

Данный класс содержит обязательный метод getName(). Именно по тому имени, который вернет данный метод можно получить доступ к нативному модулю из кода Javascript (об этом далее).
Обратим также внимание на то, что конструктор класса принимает контекст приложения в качестве аргумента. Контекст приложения необходим, когда мы хотим взаимодействуем с компонентами Android.

Создадим метод класса CustomModule, который будет вызываться из кода Javascript:

@ReactMethod
    public void show(String message, int duration) {
        Toast.makeText(context,"Hello world", Toast.LENGTH_LONG).show();
    }

Заметим, что для того, чтобы метод был доступен в RN, необходимо использовать декоратор “@ReactMethod”.

Класс Toast — компонент Android, который может вызывать всплывающее сообщение снизу с помощью метода show().

Связь модуля с приложением Android


После того, как был создан модуль, его необходимо поместить в пакет (“package”).

Создадим пакет в том же пространстве имен:

package com.awesomeproject;

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 CustomPackage 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 CustomModule(reactContext));
        return modules;
    }

}

Интерфейс “ReactPackage” содержит два обязательных метода: “createNativeModules” и “createViewManagers”. View manager в коде RN — это компонент. Наш модуль будет использовать функции и не является ui компонентом Android и поэтому помещен в метод “createNativeModules”.

Примечание: один пакет может содержать несколько модулей.

Дальше, пакет необходимо связать с приложением Android следующим образом:

    //MainApplication.java

@Override
    protected List<ReactPackage> getPackages() {
      @SuppressWarnings("UnnecessaryLocalVariable")
      List<ReactPackage> packages = new PackageList(this).getPackages();
      packages.add(new CustomPackage());
      return packages;
    }

Использование модуля в коде Javascript


Теперь попробуем вызвать метод “show()” в приложении RN:

const App = () => {
  NativeModules.ToastExample.show();
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={styles.scrollView}>
          <Text>text</Text>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

Результат:



Обмен данными между приложениями RN и Android


Теперь, осуществим обмен данными между приложениями. Создадим в классе CustomModule два новых метода, для нахождения суммы:

      @ReactMethod
    public void sum(int a, int b, Promise res) {
        try {
            res.resolve(a+b);
        } catch (IllegalViewOperationException e) {
            res.resolve(e);
        }
    }

@ReactMethod
    public void sum(float a, float b, Callback success, Callback fail) {
        try {
            success.invoke((a+b));
        } catch (IllegalViewOperationException e) {
            fail.invoke(e.getMessage());
        }
    }

Переменные “a” и “b” будут приходить из кода Javascript и необходимо помнить про соответствие типов данных между Java и JS:



Примечание: так как типу Number соответствует сразу несколько типов из Java мы используем перегрузку, создав два метода с одним названием, но разными типами параметров.

Чтобы вернуть данные в код JS модуль com.facebook.react.bridge содержит типы Promise и CallBack.

Теперь используем метод в Js:

const showRes = async () => {
const res = NativeModules.SendDataToRN.sum(400, 250);
   alert(res);
};

const App = () => {
   React.useEffect(() => {
	showRes();
   }, [])

  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={styles.scrollView}>
          <Text>text</Text>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

Результат:



Заключение


Материалы статьи можно использовать во всех ситуациях, когда api для rn еще не написано. Как видно из примеров, обмен данными между приложениями — достаточно простая операция, не требующая глубоких знаний программирования на Java.
Tags:
Hubs:
Rating0
Comments0

Articles