iOS static
此篇是為了註記iOS static
需求
因為是希望把跟server註冊APNs token這段拿到React Native JS Code這邊做掉,所以需要APNs token的取得和通知(當token更新或者其他原因更換了..得通知到JS Code) ps.這裡的通知就是上方的寫法內容
因為怕ios Native已取得token,而後JS Code才監聽(addListener)完成,所以這邊為了保險一點,在iOS Native內加上static參數去儲存token,並且在App第一次開啟時先去獲取一次該static token
還有加上EventEmitter測試的Code
完整Code如下
APNsTokenEmitter.h
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
@interface APNsTokenEmitter : RCTEventEmitter<RCTBridgeModule>
@property (nonatomic, retain) NSString *apnsToken;
- (void)apnsTokenReceive:(NSString *)token;
@end
APNsTokenEmitter.m
#import "APNsTokenEmitter.h"
#import <React/RCTLog.h>
@implementation APNsTokenEmitter
{
bool hasListeners;
}
RCT_EXPORT_MODULE();
@synthesize apnsToken;
/**
想再其它.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
{
self.apnsToken = token;
if (hasListeners) {
[self sendEventWithName:@"APNsToken" body:token];
RCTLogInfo(@"APNsTokenEmitter apnsTokenReceive(Has Listener), %@", token);
}else {
RCTLogInfo(@"APNsTokenEmitterapnsTokenReceive(No Listener), %@", token);
}
}
@end
AppDelegat.h
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@end
AppDelegat.m(內包含註冊APNs token的code,詳細還是參考註冊那篇文章)
#import "AppDelegate.h"
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import "APNsTokenEmitter.h"
#import "Orientation.h"
#import "SplashScreen.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
NSLog(@"Requesting permission for push notifications..."); // iOS 8
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:
UIUserNotificationTypeAlert | UIUserNotificationTypeBadge |
UIUserNotificationTypeSound categories:nil];
[UIApplication.sharedApplication registerUserNotificationSettings:settings];
} else {
NSLog(@"Registering device for push notifications..."); // iOS 7 and earlier
[UIApplication.sharedApplication registerForRemoteNotificationTypes:
UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeSound];
}
// ????去掉這段 螢幕就黑的... (這段應該是我自己寫的Alert啊..
NSURL *jsCodeLocation;
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"AllPayPassRN"
initialProperties:nil
launchOptions:launchOptions];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
//why...
[SplashScreen show]; // 添加这一句,这一句一定要在最后
return YES;
}
- (void)application:(UIApplication *)application
didRegisterUserNotificationSettings:(UIUserNotificationSettings *)settings
{
NSLog(@"Registering device for push notifications..."); // iOS 8
[application registerForRemoteNotifications];
}
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)token
{
//將token parser好
NSString * deviceTokenString = [[[[token description]
stringByReplacingOccurrencesOfString: @"<" withString: @""]
stringByReplacingOccurrencesOfString: @">" withString: @""]
stringByReplacingOccurrencesOfString: @" " withString: @""];
NSLog(@"Registration successful, bundle identifier: %@, mode: %@, device token: %@",
[NSBundle.mainBundle bundleIdentifier], [self modeString], deviceTokenString);
//pass deviceTokenString to function and sending events to javascript
[self sendAPNsTokenToJS:deviceTokenString];
}
- (void)application:(UIApplication *)application
didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
NSLog(@"Failed to register: %@", error);
}
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier
forRemoteNotification:(NSDictionary *)notification completionHandler:(void(^)())completionHandler
{
NSLog(@"Received push notification: %@, identifier: %@", notification, identifier); // iOS 8
completionHandler();
}
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)notification
{
NSLog(@"Received push notification: %@", notification); // iOS 7 and earlier
}
- (NSString *)modeString
{
#if DEBUG
return @"Development (sandbox)";
#else
return @"Production";
#endif
}
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return [Orientation getOrientation];
}
//write function
-(void)sendAPNsTokenToJS:(NSString *)token
{
APNsTokenEmitter *tokenEmitter = [APNsTokenEmitter allocWithZone:nil];
[tokenEmitter apnsTokenReceive:token];
}
@end
AllPayPassMethod.h (這是我曝露給RN Code的Module)
//匯入RCTBridgeModule標頭
#import <React/RCTBridgeModule.h>
//宣告AllPayPassMethod類別是NSObject的子類別並實作RCTBridgeModule界面,以@end結束界面得宣告。
@interface AllPayPassMethod : NSObject <RCTBridgeModule>
@end
AllPayPassMethod.m
#import "AllPayPassMethod.h"
#import <React/RCTLog.h>
#import "IntellaSDK/IntellaSDK.h"
#import "APNsTokenEmitter.h"
//@implementation 與 @end 行表示於之間的內容是AllPayPassMethod的類別實作。
@implementation AllPayPassMethod
// To export a module named AllPayPassMethod。叫用RN的巨集已讓此類別可被RN存取
RCT_EXPORT_MODULE();
//同樣的,bridgeTest :str的方法定義也已RCT_EXPORT_METHOD巨集前綴,他匯出此方法已顯露給我們的js程式。
//每個參數名稱包含在方法名稱中。
RCT_EXPORT_METHOD(bridgeTest:(NSString*) str){
RCTLogInfo(@"bridgeTest, %@", str);
}
RCT_EXPORT_METHOD(getPhoneOnlyNumber: (RCTResponseSenderBlock)callback){
NSString *UDID=[allpaylib getUDID];
// NSLog(@"UDID=%@",UDID);
callback(@[UDID]);
}
RCT_EXPORT_METHOD(emitterAPNsTokenTest:(NSString*) str){
RCTLogInfo(@"emitterAPNsTokenTest, %@", str);
APNsTokenEmitter *tokenEmitter = [APNsTokenEmitter allocWithZone:nil];
[tokenEmitter apnsTokenReceive:str];
}
RCT_EXPORT_METHOD(getAPNsToken:(RCTResponseSenderBlock)callback){
APNsTokenEmitter *tokenEmitter = [APNsTokenEmitter allocWithZone:nil];
RCTLogInfo(@"getAPNsToken, %@", tokenEmitter.apnsToken);
if(tokenEmitter.apnsToken == nil) {
callback(@[@""]);
}else {
callback(@[tokenEmitter.apnsToken]);
}
}
@end
RN JS Code (只貼部分code)
import {NativeModules, NativeEventEmitter} from 'react-native’
const {APNsTokenEmitter, AllPayPassMethod} = NativeModules
...
componentDidMount() {
AllPayPassMethod.getAPNsToken((token) => console.log(`token來也~~${token}`))
this.eventEmitter = new NativeEventEmitter(NativeModules.APNsTokenEmitter);
this.eventEmitter.addListener('APNsToken', (token) => console.log(`token來也~~${token}`))
}
...
componentWillUnmount() {
subscription.remove();
}
Last updated