LoginSignup
33
29

More than 5 years have passed since last update.

20分でわかる React Native Modules 開発

Last updated at Posted at 2018-07-24
1 / 37

Native Modules とは?

  • React Native 標準で用意されていない機能をネイティブで作成するための機構
  • iOS:Objective-C(Swiftも可能)、Android:Java(Kotlinも可能)
  • React Native における常套手段かつ最終手段
  • UI がからむ場合は、Native UI Components を使用する

リソース


Native Modules で Native側から、OS名、OSバージョン名を取得する関数の実装を通して説明します。


デモのソース


JavaScript と ネイティブ間のデータの受け渡し

React Native Modules がよしなにマッピングしてくれる

Objective-C Java
string NSString String
number NSInteger,float,double,CGFloat,NSNumber Integer,Double,Float
boolean BOOL,NSNumber Boolean
array NSArray ReadbleArray
object NSDictionary ReadbleMap
function RCTResponseSenderBlock Callback

前提

  • XCode, Android Studio インストール済み(React Nativeの環境構築で入る)
  • react-native init NativeModulesTest

仕様

  • モジュール名

    • DeviceInformation
  • 関数名

    • getOSInfo
  • 返り値

    • 返り値1:OS名
    • 返り値2:Version名
  • 返り値例

    • "iOS", "11.0"
    • "Android", "8.1"

iOS


1分でわかる Objective-C


特徴

  • C言語をベースに開発されたオブジェクト指向言語。
  • Cの記法・ライブラリが全部動く。
  • C言語にコンパイルされるので、激早。関数呼び出しはメッセージ呼び出し的になるのでネイティブCより少し遅い。

// ポインタを利用する。 文字列には、@ をつけて CStringと区別する。
NSString* string = @"hogehoge";
NSArray*  array = @[@"hoge",@"fuga"];
NSDictionary* dictionary = @{@"key1":@"value1",@"key2":@"value2"};

クラス/関数の定義

  • Hoge.h(宣言を書く)
@interface Person : NSObject
-(NSString*)nameWithType:(NSInteger)type;
@end
  • Hoge.m(実装を書く)
@implementation
-(NSString*)nameWithType:(NSInteger)type {
   return type == 0 @"Taro Suzuki" ? @"鈴木太郎";
}
@end

関数呼び出し

[person walk];


ブロック

  • JavaScript でいうクロージャー。
  • 厳密に型の定義がされる
[viewController presentViewController:childViewController animated:YES completion:^{
        NSLog(@"completed");
    }];

手順

① iOS用の プロジェクトを XCode で開く
② ググって OSVersion を取得する関数を調べる
③ DeviceInformation クラスの作成
④ DeviceInformation.h を編集
⑤ DeviceInformation.m を編集
⑥ JavaScript で 作成した Native Module を呼び出す
⑦ 実行


① iOS用の プロジェクトを XCode で開く

プロジェクトルート(NativeModulesTest) > ios > NativeModulesTest.xcodeproj

② ググって OSVersion を取得する関数を調べる

#import <UIKit/UIKit.h>
[UIDevice currentDevice].systemVersion

③ DeviceInformation クラスの作成

  • NativeModuleTest ってなっているぐらいのところで右クリックして New File をクリック
  • Cocoa Touch Class を選択
  • Class のところに DeviceInformation と入力して、右下 Next をクリック
  • ファイルを作成する場所を選んで(そのままでOK)、右下 Create をクリック

④ DeviceInformation.h を編集

#import <Foundation/Foundation.h>

// 次の行を追加
#import <React/RCTBridgeModule.h>

// <RCTBridgeModule> を追加
@interface DeviceInformation : NSObject<RCTBridgeModule>
@end

⑤ DeviceInformation.m を編集

// 次の行を追加。UIDevice クラスを利用するのに必要
#import <UIKit/UIKit.h>
@implementation DeviceInformation
// JavaScript側にこのモジュール(DeviceInformation)を公開するよというマクロ。
// マクロとはC言語系の言語で使われるコンパイル時に置き換えて使用できる関数や定数のこと。
RCT_EXPORT_MODULE();

// JavaScript側に公開する関数の定義。getOSInfo(最初の:まで) が公開される関数名となる。
RCT_EXPORT_METHOD(getOSInfo:(RCTResponseSenderBlock)callback) {
  // callbackに返り値となる値を配列で渡す
  callback(@[@"iOS", [UIDevice currentDevice].systemVersion]);
}
@end

