LoginSignup
8
10

More than 5 years have passed since last update.

React NativeからObjective-Cのコードを呼ぶ方法(Native Modules)

Last updated at Posted at 2016-01-15

Native Modulesについて

React Nativeを使えばJavaScriptでネイティブアプリを作ることができます。

ただ、各OSの全APIを呼べるわけではないですし、Objective-CやSwift書いた既存のコードを使いたい場面もあります。

そのために用意されているNative Modulesという仕組みを試してみました。
React Native official document: Native Modules

minimumなsampleはここが分かりやすかったです。
Objective-C側で作成したNSStringをReact Nativeで出力するだけです。
React Native - Super Simple Native Module Example

Native Moduleの実装

NSURLProtocolを使って広告ブロックを実装

参考記事: iOSアプリ中のUIWebviewで広告ブロック(Objective-C)

上記の記事ではNSURLProtocolを使ってUIWebviewに広告ブロック機能を実装しています。

React NativeにはNSURLProtocolを呼ぶAPIが存在しないため、Native Moduleを使ってWebViewに広告ブロック機能を実装してみます。

Objective-Cのコードでは、広告ブロックのロジックを実装したFilteredURLProtocolを以下のコードでNSURLProtocolに設定しています。
*詳しくは元記事をご覧ください。

[NSURLProtocol registerClass:FilteredURLProtocol.class];

これをReact Nativeから呼んであげればOKということです。

ブリッジ用Classの作成

ブリッジ用にAdblockManager Classを作成します。

ブリッジで使用するClassはRCTBridgeModuleプロトコルを継承する必要があります。

AdblockManager.h
#import "RCTBridgeModule.h"

@interface AdblockManager : NSObject<RCTBridgeModule>

@end

React Nativeから呼び出せるメソッドの作成にはRCT_EXPORT_METHOD()マクロを使います。

ブリッジ呼び出ししたメソッドは非同期なので返り値が必要な場合はcallbackで渡します。

AdblockManager.m
#import "AdblockManager.h"
#import "FilteredURLProtocol.h"
@implementation AdblockManager


RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(setAdblock:(RCTResponseSenderBlock)callback)
{
  [NSURLProtocol registerClass:FilteredURLProtocol.class];
  NSString* result = @"setAdblock";
  callback(@[result]);

}

RCT_EXPORT_METHOD(unsetAdblock:(RCTResponseSenderBlock)callback)
{
  [NSURLProtocol unregisterClass:FilteredURLProtocol.class];
  NSString* result = @"unsetAdblock";
  callback(@[result]);
}
@end

React Native側からの呼び出し

NativeModulesをimportします。

WebViewのmount時に登録、unmount時に登録解除します。

SimpleWebView.js
import React, {Component} from 'react-native';
import {AdblockManager} from 'NativeModules';
const {
  StyleSheet,
  View,
  WebView
} = React;

export default class SimpleWebView extends Component{

  componentWillMount(){
    if (this.props.adblock){
      AdblockManager.setAdblock((result) => {
        console.log(result);
      });
    }
  }

  componentWillUnmount() {
    if (this.props.adblock){
      AdblockManager.unsetAdblock((result) => {
        console.log(result);
      });
    }
  }

  render(){
    return (
      <View style={styles.container}>
        <WebView url={this.props.url} startInLoadingState={true}/>
      </View>
    );
  }
}

let styles = StyleSheet.create({
  container: {
    flex: 1
  }
});

メソッドを呼び出すだけならこれだけです。
思っていたよりもかなり簡単でした。

UIが絡むとどうなるんでしょうね。

ソースはこちら。
https://github.com/enu-kuro/ReactNative-Adblock-WebView

React Nativeを触ってみた感想

起動させるまでがしんどかったです。
githubからサンプルコードを落としてきても簡単には起動してくれません。
ググッてググッてゴニョゴニョしてやっと起動できましたが、心に余裕がないと起動する前に諦めてしまいそうです・・・。
一通り罠を通ったので最近は起動まではなんとかできることが多くなりました。

作っていると謎の挙動によくぶち当たります。
情報がまだ少ないので解決できないで別の方法で回避しなくてはならないことがあったりします。
例えばNavigatorIOSのtitleやpropsが更新されてくれないとか。
そのせいでサンプルに作ったコードもやや無理やりな実装になっている部分があります。
(現在FacebookはAndroidでも使用できるNavigatorを使用するようにしておりNavigatorIOSのメンテはしていないとのことです)

JavaScriptだけで簡単なアプリは作れてしまいますが、iOSでの実装の仕組みを知っていないと細かい挙動を実装するのは難しいかなと思いました。
ListViewのDataSourceとか。

StoryBoardが使えないので複雑なアプリになるとUIや画面遷移管理はしんどそうです。
CSSかけないのでつらいです。

iPhone6で操作する分にはパフォーマンスはまったく気になりませんでした。
(追記: と思いましたがいろいろ触っていると挙動がぎこちなくなってきました。使用メモリがどんどん増えているのでメモリリークしているようです。メモリはまったく意識せずに作っていたのですがどうすればいいのでしょうね・・・。)

お疲れ様でした。

8
10
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
8
10