Необходимость работы с нативной частью приложения 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.