Создаем нативный Android модуль и связываем его с React Native приложением.

Пример нативного Android модуля в React Native приложении.

В этой статье мы создадим нативный Android модуль, который будет возвращать уровень заряда батарейки смартфона в React Native приложение.

Но для начала я советую прочитать не большую статью о том, как работает React Native.

Создаем нативный Android модуль

Готовим основной файл модуля

Открываем проект на React Native и ищем в нем папку
android/app/src/main/java/com/[название вашего проекта]/.

Создаем в ней файл BatteryLevel.java.

// BatteryLevel.java

package com.createnativemodule; // имя пакета вашего приложения

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 BatteryLevel extends ReactContextBaseJavaModule {
  public BatteryLevel(ReactApplicationContext reactContext) {
    super(reactContext);
  }
}

Мы только что создали каркас для нашего модуля. В этом файле мы будем описывать методы, которые хотим использовать из JavaScript.

Для того, чтобы мы смогли обратиться к модулю из JavaScript, нужно добавить обязательный метод getName и указать в нем имя нашего модуля.

// BatteryLevel.java

...
@Override
public String getName() {
  return "BatteryLevel"; // "BatteryLevel" - имя модуля, доступное из JavaScript
}

Пока что модуль не умеет определять уровень заряда батарейки.

Поэтому нужно написать метод getLevel, который определит уровень заряда и передаст его в JavaScript.

// BatteryLevel.java

package com.createnativemodule;

import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
...

...
@ReactMethod
public void getLevel(Callback updateLevelCallback) {
  IntentFilter iFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
  Intent battery = getReactApplicationContext().registerReceiver(null, iFilter);

  int level = battery.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
  int scale = battery.getIntExtra(BatteryManager.EXTRA_SCALE, -1);

  float batteryPercent = level / (float)scale; // значение от 0 до 1

  updateLevelCallback.invoke(batteryPercent); // выполняем callback-метод, переданный из JavaScript и передаем в него значение batteryPercent
}

Хочу заострить ваше внимание на некоторых вещах:

  1. Аннотация @ReactMethod перед методом говорит, что мы можем вызвать этот метод из JavaScript. Это обязательное условие, иначе вы не сможете вызвать этот метод из JavaScript.
  2. Методы, которые мы хотим вызвать из JavaScript, должны иметь возвращаемый тип void. Это значит, что метод ничего не возвращает явным образом, т.е. нет оператора return в конце метода.

Раз метод ничего не возвращает, то как он передаст значение заряда батарейки в JavaScript?

Для этого мы используем callback-метод. Из JavaScript файла мы передадим в метод getLevel функцию, которая должна быть выполнена по его окончании. В нашем случае это updateLevelCallback.

Полный код файла BatteryLevel.java
Полный код файла BatteryLevel.java

Регистрируем модуль

Основная часть модуля готова. Теперь нам нужно зарегистрировать его, чтобы он стал доступен из JavaScript.

Для этого создадим файл-пакет BatteryLevelPackage.java в папке android/app/src/main/java/com/[название вашего проекта]/ и добавим модуль в метод createNativeModules.

// BatteryLevelPackage.java

package com.createnativemodule;

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 BatteryLevelPackage 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 BatteryLevel(reactContext)); // Добавляем модуль в пакет модуля

    return modules;
  }
}
Полный код файла BatteryLevelPackage.java
Полный код файла BatteryLevelPackage.java

Добавляем пакет модуля ко остальным пакетам приложения

Пакет модуля должен быть предоставлен в методе getPackages в файле MainApplication.java. В этом методе через запятую указываются все пакеты нативных модулей, используемых в React Native проекте.

// MainApplication.java
...
import com.createnativemodule.BatteryLevelPackage; // импортируем пакет модуля BatteryLevel
...

...
@Override
protected List<ReactPackage> getPackages() {
  return Arrays.<ReactPackage>asList(
      new MainReactPackage(),
      new BatteryLevelPackage() // добавляем пакет модуля BatteryLevel к остальным
  );
}
...
Полный код файла MainApplication.java
Полный код файла MainApplication.java

Используем нативный Android модуль в React Native приложении

В проекте React Native в файле App.js (вы можете использовать любой другой файл) импортируем NativeModules из пакета ‘react-native’ и достаем из него недавно созданный модуль BatteryLevel.

// App.js

...
import {NativeModules} from 'react-native'; // импортируем NativeModules
...

...
constructor(props) {
  super(props);

  this.state = {
    batteryLevel: 0 // значение заряда батарейки по умолчанию. Дальше мы его обновим, когда получим значение от нативного модуля.
  };
}
...

...
render() {
  let batteryLevel = this.state.batteryLevel.toFixed(2) * 100;

  return (
    <View style={styles.container}>
      <Text style={styles.batteryLevel}>
        Уровень заряда: {batteryLevel}%
      </Text>
      <Button 
        title="Показать уровень заряда" 
        onPress={() => {
          NativeModules.BatteryLevel.getLevel(
            (batteryLevel) => {
              this.setState({batteryLevel: batteryLevel});
            }
          );
        }} 
      />
    </View>
  );
}
...
Полный код файла App.js
Полный код файла App.js

По нажатию на кнопку «Показать уровень заряда», мы вызываем метод getLevel из нативного модуля BatteryLevel и передаем в него функцию с аргументом batteryLevel. Нативный модуль вернет нам значение batteryLevel.

Подытожим

Шаги для создания и использования нативного Android модуля в React Native приложении:

  1. Создаем основной файл модуля в папке android/app/src/main/java/com/[название вашего проекта]/.
  2. Создаем пакет модуля в той же папке и регистрируем модуль.
  3. Добавляем пакет модуля в метод getPackages в файле MainApplication.java.
  4. В React Native проекте в файле App.js (или в другом) импортируем NativeModules из пакета ‘react-native’.
  5. Используем нативный модуль: NativeModules.[имя модуля].[имя метода]().

Задавайте вопросы, указывайте на неточности и делитесь своим опытом в комментариях.

Спасибо за внимание

Советую

Источники информации:
1. https://facebook.github.io/react-native/docs/native-modules-android
2. https://developer.android.com/training/monitoring-device-state/battery-monitoring

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *