LoginSignup
1
1

More than 5 years have passed since last update.

[React Native] 設定.appを開くNativeModuleを作った

Last updated at Posted at 2015-05-24

ReactNativeで作ったアプリから、設定.appにジャンプしたい!ので、
Native Module を書きました。※ただしジャンプできるのはiOS8のみ

React Native はまだまだ発展途上なので、重箱の隅をつつきたいときは、Objective-Cのコード(Native Modules)を書く必要があります。
少なくとも実装した当時はまだReactNative公式では提供してなかったので、自分で作りました。

なお、設定.appの値を読み込むNative Modulesも作ったのですが、コミットした5日後に公式にもっとちゃんとしたNative Moduleが追加されてました。。。

あと、NativeModuleでPromiseを返す機能も検討されているようです。楽しみです。
[Bridge] Add support for JS async functions to RCT_EXPORT_METHOD


以下は、Native Moduleを作った時の流れのメモです。

設定.appを開く(Objective-C)

iOS 5以前では開けたらしいのですが、iOS 6,7は開けず、iOS 8以降からは開けるようです。
今回、iOS 5以前は対象外としてます。

設定.appを開くには以下のようにします。

  NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
  BOOL result = [[UIApplication sharedApplication] openURL:url];
  if (result) { /* 成功 */ } else { /* 失敗 */ }

iOS8未満では UIApplicationOpenSettingsURLString を使おうとするとクラッシュ?するらしいので、以下のコードでiOSのバージョンを判定します。

  UIDevice *device = [UIDevice currentDevice];
  NSString *versionStr = [device systemVersion];
  NSString *versionSupportedOpening = @"8.0";
  NSComparisonResult resultCompare = [[device systemVersion]
                                       compare:versionSupportedOpening
                                       options:NSNumericSearch];
  if (resultCompare != NSOrderedDescending) {
    // iOS 8.0 未満
  } else {
    // iOS 8.0 以上
  }

Objective-CのコードをNative Modulesとして書く

公式資料(Native Modules (iOS))を参考にブリッジを書きます。
資料を読めばだいたいわかります、が、iOSアプリを作り慣れてない自分は引っかかったので細かい補足をしていきます。

.h, .mファイルの追加

モジュールを追加するには、まずXcodeで新しいファイルを追加します。
[iOS] - [Source] - [Cocoa Touch Class] を選びましょう。
言語にObjective-Cを選べば、いい感じに.hと.mファイルを生成してくれます。

ここではOpenSettingAppModuleという名前で作成します。

RCTBridgeModuleプロトコル

Native Modlues は、RCTBridgeModuleプロトコルに従った実装が必要です。
具体的には以下の3点が必要になります。

  • 親クラスを NSObject から NSObject <RCTBridgeModule> に変更。
  • .m ファイル内で、RCT_EXPORT_MODULE();を呼び出す。
  • .m ファイル内で、jsから呼び出すメソッドを定義する。
    • RCT_EXPORT_METHOD(メソッド名:引数...){実装}
OpenSettingAppModule.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "RCTBridgeModule.h"
#import "RCTLog.h"

@interface OpenSettingAppModule : NSObject<RCTBridgeModule>

@end
CalendarManager.m
#import "OpenSettingAppModule.h"

@implementation OpenSettingAppModule

RCT_EXPORT_MODULE();

/**
 * Javascriptからの呼び出しは以下のとおり。
 *   OpenSettingAppModule.openSettingsApp(callback);
 */
RCT_EXPORT_METHOD(openSettingsApp:(RCTResponseSenderBlock)callback)
{
  /* Objective-Cで行いたい処理 */
}

@end

RCT_EXPORT_METHOD() で定義できる引数の型

リテラルや関数、配列、マップが使えます。
詳しくは公式のArgument Typesをみてください。

実装例

以上を踏まえて実装すると、以下のようになります。
ログを出力したいときは"RCTLog.h"をインポートして、RCTLogInfo()などで出力できます。

CalendarManager.m
RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(canOpenSettingsApp:(RCTResponseSenderBlock)callback)
{
  if (/* iOS8以上? */) {
    /* コールバックに渡す引数は、1つでも配列として渡す必要あり */
    callback(@[true]);
  } else {
    callback(@[false]);
  }
  RCTLogInfo(@"Finish");
}

RCT_EXPORT_METHOD(openSettingsApp:(RCTResponseSenderBlock)callback)
{
  /* 設定.appを開く処理 */
  if (/* 成功 */) {
    callback(@[@true]);
  } else {
    callback(@[@false]);
  }
  RCTLogInfo(@"Finish");
}

@end

jsからNative Modulesを呼び出す

ここまでやって、やっとjsから処理を利用できます。

require

まず、React Nativeのモジュール(NativeModules)をrequireします。

var React = require('react-native');
var {
  ...,
  NativeModules,
} = React;

次に、今回追加したNativeModule(OpenSettingAppModule)をrequireします。

var {
  OpenSettingAppModule,
} = NativeModules;

実行

NativeModule内で定義したRCT_EXPORT_METHOD(){}の処理を呼び出します。

OpenSettingAppModule.openSettingsApp((result) => {
  /* 設定.appを開いた後の行いたい処理 */
});

古い生javascriptしか知らない自分でもわかるように書くと、以下のようになります。

var callback = function(result) {
  /* 設定.appを開いた後の行いたい処理 */
}
OpenSettingAppModule.openSettingsApp(callback);

実装例

実際の実装は以下です。とんでもなく汚いです。

1
1
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
1
1