React NativeとiOSの相互作用の詳細な説明

React NativeとiOSの相互作用の詳細な説明

前提条件

まず、ocの文法について少し理解しておくのがベストです。

1. 宣言ファイルnativeModule.hを作成する

#import <Foundation/Foundation.h>
#import <React/RCTBridgeModule.h>

@interface ネイティブモジュール: NSObject <RCTBridgeModule>

@終わり

2. nativeModule.mファイルを作成する

#import <Foundation/Foundation.h>
#"nativeModule.h"をインポートします

@interface ネイティブモジュール ()

@終わり

@実装ネイティブモジュール

@終わり

これはファイルを追加した後のディレクトリ構造です。

インターフェースの違いについて:

.h 内の @interface は他のクラスが呼び出すために使用されます。 @property と関数は他のクラスから「見える」 (public)

.m 内の @interface は OC ではクラス拡張と呼ばれ、.h ファイルの @interface を補足するものです。ただし、.m ファイル内の @interface は外部に公開されておらず、.m ファイル内でのみ表示されます (プライベート)

そのため、外部に公開するメソッドと変数は .h ファイルに配置し、外部に公開したくない変数は .m ファイルに配置します (.m ファイル内のメソッドは宣言なしで直接使用できます)。

RNはiOSに価値を渡す

方法1: ネイティブに通常通り値を渡す

.m ファイルに次のメソッドを追加します。

//上記のコードを省略 @implementation nativeModule

// このコードは、nativeModule モジュールが RN でアクセスできるようにモジュールをエクスポートするために必要です。
RCT_EXPORT_MODULE();

// 文字列を受け取る RCT_EXPORT_METHOD(addHelloWord:(NSString *)name location:(NSString *)location)
{
  NSLog(@"%@,%@", 名前、場所);
}
@終わり

RNコード:

'react-native' から { Button, NativeModules } をインポートします。
const { nativeModule } = ネイティブモジュール

<Button title={'2つのパラメータをネイティブに渡す'} onPress={() => {
    nativeModule.addHelloWord('あなたの名前', '場所: 浙江省')
}}/>

このボタンをクリックすると、「your name」と「location: Zhejiang」の 2 つの文字列がネイティブ側に渡されます。

方法2: コールバック関数を渡す

.m ファイルに追加します:

// 1 つのパラメータ(JavaScript コールバック関数に渡されるパラメータの配列)のみを受け入れます。
RCT_EXPORT_METHOD(checkIsRoot:(RCTResponseSenderBlock)コールバック) {
  NSArray *配列 = @[@"文字列", @"数値"];
  コールバック(配列);
}

RN にコードを追加します:

<Button title={'js はネイティブにコールバックを渡し、コールバックで配列を受け取ります'} onPress={() => {
    nativeModule.checkIsRoot((str: 文字列, num: 文字列) => {
      コンソール.log(文字列、数値)
    })
}}/>

これは、いくつかの操作が完了した後にコールバックを解決するために RN のネイティブ エンドに渡されるコールバック関数です。**コールバックが複数回呼び出されると、RN はエラーを報告します**

方法3: プロミスコールバックを取得する

.m ファイルに次のコードを追加します。

@interface ネイティブモジュール ()

@property (非アトミック) RCTPromiseResolveBlock normalResolve;
@property (非アトミック) RCTPromiseRejectBlock normalReject;
@property (非アトミック) NSInteger num;

@終わり


// これはタイマーです - (void)startTime: (NSArray*) data{
  NSTimer *timer = [NSTimer schedulingTimerWithTimeInterval:2 repeats:YES block:^(NSTimer * _Nonnull timer) {
    
    NSArray *events =@[@"Promise ",@"test ",@" 配列"];
    if (イベント) {
      イベントを通常の状態に戻します。
      [タイマー無効化];
    } それ以外 {
      [タイマー無効化];
      NSError *error=[NSError errorWithDomain:@"エラーメッセージを呼び出しています..." code:101 userInfo:nil];
      self.normalReject(@"no_events", @"イベントはありませんでした", error);
    }
  }];
  
  [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}

// RNへのコールバックパラメータ、コールバックエラー情報 RCT_EXPORT_METHOD(getHBDeviceUniqueID: (RCTPromiseResolveBlock)resolve
                  拒否者:(RCTPromiseRejectBlock)拒否) {
  
  // 実行されるタスク self.normalResolve = resolve;
  自己.normalReject = 拒否;
  
  [self performSelectorOnMainThread:@selector(startTime:) withObject: [NSArray arrayWithObjects: @"1", @"2", nil] waitUntilDone:YES];
}

RN にコードを追加します:

<Button title={'ネイティブはPromiseをJSに渡します'} onPress={() => {
    nativeModule.getHBDeviceUniqueID().then((arr: string[]) => {
      console.log('解決', arr)
    }).catch((err: 文字列) => {
      コンソール.エラー(err)
    })
}}/>

nativeModule.getHBDeviceUniqueID の実行は、ネイティブ側のコールバックを取得できる Promise であり、実際には方法 2 に似ています。

