はじめまして。Argano の松田です。 本記事では、React Native で JavaScript からネイティブコードを呼び出す方法を紹介します。

Native Module

React Native でアプリを作成する際、次のような要望が出てくるかもしれません。

  • Apple や Google Pay にアクセスするためのネイティブ API など、JavaScript ではデフォルトで利用できないネイティブプラットフォーム API にアクセスする必要がある
  • 既存の Objective-C、Swift、Java、Kotlin、C++ ライブラリを JavaScript で再実装せずに再利用したい
  • 画像処理などのために高性能なマルチスレッドコードを記述したい

そんな時に React Native の Native Module をいう機能を使用できます。 Native Module は、Objective-C、Swift、Java、Kotlin、C++ クラスのインスタンスを JavaScript オブジェクトとして公開し、それによって JavaScript の中から任意のネイティブコードを実行できるようにするものです。 今回は React Native アプリケーション内の JavaScript から ネイティブのメソッドを実行してみます。 最終的には、JavaScript から MyModule.log('Test'); を呼び出し、ネイティブにログ出力できるようにします。

Native Module の作成

環境構築は終わっている前提で進めます。Android の Native Module を作成するには Java か Kotlin を選ぶことができますが、今回は Java を使用します。 ます、android/app/src/main/java/com/your-app-name/ フォルダ内に、MyModule.java ファイルを作成します。

MyModule.java の内容

package com.your-app-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 MyModule extends ReactContextBaseJavaModule {
  MyModule(ReactApplicationContext context) {
    super(context);
  }
  @Override
  public String getName() {
    return "MyModule";
  }
}

Native Module は getName メソッドを実装する必要があります。このメソッドは、Native Module の名前を表す文字列を返します。その名前を使用して JavaScript からアクセスできます。

// JavaScript からアクセス
const { MyModule } = ReactNative.NativeModules;

Native メソッドを JavaScript に書き出す

次に、Native Module にログを出力するメソッドを追加し、JavaScript から呼び出すことができるようにします。JavaScript から呼び出される Native Module のメソッドには、必ず @ReactMethod のアノテーションを付けなければなりません。 MyModule に log メソッドを実装します。

import android.util.Log;
@ReactMethod
public void log(String content) {
  Log.d("MyModule", "Content: " + content);
}

Module の登録

Native Module を書いたら、それを React Native に登録する必要があります。そのためには、Native Module を ReactPackage に追加して、ReactPackage を React Native に登録します。 まず、Native Module を ReactPackage に追加します。android/app/src/main/java/com/your-app-name/ フォルダ内に MyAppPackage.java ファイルを新規に作成します。

MyAppPackage.java の内容

package com.your-app-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 MyModule(reactContext));
    return modules;
   }
}

次に MainApplication.java を編集します。

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

Native Module を JavaScript から呼び出す

JavaScript から Native Module にアクセスするためには、まず React Native から NativeModules をインポートする必要があります。

import { NativeModules } from 'react-native';

そして、NativeModules から MyModule のネイティブモジュールにアクセスできるようになります。

const { MyModule } = NativeModules;

あとは 実装したメソッドを呼び出すだけです。

const onPress = () => {
  MyModule.log('log test');
};

最後に再ビルドを実行します。Native Module を修正した場合は JavaScript を修正した場合と違い、ホットリロードが効かないため注意が必要です。

npx react-native run-android

まとめ

Native Module の基本的な使い方を見てきました。アプリを作る中で使用する機会は少ないかもしれません。しかし、JavaScript での実装ができない場合は、ライブラリを探すか、Native Module を利用することになります。 JavaScript にイベントを送信したり、ライフサイクルメソッドを使用したりすることもできます。 React Native であれど、かなり柔軟にさまざまな要件を満たせそうです。