# EventEimtter - iOS

### 要用到的有以下檔案

* APNsTokenEmitter.h - EventEmitter的標頭檔
* APNsTokenEmitter.m - EventEmitter 實作
* Use.h - 要暴露給JS Code使用的標頭檔）
* Use.m(要使用的.m檔案內) - 要暴露給RN JS Code使用的實作（這邊我是把EventEmitter封裝進此檔案內
* rnJsCode.js (RN的JS code) - 使用EventEimtter的JS Code

\
**新建檔案(New File) APNsTokenEmitter.h**

```
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>

@interface APNsTokenEmitter : RCTEventEmitter<RCTBridgeModule>
- (void)apnsTokenReceive:(NSString *)token;
@end
```

\
**新建檔案(New File) APNsTokenEmitter.m**

```
#import "APNsTokenEmitter.h"
#import <React/RCTLog.h>

@implementation APNsTokenEmitter
{
  bool hasListeners;
}

RCT_EXPORT_MODULE();

/**
 想再其它.m檔內使用，得先取得APNsTokenEmitter，但用下方方法初始化會有Error
  APNsTokenEmitter * tokenEmitter = [[APNsTokenEmitter alloc] init];

 請參考 https://github.com/facebook/react-native/issues/15421 解法（singleton pattern）
 **/
+ (id)allocWithZone:(NSZone *)zone {
  static APNsTokenEmitter *sharedInstance = nil;
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    sharedInstance = [super allocWithZone:zone];
  });
  return sharedInstance;
}

-(NSArray<NSString *> *)supportedEvents
{
  return @[@"APNsToken"];
}

// Will be called when this module's first listener is added.
-(void)startObserving {
  RCTLogInfo(@"APNsTokenEmitter startObserving");
  hasListeners = YES;
  // Set up any upstream listeners or background tasks as necessary
}

// Will be called when this module's last listener is removed, or on dealloc.
-(void)stopObserving {
  RCTLogInfo(@"APNsTokenEmitter stopObserving");
  hasListeners = NO;
  // Remove upstream listeners, stop unnecessary background tasks
}

-(void)apnsTokenReceive:(NSString *)token
{
  if (hasListeners) {
    [self sendEventWithName:@"APNsToken" body:token];
    RCTLogInfo(@"APNsTokenEmitter apnsTokenReceive(Has Listener), %@", token);
  }else {
    RCTLogInfo(@"APNsTokenEmitterapnsTokenReceive(No Listener), %@", token);
  }
}

@end
```

ps. startObserving 和 stopObserving fun為優化，詳請參考 [官網此網址](https://facebook.github.io/react-native/docs/native-modules-ios.html#optimizing-for-zero-listeners)

\
**要使用的.m檔案內**

```
#import "AppDelegate.h"

#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>

#import “APNsTokenEmitter.h"

@implementation AppDelegate

...

- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)token
{
    //將token parser好
   NSString * deviceTokenString = [[[[token description]
                                    stringByReplacingOccurrencesOfString: @"<" withString: @""]
                                   stringByReplacingOccurrencesOfString: @">" withString: @""]
                                  stringByReplacingOccurrencesOfString: @" " withString: @""];

   //pass deviceTokenString to function and sending events to javascript
   [self sendAPNsTokenToJS:deviceTokenString];
}

//call APNsTokenEmitter
-(void)sendAPNsTokenToJS:(NSString *)token
{
  APNsTokenEmitter *tokenEmitter = [APNsTokenEmitter allocWithZone:nil];
  [tokenEmitter apnsTokenReceive:token];
}

....

@end
```

\
**JS code**

```
import { NativeEventEmitter, NativeModules } from 'react-native'
const {APNsTokenEmitter} = NativeModules

...

componentDidMount() {
    this.eventEmitter = new NativeEventEmitter(NativeModules.APNsTokenEmitter);
    this.eventEmitter.addListener('APNsToken', (token) => console.log(`token來也～～${token}`))
}

...

componentWillUnmount() {
    subscription.remove();
}
```

### 參考

* [Sending Events to JavaScript - 官網](https://facebook.github.io/react-native/docs/native-modules-ios.html#sending-events-to-javascript)
* [Listening for events in react native ios - stackoverflow](https://stackoverflow.com/questions/36092903/listening-for-events-in-react-native-ios)
* [原生模塊向JS傳遞數據的幾種方式](https://github.com/crazycodeboy/RNStudyNotes/blob/master/React%20Native%E5%8E%9F%E7%94%9F%E6%A8%A1%E5%9D%97%E5%90%91JS%E4%BC%A0%E9%80%92%E6%95%B0%E6%8D%AE%E7%9A%84%E5%87%A0%E7%A7%8D%E6%96%B9%E5%BC%8F/React%20Native%E5%8E%9F%E7%94%9F%E6%A8%A1%E5%9D%97%E5%90%91JS%E4%BC%A0%E9%80%92%E6%95%B0%E6%8D%AE%E7%9A%84%E5%87%A0%E7%A7%8D%E6%96%B9%E5%BC%8F.md#%E4%B8%89%E7%A7%8D%E6%96%B9%E5%BC%8F%E7%9A%84%E4%BC%98%E7%BC%BA%E7%82%B9)
