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 を構築するチュートリアル

推薦する

MySQL DDLステートメントの使用

序文SQL の言語分類には主に以下の種類があります。 DDLデータ定義言語作成、削除、変更データ定義...

WEB 標準ウェブページ構造

背景画像でも、ページ上のテキストサイズでも、1 ピクセルの違いは非常に明白です。そして、私は学生時代...

MySQL 5.7.17 圧縮バージョンのインストールノート

この記事では、参考までにMySQL 5.7.17圧縮版のインストール手順を紹介します。具体的な内容は...

Nginx キャッシュ設定例

Web アプリケーションの開発とデバッグを行う際には、テストのためにブラウザのキャッシュをクリアした...

フロントエンドネットワーク、JavaScriptの最適化、開発のヒントについて簡単に説明します。

1. ネットワークの最適化YSlowには23のルールがあります。これら数十のルールは、主に、不要な...

vue-cropper を使用して vue で写真をトリミングする方法をご存知ですか?

目次1. インストール: 2. 使用方法: 3. 組み込みメソッド: 4. 使用方法:要約する公式サ...

州と市町村の連携を簡単に実現するJavaScript

この記事では、省と市の簡単な連携を実現するためのJavaScriptの具体的なコードを参考までに紹介...

JavaScriptプロトタイプと例の詳細な説明

目次コンストラクタインスタンスとプロトタイプの関係プロトタイププロパティ属性またはメンバーの検索原則...

JavaScript BOMの構成と一般的なイベントの詳細な説明

目次1. 部品2. BOMの構成2. ウィンドウオブジェクトの共通イベント1. ウィンドウ読み込みイ...

React refの使用例

目次refとは何かrefの使い方DOM要素に配置するクラスコンポーネントに配置する関数コンポーネント...

Vue で動的パラメータと計算プロパティを使用する方法

1. 動的パラメータ2.6.0 以降では、角括弧で囲まれた JavaScript 式をディレクティブ...

MySQL テーブル名の大文字と小文字の選択

目次1. 大文字と小文字の区別を決定するパラメータ2. パラメータ変更に関する注意事項要約: 1. ...

MySQL でサーバーのインストールを開始できない場合の解決策について簡単に説明します。

コンピュータに初めて MySQL をインストールする場合、通常このエラー メッセージは表示されません...

Tudou.com フロントエンドの概要

1. 分業とプロセス<br />Tudou.comでは、プロジェクト開発が中核であり、誰...

MySQL レプリケーションの利点と原則を詳しく説明します

レプリケーションとは、マスター データベースの DDL および DML 操作をバイナリ ログを介して...