⑥ JavaScript で 作成した Native Module を呼び出す

// 中略
import {NativeModules} from 'react-native';
// 中略
export default class App extends Component<Props> {
  constructor(props:Props) {
    super(props);
    this.state = {osInfo:''};    
    // 定義したモジュール名が、NativeModules に存在するようになる。
    var DeviceInformation = NativeModules.DeviceInformation;
  
    // 定義した関数名で呼び出し。ネイティブ上で callback に渡した引数の値がその順序で引数として渡される。
    DeviceInformation.getOSInfo((os, version) => {
        this.setState({osInfo: `${os} ${version}`});
    });
  }
// 中略
 render() {
    return (
      <View style={styles.container}>
        <Text>OS:{this.state.osInfo}</Text>
// 中略

⑦ 実行

  • XCode 上で Product > Run (Cmd+R)

or

  • react-native run-ios

スクリーンショット 2018-07-25 0.37.14.png


Android



手順

① Android用の Project を Android Studio で開く
② ググって OSVersion を取得する関数を調べる
③ DeviceInformationModule クラスの作成
④ DeviceInformationPackage クラスの作成
⑤ MainApplicationを修正
⑥ JavaScriptの実装(iOSの実装で作成済み)
⑦ 実行


① Android用の Project を Android Studio で開く

  1. Android Studioを起動
  2. Open an Existing Android Studio project を選ぶ
  3. プロジェクトルート(NativeModulesTest) > android ディレクトリを選ぶ
  4. Gradleの設定で、Update してね的なメッセージがでるので迷わずupdate.

② ググって OSVersion を取得する関数を調べる

import android.os.Build;
Build.VERSION.RELEASE

③ DeviceInformationModule クラスの作成

  • app > java > com.nativemoduletest ってなっているぐらいのところで右クリックして New -> 'Java Class' をクリック
  • Nameのところに DeviceInformation 、Superclass に ReactContextBaseJavaModule と入力して OK をクリック
  • Class のところに と入力して、右下 Next をクリック
  • ファイルを作成する場所を選んで(そのままでOK)、右下 Create をクリック

package com.nativemodulestest;

// 次のimportを追加
import android.os.Build;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;

// ReactContextBaseJavaModule を継承する
public class DeviceInformationModule extends ReactContextBaseJavaModule{
    // コンストラクタの定義。super(reactContext)するだけでよい。
    public DeviceInformationModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }
    // getName() を override.この関数の返り値が、JavaScript に公開されるModule名になる。iOSとそろえる。
    @Override
    public String getName() {
        return "DeviceInformation";
    }
  // @ReactMethod というアノテーションを行うことで、JavaScript側に定義したメソッドを公開すること示す。
    @ReactMethod
    public void getOSInfo(Callback callback) {
        // Androidでは、JavaScriptへの返り値を 可変長引数で渡す。
        callback.invoke("android",Build.VERSION.RELEASE);
    }


④ DeviceInformationPackage クラスの作成

DeviceInformationModule と同様に、DeviceInformationPackageクラスを作成

package com.nativemodulestest;

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 DeviceInformationPackage implements ReactPackage {
    // テンプレート的な実装。単に作成したDeviceInformationModule new して modules に追加
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new DeviceInformationModule(reactContext));
        return modules;
    }
  // View を使わない場合は、emptyList を返す
    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

⑤ MainApplicationを修正

// 中略
    @Override
    protected List<ReactPackage> getPackages() {
      return Arrays.<ReactPackage>asList(
          new MainReactPackage(),  
          // 直前の , と 次の行を追加
          new DeviceInformationPackage()
      );
    }

⑥ JavaScriptの実装

iOSで実装済み


⑦ 実行

  • Android Studio上で Run > Run 'app' (Ctrl+R)

or

  • react-native run-android

スクリーンショット 2018-07-25 0.35.35.png


まとめ

だいたいおまじない。実質的に実装したのは次の部分のみ。

  • iOS
RCT_EXPORT_METHOD(getOSInfo:(RCTResponseSenderBlock)callback) {
  callback(@[@"iOS", [UIDevice currentDevice].systemVersion]);
}
  • Android
@ReactMethod
public void getOSInfo(Callback callback) {
    callback.invoke("android",Build.VERSION.RELEASE);
}
33
29
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
33
29