Wifi信号值可以正常获取,SIM卡的信号值是通过私有API获取的,如果正常使用,App Store恐怕会拒绝上架。
一,React To iOS
1,新建一个继承于NSObject的类,.m文件需要导入两个RN框架
#import
#import
@interface RNCalliOSAction ()
@end
2,在.m文件实现
@implementation RNCalliOSAction
/*
一旦RCT_EXPORT_MODULE();声明该类是EXPORT_MODULE,那么该类的实例已经创建好了.如果你在其他地方创建这个类的实例(alloc 或 new),会导致,RN不能正确识别该类的实例.
*/
RCT_EXPORT_MODULE();
注意RCT_EXPORT_MODULE()括号内如果为空,默认就是当前类名。可以根据自己需求,填写在RN代码中接收的对象名称
3,接收方法
第一种没有回调的
RCT_EXPORT_METHOD(calliOSActionWithObject:(id)object) {
NSLog(@"%@", object);
}
第二种有回调的
RCT_EXPORT_METHOD(calliOSActionWithCallBack:(RCTResponseSenderBlock)callBack) {
NSString *string=@"hello";
NSArray *array=@[@"RN",@"and",@"iOS"];
NSString *end=@"goodbay";
//更多参数放到数组中进行回调
callBack(@[string,array,end]);
}
4,RN中的实现
let RNCalliOSAction = NativeModules.RNCalliOSAction
RNCalliOSAction.calliOSActionWithParams('Hello iOS')
复制过去,即可默认导入“NativeModules”
注意NativeModules.RNCalliOSAction中的“RNCalliOSAction”就是接收RN消息的iOS文件类名,如果在2中括号内有填写,那么用括号内填写的名称。
二,iOS To React
过时的方法我们不讲,我介绍Xcode中不报警告的写法。
第一步获取网络信号质量值并且主动发出通知传递出去。
.h文件。
#import
#define TYZ_NETWORK_ADDRESS @"www.apple.com"
/**
* 控制信号值类型的数值
*/
#define WIFIValueLow -80
#define WIFIValueHigh -60
#define SIMValueLow 20
#define SIMValueHigh 60
#define NetTool [TYZNetworkingTool initial]
/**
* 网络连接类型
*/
typedef NS_ENUM(NSInteger, NetworkType) {
NetworkType_None = 0,
NetworkType_Wifi = 1,
NetworkType_2G = 2,
NetworkType_3G = 3,
NetworkType_4G = 4,
NetworkType_5G = 5, // 5G网络还未定义
};
/**
* 信号强度类型
*/
typedef NS_ENUM(NSInteger, NetworkIntensity) {
NetworkIntensity_Default = 0, // 没有信号
NetworkIntensity_Low = 1, // wifi:<-80 SIM:<20
NetworkIntensity_Mid = 2, // wifi:-80~-70 SIM:20~60
NetworkIntensity_High = 3, // wifi:>-70 SIM:>60
};
@interface TYZNetworkingTool : NSObject
/**
* 网络连接类型
*/
@property(nonatomic, assign) NetworkType networkType;
/**
* 信号强度类型
*/
@property(nonatomic, assign) NetworkIntensity networkIntensity;
/**
* 初始化
*/
+ (instancetype)initial;
@end
.m文件
#import "TYZNetworkingTool.h"
#import
#import
#import "Reachability.h"
#import "RNCalliOSAction.h"
#import "iOSCallRNAction.h"
@interface TYZNetworkingTool ()
@property (nonatomic, strong) Reachability *reachability;
#warning 测试用
@property(nonatomic, assign) NSInteger count;
@end
@implementation TYZNetworkingTool
+ (instancetype)initial {
static dispatch_once_t onceToken;
static TYZNetworkingTool *instance = nil;
dispatch_once(&onceToken,^{
instance = [[TYZNetworkingTool alloc] init];
[instance monitorNetworkState];
});
return instance;
}
- (void)monitorNetworkState {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:)name:kReachabilityChangedNotification object: nil];
NSString *remoteHostName = TYZ_NETWORK_ADDRESS;
self.reachability = [Reachability reachabilityWithHostName:remoteHostName];
[self.reachability startNotifier];
}
- (void)reachabilityChanged:(NSNotification *)notification{
Reachability *curReach = [notification object];
NSParameterAssert([curReach isKindOfClass: [Reachability class]]);
NetworkStatus status = [curReach currentReachabilityStatus];
switch (status) {
case NotReachable:
NSLog(@"====当前网络不可达=======");
self.networkType = NetworkType_None;
break;
default:
NSLog(@"====当前网络连接中=======");
self.networkType = [self networkStateType];
break;
}
}
- (NetworkType)networkStateType {
UIApplication *app = [UIApplication sharedApplication];
NSArray *subviews = [[[app valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];
for (id subview in subviews) {
if ([subview isKindOfClass:NSClassFromString(@"UIStatusBarDataNetworkItemView")]) {
int networkType = [[subview valueForKeyPath:@"dataNetworkType"] intValue];
self.networkIntensity = [self getSignalLevelWithType:networkType subview:subview];
switch (networkType) {
case 1:
return NetworkType_2G;
case 2:
return NetworkType_3G;
case 3:
return NetworkType_4G;
case 5:
return NetworkType_Wifi;
default:
return NetworkType_None;
}
}
}
return NetworkType_None;
}
- (NetworkIntensity)getSignalLevelWithType:(NSInteger)networkType subview:(NSDictionary *)subview {
if (networkType == 0) {
return NetworkIntensity_Default;
} else if (networkType == 5) {
int networkIntensity = [[subview valueForKeyPath:@"wifiStrengthRaw"] intValue];
NSLog(@"networkIntensity: %d", networkIntensity);
if (networkIntensity > WIFIValueHigh) {
return NetworkIntensity_High;
} else if (networkIntensity > WIFIValueLow) {
return NetworkIntensity_Mid;
} else {
return NetworkIntensity_Low;
}
} else {
// 此API是apple私有API,所以只可运用在越狱设备中,如果提交appstore,会遭遇apple的拒绝上架反馈!
void *libHandle = dlopen("/System/Library/Frameworks/CoreTelephony.framework/CoreTelephony",RTLD_LAZY);//获取库句柄
int (*CTGetSignalStrength)(void); //定义一个与将要获取的函数匹配的函数指针
CTGetSignalStrength = (int(*)(void))dlsym(libHandle,"CTGetSignalStrength"); //获取指定名称的函数
if(CTGetSignalStrength == NULL) {
return NetworkIntensity_Default;
} else {
int level = CTGetSignalStrength();
NSLog(@"level: %d", level);
dlclose(libHandle); //切记关闭库
if (level > SIMValueHigh) {
return NetworkIntensity_High;
} else if (level > SIMValueLow) {
return NetworkIntensity_Mid;
} else {
return NetworkIntensity_Low;
}
}
}
}
- (void)setNetworkType:(NetworkType)networkType {
_networkType = networkType;
self.count = 0;
}
- (void)setCount:(NSInteger)count {
_count = count;
if (count % 2 == 0) {
[CallRN callToReactWithNameNumber:1 body:@{@"key" : @"Hello React"}];
} else {
[self sendReactWithNetworkStateChanged];
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.count ++;
});
}
- (void)sendReactWithNetworkStateChanged {
NSDictionary *dict = @{
@"NETWORKTYPE" : @(self.networkType),
@"SIGNALLEVEL" : @(self.networkIntensity)
};
[self sendDataToReactWithBody:dict];
}
- (void)sendDataToReactWithBody:(NSDictionary *)body {
[CallRN callToReactWithNameNumber:0 body:body];
}
@end
在这里已经向React发出两个传值的通知了。当self.count为偶数时发出一个测试用的通知,当self.count为奇数时,向React传递了当前的网络信号类型和信号值类型。React接收到以后,就可以直接处理了。
下面一步一步来处理发送和接收的核心
1,iOS端发送
.h文件。发送的通知类型只能是既定的宏,这些通知名称会被加入一个数组中。
“TYZSingleton.h”是单例宏文件
#import
#import "TYZSingleton.h"
#define CallRN [iOSCallRNAction sharediOSCallRNAction]
/**
* 以下宏即是所有发出的通知名称
*/
#define CallToRNNotication1 @"NetworkState"
#define CallToRNNotication2 @"notification2"
#define CallToRNNotication3 @"notification3"
#define CallToRNNotication4 @"notification4"
@interface iOSCallRNAction : RCTEventEmitter
TYZSingleto_h(iOSCallRNAction)
/**
向React发送通知
@param number 第几个通知
@param body 参数
*/
- (void)callToReactWithNameNumber:(NSInteger)number body:(NSDictionary *)body;
@end
.m文件
#import "iOSCallRNAction.h"
@interface iOSCallRNAction ()
/**
* 通知连接第几个
*/
@property(nonatomic, assign) NSInteger number;
/**
* 通知连接类型
*/
@property(nonatomic, strong) NSArray *reactNotifications;
@end
@implementation iOSCallRNAction
TYZSingleto_m(iOSCallRNAction)
- (NSArray *)reactNotifications {
if (_reactNotifications == nil) {
_reactNotifications = @[
CallToRNNotication1,
CallToRNNotication2,
CallToRNNotication3,
CallToRNNotication4
];
}
return _reactNotifications;
}
RCT_EXPORT_MODULE();
- (NSArray *)supportedEvents {
return self.reactNotifications;
}
- (void)startObserving {
[self.reactNotifications enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(emitEventInternal:) name:obj object:nil];
}];
}
- (void)stopObserving {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)emitEventInternal:(NSNotification *)notification {
[self sendEventWithName:self.reactNotifications[self.number] body:notification.object];
}
- (void)callToReactWithNameNumber:(NSInteger)number body:(NSDictionary *)body {
if (number < self.reactNotifications.count) {
self.number = number;
[[NSNotificationCenter defaultCenter] postNotificationName:self.reactNotifications[self.number] object:body];
}
}
@end
已经写成了单例“- (void)stopObserving”不起作用
2,React端接收
const nativeBridge = NativeModules.iOSCallRNAction;
const NativeModule = new NativeEventEmitter(nativeBridge);
复制过去,会默认导入“NativeModules”和“NativeEventEmitter”
在需要处理的地方接收传递过来的值
componentDidMount() {
let RNCalliOSAction = NativeModules.RNCalliOSAction
RNCalliOSAction.calliOSActionWithParams('Hello iOS')
this.listener1 = NativeModule.addListener('NetworkState', (data)=>{
console.log('Hello RN:'+ data.NETWORKTYPE + ' ' + data.SIGNALLEVEL)
})
this.listener2 = NativeModule.addListener('notification2', (data)=>{
console.log('Hello RN:'+ data.key)
})
}
其他人介绍一种更简便的方法“[self.bridge.eventDispatcher sendAppEventWithName:@"getSelectDate" body:@{@"SelectDate":str_date}]”Xcode报警告,而且调用不灵活。经过我上面的封装,任何地方都可以调用传值的方法,不会对其它功能造成影响。