React NativeでモバイルOSのすべての機能を使用する方法

市場には、Cordova、Xamarin、React Nativeなど、あまり知られていないクロスプラットフォームソリューションがいくつかあります。 多くのモバイル開発者は、クロスプラットフォームソリューションでは、ネイティブアプリケーションでできることを実行できないと考えています。







記事では、この神話を解き明かし、React Nativeのメカニズムについて説明します。これにより、ネイティブアプリケーションで可能なすべてのことを実行できます。 このメカニズムはネイティブモジュールです。 Under the cut-AndroidおよびiOS用のネイティブモジュールの作成方法の詳細な説明。







画像







携帯電話向けのクロスプラットフォーム開発のネイティブモジュールは、いくつかのことを支援します。









React Nativeのサンプルアプリケーション図



オペレーティングシステムはネイティブアプリケーションを実行します。 React Nativeランタイムと、アプリケーション開発者(またはReact Nativeのライブラリの作成者)によって作成されたネイティブモジュールのコードは、低レベルで動作します。 その上で、React Native Bridgeは機能します-ネイティブコードとjsの間の中間リンク。 Js自体はJavaScript VM内で実行されるJS VM内で実行されます。 iOSでは、システムによって提供され、Androidでは、アプリケーションはそれをライブラリの形式でドラッグします。







画像







ネイティブモジュールの作成



Androidの下で



計画はこれです:









桁1-Androidコンポーネント



主な背景がAndroidの場合、このリトリートをスキップできます。 基本的なiOSまたはReact JSの経験を持つ開発者の場合、Androidアプリケーションに次のコンポーネントを含めることができることを確認する必要があります。









このコンテキスト(khe-khe)では、もちろん、アプリケーションにのみ興味があります。 このコンポーネントはアプリケーション自体のオブジェクトであることを思い出させてください。 React Nativeアプリケーションの場合は、アプリケーションクラスを実装し、このクラスを使用してReactApplicationインターフェイスを実装できます(およびReact Nativeアプリケーションの場合)。







package com.facebook.react; public interface ReactApplication { ReactNativeHost getReactNativeHost(); }
      
      