方法4: 同期的にpromiseを取得する方法

.m ファイルに追加します:

// これはタイマー2です
-(void)startTime2: (NSArray*) データ{
  NSLog(@"データ%@",データ);
  
  NSTimer *timer = [NSTimer schedulingTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
    
    NSLog(@"%d", (int)self.num);
    
    自己番号 = 自己番号 + 1;
    
    NSLog(@"%d", (int)self.num);
    
    (自己番号>4)の場合{
      [タイマー無効化];
      NSLog(@"終了");
      データを通常の状態に戻します。
    }
    
  }];
  
  [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}

// RCT_REMAP_METHOD は RCT_EXPORT_METHOD と同じですが、このメソッドは JS スレッド上の JS から同期的に呼び出され、結果を返す場合があります。
// 同期にはパフォーマンス上の問題が生じる可能性があります。RCT_REMAP_METHOD(findEvents, を使用しないことをお勧めします。
                 findEventsWithResolver:(RCTPromiseResolveBlock) 解決する
                 拒否者:(RCTPromiseRejectBlock)拒否)
{
  自己解決を通常の方法で解決します。
  自己.normalReject = 拒否;
  
  
  自己番号 = 0;
  
  [self performSelectorOnMainThread:@selector(startTime2:) withObject: [NSArray arrayWithObjects: @"1", @"2", nil] waitUntilDone:YES];
}

RN 側にコードを追加します。

<Button title={'ネイティブは JS2 に Promise を渡します'} onPress={() => {
    nativeModule.findEvents().then((arr: string[]) => {
      console.log('解決', arr)
    }).catch((err: 文字列) => {
      コンソール.エラー(err)
    })
}}/>

方法 4 は基本的に方法 3 と同じですが、違いが 1 つあります。それは、RCT_REMAP_METHOD がこの方法を使用してコードを同期状態にすることです。

iOSはRNエンドに値を渡す

初期データ提供

appDelegate.m に次のコードを追加します。

NSArray *imageList = @[@"http://foo.com/bar1.png",
                @"http://foo.com/bar2.png"];

NSDictionary *props = @{@"images" : imageList};


RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"learn" initialProperties:props];
// このコード行はすでに存在します。違いは initialProperties:props です。

RN 側に次のように記入します:

// APP を書き換えます。images は iOS によって提供されるデータです。ここではコンテキストを通じてデータを渡します。export default class App extends React.Component<{ images: string[] }> {

  与える() {
    <NativeProps.Provider 値 = {this.props.images}> を返します。
      <AppContainer/>
    </ネイティブプロパティ.プロバイダー>
  }
}

// フックで使用するだけです const images = useContext(NativeProps);

<Text>これはネイティブ側からの初期データです {JSON.stringify(images)}</Text>

イベントリスナーの追加

.m ファイルに次のコードを追加します。

// 監視可能なイベント名 - (NSArray<NSString *> *)supportedEvents
{
  @[@"EventReminder"] を返します。
}


RCT_EXPORT_METHOD(postNotificationEvent:(NSString *)名前)
{
  NSLog(@"カレンダーイベントリマインダーを受信しました");
    [self sendEventWithName:@"EventReminder" 本文:@{@"name": name}];;
}

- (void)calendarEventReminderReceived:(NSNotification *)通知
{
  // これは公式ウェブサイトからの例です NSLog(@"calendarEventReminderReceived");
  NSString *eventName = notification.userInfo[@"name"];
  [self sendEventWithName:@"EventReminder" 本文:@{@"name": eventName}];
}

RCT_EXPORT_METHOD(送信){
  NSDictionary *dict = @{@"name" : @"veuimyzi"};
  
  NSNotification *notification = [[NSNotification alloc] initWithName:@"EventReminder" object:nil userInfo:dict];
  
  [自己カレンダーイベントリマインダー受信:通知];
}

RN にコードを追加します:

const ManagerEmitter = 新しい NativeEventEmitter(nativeModule)

定数[メッセージ、setMsg] = useState([])

// フック内で使用。componentDidMount ライフサイクルに似ている。useEffect(() => {
    const サブスクリプション = ManagerEmitter.addListener(
      「イベントリマインダー」、
      (リマインダー)=> {
        setMsg(前の状態 => {
          prevState.concat(リマインダー.name) を返します
        })
        console.log('これは監視されたEventReminderイベント応答です', reminder.name)
      }
    )

    戻り値 () => {
      サブスクリプション.削除()
    }
}, [])


<Button title={'js はイベントをリッスンし、ネイティブが js に通知を送信できるようにします'} onPress={() => {
    ネイティブモジュールの postNotificationEvent('テスト')
}}/>

<Button title={'js はイベントをリッスンし、ネイティブが js に通知を送信できるようにします'} onPress={() => {
    ネイティブモジュール.Send()
}}/>

{
    msg.map((項目, インデックス) => {
      <テキストキー={item + index}>item:{item}</Text>を返します
    })
}

