React NativeからAndroid呼び出し(Java)
やりたいこと
React NativeからAndroidの画面を呼び出したいです。
実現したいこと
React Native(JavaScript)の画面からAndroid(Java)の画面に遷移したいです。
ネイティブモジュールを使えばできそうですが、Androidアプリの開発経験すらない初心者ですので、やってみます。 reactnative.dev
全体の流れ
経験者の方には「ネイティブモジュールを使って画面遷移なんて簡単じゃん」と思われそうですが、 当方React NativeはおろかAndroidアプリの開発経験すらないので、あまりイメージが湧きません。 そこで、 Ⅰ. ネイティブモジュールを呼び出してみて Ⅱ. ネイティブモジュールで画面遷移をする という流れで進めていきたいと思います。
以下はReact Nativeのプロジェクトが作成されている前提ですので、プロジェクトがない場合はこちら等をご参照ください。 teisyoku-tabetai.hatenablog.com
Ⅰ. ネイティブモジュール呼び出し
ネイティブモジュールとして呼び出すネイティブコードは、Androidの場合android/app/src/main/java/com/プロジェクト名/ 配下にあります。]
初期の時点で、MainActivity.javaファイルとMainApplication.javaがありますが、それぞれの意味はざっくり以下です。
- MainActivity:React Nativeアプリケーションの起動を制御。アプリケーションのエントリーポイントとなるReactコンポーネントを指定する役割を果たす。
- MainApplication:React NativeプロジェクトのAndroidアプリケーションレベルの設定と初期化を行う。
Androidプロジェクトでアプリケーションを作成する場合、MainActivityは起動する画面になりますが、React Nativeプロジェクトの場合はReact Nativeの画面に関係、つまりAndroidとして別の画面を作るなら別のActivityに書くよ、ということが伝わればここではOKです。
import React from 'react'; import { Text, Button, NativeModules, View, StyleSheet } from 'react-native'; const { AndroidScreen } = NativeModules; //ネイティブモジュール読み込み export default function App() { const onPressExampleButton = () => { AndroidScreen.getAnimalName((animal) => console.log(animal)); }; return ( <View style={styles.container}> <Text style={styles.text}>React Nativeの画面です</Text> <Button title="かわいい動物の名前" onPress={onPressExampleButton} /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, text: { fontSize: 20, textAlign: 'center', margin: 30, }, })
ここで「かわいい動物の名前」ボタンを押すと、JavaScriptのコンソールでかわいい動物の名前が出力されるようにしたいです。 ネイティブブリッジを使うため、Javaにコードを書きます。
- AndroidScreenPackage
package com.integratedandroidscreen; import java.util.ArrayList; import java.util.Collections; import java.util.List; import com.facebook.react.ReactPackage; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.uimanager.ViewManager; public class AndroidScreenPackage 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 AndroidScreenModule(reactContext)); return modules; } }
- MainApplication.java
protected List<ReactPackage> getPackages() { ... packages.add(new com.integratedandroidscreen.AndroidScreenPackage()); // ここだけ追加 ... return packages; }
ビルドして実行すると、 ネイティブコードで記述したgetAnimalNameメソッドが呼ぶことができました。 かなり簡単なことしかしていませんが、以上がReact NativeからJavaコードを呼ぶ流れです。
Ⅱ. Androidの画面へ遷移
App.tsx
import React from 'react'; import { Text, Button, NativeModules, View, StyleSheet } from 'react-native'; const { AndroidScreen } = NativeModules; export default function App() { const onPressExampleButton = () => { AndroidScreen.moveAndroidScreen(); }; return ( <View style={styles.container}> <Text style={styles.text}>React Nativeの画面です</Text> <Button title="Androidの画面へ遷移" onPress={onPressExampleButton} /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', }, text: { fontSize: 20, textAlign: 'center', margin: 30, }, })
画面用のメソッドを追加 - AndroidScreenActivity.java
package com.integratedandroidscreen; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; public class AndroidScreenActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_androidscreen); } }
package com.integratedandroidscreen; import java.util.HashMap; import java.util.Map; import android.content.Intent; import androidx.annotation.NonNull; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.Arguments; import com.facebook.react.modules.core.DeviceEventManagerModule; public class AndroidScreenModule extends ReactContextBaseJavaModule { private static final String REACT_CLASS = "AndroidScreen"; private final ReactApplicationContext reactApplicationContext; public AndroidScreenModule(ReactApplicationContext reactApplicationContext) { super(reactApplicationContext); this.reactApplicationContext = reactApplicationContext; } @Override public String getName() { return "AndroidScreen"; } private String animal = "panda"; // かわいい動物 @ReactMethod public void getAnimalName(Callback callback) { callback.invoke(animal); } }
- AndroidScreenModule
// 以下メソッドを追記 @ReactMethod public void moveAndroidScreen() throws InterruptedException { Intent intent = new Intent(); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setClassName(reactApplicationContext, "com.integratedandroidscreen.AndroidScreenActivity"); reactApplicationContext.startActivity(intent); }
Manifestファイルに以下を追加
<activity android:name="com.integratedandroidscreen.AndroidScreenActivity" android:label="@string/app_name"> </activity>
画面レイアウト用にapp/res/layout/activity_androidscreen_xmlを追加
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".AndroidScreenActivity"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Androidの画面です" android:textSize="34sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
gradleに以下を追加(レイアウト用に別途必要となったため)
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
ビルドして再実行することで、冒頭に示した画面遷移を実現することができました。