これは、ReactNativeが使用したいネイティブパッケージについて学習するために必要です。 これを行うには、アプリケーションはパッケージリストをリストするReactNativeHostのインスタンスを返す必要があります。







 class MainApplication : Application(), ReactApplication { private val mReactNativeHost = object : ReactNativeHost(this) { override fun getPackages(): List<ReactPackage> { return Arrays.asList( MainReactPackage(), NativeLoggerPackage() ) } override fun getReactNativeHost(): ReactNativeHost { return mReactNativeHost } }
      
      





NativeLoggerPackageは、お客様と一緒に作成するパッケージです。 渡された値のみを記録し、実際の機能ではなくネイティブモジュールの作成プロセスに焦点を合わせます。







アプリケーションがReactApplicationを実装する必要があるのはなぜですか? React Nativeの中にはこんな面白いコードがあるからです:







 public class ReactActivityDelegate { protected ReactNativeHost getReactNativeHost() { return ((ReactApplication) getPlainActivity().getApplication()) .getReactNativeHost(); } }
      
      





画像







次に、NativeLoggerPackageを実装します。







 class NativeLoggerPackage : ReactPackage { override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> { return Arrays.asList<NativeModule>(NativeLoggerModule()) } override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> { return emptyList<ViewManager<*, *>>() } }
      
      





createViewManagersメソッドは省略していますが、この記事では重要ではありません。 また、作成されたモジュールのリストを返すcreateNativeModulesメソッドが重要です。 モジュールは、jsから呼び出すことができるメソッドを含むクラスです。 NativeLoggerModuleを作成しましょう:







 class NativeLoggerModule : BaseJavaModule() { override fun getName(): String { return "NativeLogger" } }
      
      





Androidコンテキストにアクセスする必要がない場合は、少なくともBaseJavaModuleからモジュールを継承する必要があります。 必要がある場合は、別の基本クラスを使用する必要があります。







 class NativeLoggerModule(context : ReactApplicationContext) : ReactContextBaseJavaModule(context) { override fun getName(): String { return "NativeLogger" } }
      
      





いずれの場合でも、getName()メソッドを定義する必要があります。このメソッドは、jsでモジュールを使用できる名前を返します。これについては後で説明します。

最後に、jsのメソッドを作成しましょう。 これは、ReactMethodアノテーションを使用して行われます。







 class NativeLoggerModule : BaseJavaModule() { override fun getName(): String { return "NativeLogger" } @ReactMethod fun logTheObject() { Log.d(name, “Method called”) } }
      
      





ここで、jsからの呼び出しにlogTheObjectメソッドが使用可能になります。 しかし、何も返さないパラメータなしでメソッドを呼び出したいだけではありません。 引数を扱いましょう(左側にjavaタイプ、右側にjs):







ブール->ブール

整数->数値

ダブル->数字

フロート->数値

文字列->文字列

コールバック->関数

ReadableMap->オブジェクト

ReadableArray->配列







jsオブジェクトをネイティブメソッドに渡したいとします。 ReadableMapはjavaに含まれます。







 @ReactMethod fun logTheObject(map: ReadableMap) { val value = map.getString("key1") Log.d(name, "key1 = " + value) }
      
      





配列の場合、ReadableArrayが渡され、反復処理が問題になりません。







 @ReactMethod fun logTheArray(array: ReadableArray) { val size = array.size() for (index in 0 until size) { val value = array.getInt(index) Log.d(name, "array[$index] = $value") } }
      
      





ただし、最初の引数でオブジェクトを渡し、2番目の引数で配列を渡したい場合は、ここでも驚くことはありません。







 @ReactMethod fun logTheMapAndArray(map: ReadableMap, array: ReadableArray): Boolean { logTheObject(map) logTheArray(array) return true }
      
      





これをjavascriptから呼び出すにはどうすればよいですか? これ以上簡単なことはありません。 最初に行うことは、react-nativeルートライブラリからNativeModulesをインポートすることです。







 import { NativeModules } from 'react-native';
      
      





そして、モジュールをインポートします(NativeLoggerと呼びましたか?):







 import { NativeModules } from 'react-native'; const nativeModule = NativeModules.NativeLogger;
      
      





これでメソッドを呼び出すことができます:







 import { NativeModules } from 'react-native'; const nativeModule = NativeModules.NativeLogger; export const log = () => { nativeModule.logTheMapAndArray( { key1: 'value1' }, ['1', '2', '3'] ); };
      
      





うまくいく! しかし、待ってください、私はすべてが正常であるかどうか、記録したいものを記録できたかどうかを知りたいです。 戻り値はどうですか?







画像







ただし、ネイティブモジュールからの関数の戻り値はありません。 関数を渡して外に出なければなりません:







 @ReactMethod fun logWithCallback(map: ReadableMap, array: ReadableArray, callback: Callback) { logTheObject(map) logTheArray(array) callback.invoke("Logged") }
      
      





唯一のinvokeメソッド(Object ... args)を持つCallbackインターフェイスは、ネイティブコードに入ります。 js側から見ると、これは単なる関数です。







 import { NativeModules } from 'react-native'; const nativeModule = NativeModules.NativeLogger; export const log = () => { const result = nativeModule.logWithCallback( { key1: 'value1' }, [1, 2, 3], (message) => { console.log(`[NativeLogger] message = ${message}`) } ); };
      
      





残念ながら、コンパイル時にjsのネイティブコードと関数からコールバックパラメーターを検証するツールはありません。注意してください。







幸いなことに、Promisesメカニズムを使用できます。これは、ネイティブコードではPromiseインターフェイスでサポートされています。







 @ReactMethod fun logAsync(value: String, promise: Promise) { Log.d(name, "Logging value: " + value) promise.resolve("Promise done") }
      
      





その後、async / awaitを使用してこのコードを呼び出すことができます。







 import { NativeModules } from 'react-native'; const nativeModule = NativeModules.NativeLogger; export const log = async () => { const result = await nativeModule.logAsync('Logged value'); console.log(`[NativeModule] results = ${result}`); };
      
      





これで、Androidのjsでネイティブメソッドを設定する作業が完了しました。 iOSを見てください。







画像







iOSでネイティブモジュールを作成する



最初に、NativeLogger.hモジュールを作成します。







 #import <Foundation/Foundation.h> #import <React/RCTBridgeModule.h> @interface NativeLogger : NSObject<RCTBridgeModule> @end
      
      





NativeLogger.mの実装:







 #import <Foundation/Foundation.h> #import "NativeLogger.h" @implementation NativeLogger { } RCT_EXPORT_MODULE();
      
      





RCT_EXPORT_MODULEは、モジュールが宣言されているファイルの名前でReactNativeにモジュールを登録するマクロです。 js内のこの名前があまり適していない場合は、変更できます。







 @implementation NativeLogger { } RCT_EXPORT_MODULE(NativeLogger);
      
      





それでは、Androidに対して行ったメソッドを実装しましょう。 これにはパラメーターが必要です。







 string -> (NSString*) number -> (NSInteger*, float, double, CGFloat*, NSNumber*) boolean -> (BOOL, NSNumber*) array -> (NSArray*) object -> (NSDictionary*) function -> (RCTResponseSenderBlock)
      
      





メソッドを宣言するには、RCT_EXPORT_METHODマクロを使用できます。







 RCT_EXPORT_METHOD(logTheObject:(NSDictionary*) map) { NSString *value = map[@"key1"]; NSLog(@"[NativeModule] %@", value); }
      
      





 RCT_EXPORT_METHOD(logTheArray:(NSArray*) array) { for (id record in array) { NSLog(@"[NativeModule] %@", record); } }
      
      





 RCT_EXPORT_METHOD(log:(NSDictionary*) map withArray:(NSArray*)array andCallback:(RCTResponseSenderBlock)block) { NSLog(@"Got the log"); NSArray* events = @[@"Logged"]; block(@[[NSNull null], events]); }
      
      





ここで最も興味深いのは、約束のサポートです。 これを行うには、別のマクロRCT_REMAP_METHODを使用する必要があります。このマクロは、jsのメソッド名を最初の引数として使用し、objective-cのメソッドシグネチャを2番目以降の引数として使用します。

インターフェイスの代わりに、2つの引数が渡されます。約束を解決するためのRCTPromiseResolveBlockと拒否のためのRCTPromiseRejectBlockです。







 RCT_REMAP_METHOD(logAsync, logAsyncWith:(NSString*)value withResolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { NSLog(@"[NativeModule] %@", value); NSArray* events = @[@"Logged"]; resolve(events); }
      
      





以上です。 イベントをネイティブモジュールからjsに送信するメカニズムについては、別の記事で説明します。







ニュアンス





便利なリンク






All Articles