postNotificationEvent メソッドは最も簡単に使用できます。ネイティブ側で sendEventWithName を呼び出すと、RN リスナーにデータを渡すことができます。

もう 1 つの方法は Send と calendarEventReminderReceived です。1 つは公式 Web サイトからのものです。この例では NSNotification からデータを取得し、Send はデータを calendarEventReminderReceived に渡します。

監視の最適化に関しては、公式サイトにもリンクがあります。時間があるときに見てみてください。.m ファイルに次のコードを追加するだけです。

@実装ネイティブモジュール
{
  bool リスナーがあります。
  // ローカル変数 }

-(void)観察開始{
  リスナーあり = YES;
}

-(void)観察を停止{
  リスナーあり = NO;
}
// リスナーを送信するときに判断を追加します。リスナーがある場合にのみ送信し、ブリッジコードの呼び出しを効果的に削減します。if (hasListeners) { 
    [self sendEventWithName:@"EventReminder" 本文:@{@"name": name}];;
}

要約する

上記コードのリポジトリ: https://github.com/Grewer/learn-rn

ネイティブ側とRN側のやりとりについては、基本的には以上です。もちろん、ネイティブ側でもプロセスなど、より複雑な操作は増えていきます。ブリッジメソッドを書こうとすると、これにたくさん遭遇するでしょう。しかし、上記をマスターすれば、いくつかのサードパーティSDKを呼び出すのに十分です。

以上がReact NativeとIOSの連携についての詳しい説明です。React NativeとIOSの連携についてさらに詳しく知りたい方は、123WORDPRESS.COMの関連記事もぜひご覧ください!

以下もご興味があるかもしれません:
  • 1 つ以上のドメイン名への React axios クロスドメイン アクセス
  • Reactnative-iOS コールバック Javascript メソッド
  • iOS 上の React Native で差分増分アップデートを実装する方法
  • React-Native コンポーネントで NavigatorIOS と ListView を組み合わせる方法
  • iOSネイティブとReactネイティブ間のさまざまなインタラクションのサンプルコード
  • React Native サードパーティ プラットフォーム共有の例 (Android、IOS デュアル プラットフォーム)
  • IOS Reactなどのタイトルが表示されない問題の解決方法
  • React-Native AndroidとiOSアプリは1つのコードで実装します
  • IOS React Native FlexBoxの詳細な説明と例

<<:  Dockerリポジトリの一般的なコマンドの詳細な説明

>>:  CentOS6.5 でファイル共有サービス Samba を構築するチュートリアル

推薦する

Nodejs がイントラネット侵入サービスを実装

目次1. LAN内のプロキシ2. イントラネットの浸透イントラネット侵入とは何ですか?橋プロキシサー...

mysql zipファイルのインストールチュートリアル

この記事では、参考までにMySQL zipファイルをインストールする具体的な方法を紹介します。具体的...

MySQLの権限とインデックスの詳細な説明

mysql の権限とインデックスmysql の最高権限ユーザーは root です。 CREATE U...

MySQL方言の簡単な紹介

データベースはさておき、人生における方言とは何でしょうか?方言とは、ある場所特有の言語です。他の場所...

SWFObjectを使用すると、HTMLにFlashを挿入する際のブラウザ互換性の問題を完全に解決できます。

一緒に学びましょう1. 伝統的な方法コードをコピーコードは次のとおりです。 <object c...

MySQLクエリの基本的なクエリ操作の学習

序文MySQL は最も人気のあるリレーショナル データベース管理システムです。WEB アプリケーショ...

Linux の総合システム監視ツール dstat の詳細な例

オールラウンドなシステム監視ツール dstat dstat は、vmstat、iostat、nets...

Vue.js での $emit の使用に関する詳細な説明

1. 親コンポーネントは props を使用して子コンポーネントにデータを渡すことができます。 2....

Dockerイメージをパッケージ化し、リモートサーバーにプッシュしてk8sにデプロイする方法

目次1. Dockerファイル2. pom 構成3. イメージプッシュ4. k8s デプロイメント前...

a タグにはテキストと画像があります。テキストを非表示にして画像のみを表示するにはどうすればよいでしょうか?

多くの場合、画像を表示する<a>タグのスタイルに遭遇しますが、タグ内にテキストがあり、そ...

NexusはAPIを使用して操作します

Nexus は RestApi を提供していますが、一部の API はまだ Groovy と組み合わ...

MySQLのslave_exec_modeパラメータの詳細な説明

今日、slave_exec_modeというパラメータを偶然見ました。マニュアルの説明から、このパラメ...

Reactの状態管理の3つのルールのまとめ

目次序文No.1 焦点No.2 複雑な状態ロジックの抽出No.3 複数状態操作の抽出要約する序文Re...

JavaScriptの知識ポイントの詳しい説明

目次1. JavaScriptの基礎2. 基本的なJavaScript構文3. JavaScript...

Dockerコンテナのログ処理の詳細な説明

Docker には多くのログ プラグインがあります。デフォルトでは json-file を使用します...