Skip to content

Commit

Permalink
1. added the VPN status check method; solved the status issue in the …
Browse files Browse the repository at this point in the history
…VPN case

2. refactor the demo
  • Loading branch information
dustturtle committed Jun 13, 2018
1 parent 87e8573 commit fc628c4
Show file tree
Hide file tree
Showing 6 changed files with 438 additions and 57 deletions.
9 changes: 9 additions & 0 deletions RealReachability/RealReachability.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
///We post self to this notification, then you can invoke currentReachabilityStatus method to fetch current status.
extern NSString *const kRealReachabilityChangedNotification;

extern NSString *const kRRVPNStatusChangedNotification;

typedef NS_ENUM(NSInteger, ReachabilityStatus) {
///Direct match with Apple networkStatus, just a force type convert.
RealStatusUnknown = -1,
Expand All @@ -54,6 +56,7 @@ typedef NS_ENUM(NSInteger, WWANAccessType) {
@optional
/// TODO:通过挂载一个定制的代理请求来检查网络,需要用户自己实现,我们会给出一个示例。
/// 可以通过这种方式规避解决http可用但icmp被阻止的场景下框架判断不正确的问题。
/// (Update: 已经添加了判断VPN的相关逻辑,以解决这种场景下大概率误判的问题)

This comment has been minimized.

Copy link
@xms1000

xms1000 Mar 19, 2019

如果使用路由器ss代理导致路由icmp受限的情况如何判断

/// 此方法阻塞?同步返回?还是异步?如果阻塞主线程超过n秒是不行的。
/// 当CustomAgent的doubleCheck被启用时,ping的doubleCheck将不再工作。
/// TODO: We introduce a custom agent to check the network by making http request, that need
Expand Down Expand Up @@ -117,4 +120,10 @@ typedef NS_ENUM(NSInteger, WWANAccessType) {
*/
- (WWANAccessType)currentWWANtype;

// Sometimes people use VPN on the device.
// In this situation we need to ignore the ping error.(VPN usually do not support ICMP.)
// 目前内部使用轮询来实现,并没有监听,如果谁知道如何监听,请告诉我:)。
//
- (BOOL)isVPNOn;

@end
115 changes: 107 additions & 8 deletions RealReachability/RealReachability.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
// Copyright © 2016 Dustturtle. All rights reserved.
//

#include <ifaddrs.h>

#import "RealReachability.h"
#import "FSMEngine.h"
#import "LocalConnection.h"
Expand All @@ -26,7 +28,13 @@

NSString *const kRealReachabilityChangedNotification = @"kRealReachabilityChangedNotification";

NSString *const kRRVPNStatusChangedNotification = @"kRRVPNStatusChangedNotification";

@interface RealReachability()
{
BOOL _vpnFlag;
}

@property (nonatomic, strong) FSMEngine *engine;
@property (nonatomic, assign) BOOL isNotifying;

Expand All @@ -41,6 +49,7 @@ @interface RealReachability()

/// for double check
@property (nonatomic, strong) PingHelper *pingChecker;

@end

@implementation RealReachability
Expand Down Expand Up @@ -73,6 +82,8 @@ - (id)init
_autoCheckInterval = kDefaultCheckInterval;
_pingTimeout = kDefaultPingTimeout;

_vpnFlag = NO;

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(appBecomeActive)
name:UIApplicationDidBecomeActiveNotification
Expand Down Expand Up @@ -182,6 +193,17 @@ - (void)reachabilityWithBlock:(void (^)(ReachabilityStatus status))asyncHandler
return;
}

// special case, VPN on; just skipping (ICMP not working now).
if ([self isVPNOn])
{
ReachabilityStatus status = [self currentReachabilityStatus];
if (asyncHandler != nil)
{
asyncHandler(status);
}
return;
}

__weak __typeof(self)weakSelf = self;
[self.pingHelper pingWithBlock:^(BOOL isSuccess)
{
Expand Down Expand Up @@ -215,13 +237,20 @@ - (void)reachabilityWithBlock:(void (^)(ReachabilityStatus status))asyncHandler
}
else
{
// delay 1 seconds, then make a double check.
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1*NSEC_PER_SEC));
__weak __typeof(self)weakSelf = self;
dispatch_after(time, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
__strong __typeof(weakSelf)self = weakSelf;
[self makeDoubleCheck:asyncHandler];
});
if ([self isVPNOn])
{
// special case, VPN connected. Just ignore the ping result.
}
else
{
// delay 1 seconds, then make a double check.
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1*NSEC_PER_SEC));
__weak __typeof(self)weakSelf = self;
dispatch_after(time, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
__strong __typeof(weakSelf)self = weakSelf;
[self makeDoubleCheck:asyncHandler];
});
}
}
}];
}
Expand Down Expand Up @@ -290,7 +319,7 @@ - (WWANAccessType)currentWWANtype
{
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)
{
CTTelephonyNetworkInfo *teleInfo= [[CTTelephonyNetworkInfo alloc] init];
CTTelephonyNetworkInfo *teleInfo = [[CTTelephonyNetworkInfo alloc] init];
NSString *accessString = teleInfo.currentRadioAccessTechnology;
if ([accessString length] > 0)
{
Expand Down Expand Up @@ -445,5 +474,75 @@ - (void)localConnectionHandler:(NSNotification *)notification
}
}

// TODO: 这里比较特别;最终决定采用提供一个外部调用方法;不提供kvo;整合应用内部的状态变化的通知提供到外部。
// 这样一个综合的策略来实现。 kvo不适合用在这里,只有get方法会操作数据(没有真正意义上的set)。
// 而如果获取用一个方法,而kvo又是另外一个的话又会很怪异.
- (BOOL)isVPNOn
{
BOOL flag = NO;
NSString *version = [UIDevice currentDevice].systemVersion;
// need two ways to judge this.
if (version.doubleValue >= 9.0)
{
NSDictionary *dict = CFBridgingRelease(CFNetworkCopySystemProxySettings());
NSArray *keys = [dict[@"__SCOPED__"] allKeys];
for (NSString *key in keys) {
if ([key rangeOfString:@"tap"].location != NSNotFound ||
[key rangeOfString:@"tun"].location != NSNotFound ||
[key rangeOfString:@"ipsec"].location != NSNotFound ||
[key rangeOfString:@"ppp"].location != NSNotFound){
flag = YES;
break;
}
}
}
else
{
struct ifaddrs *interfaces = NULL;
struct ifaddrs *temp_addr = NULL;
int success = 0;

// retrieve the current interfaces - returns 0 on success
success = getifaddrs(&interfaces);
if (success == 0)
{
// Loop through linked list of interfaces
temp_addr = interfaces;
while (temp_addr != NULL)
{
NSString *string = [NSString stringWithFormat:@"%s" , temp_addr->ifa_name];
if ([string rangeOfString:@"tap"].location != NSNotFound ||
[string rangeOfString:@"tun"].location != NSNotFound ||
[string rangeOfString:@"ipsec"].location != NSNotFound ||
[string rangeOfString:@"ppp"].location != NSNotFound)
{
flag = YES;
break;
}
temp_addr = temp_addr->ifa_next;
}
}

// Free memory
freeifaddrs(interfaces);
}

if (_vpnFlag != flag)
{
// reset flag
_vpnFlag = flag;

// post notification
__weak __typeof(self)weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
[[NSNotificationCenter defaultCenter] postNotificationName:kRRVPNStatusChangedNotification
object:strongSelf];
});
}

return flag;
}

@end

17 changes: 17 additions & 0 deletions testRealReachability.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
8EE0B63C1C40F71900CBABCA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8EE0B63A1C40F71900CBABCA /* Main.storyboard */; };
8EE0B63E1C40F71900CBABCA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8EE0B63D1C40F71900CBABCA /* Assets.xcassets */; };
8EE0B6411C40F71900CBABCA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8EE0B63F1C40F71900CBABCA /* LaunchScreen.storyboard */; };
8EF6153420CFEDD100D425CD /* NSObject+SimpleKVO.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EF6153320CFEDD100D425CD /* NSObject+SimpleKVO.m */; };
8EFA08DA1C50E25800F6D790 /* LocalConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EFA08C01C50E25800F6D790 /* LocalConnection.m */; };
8EFA08DB1C50E25800F6D790 /* FSMEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EFA08C41C50E25800F6D790 /* FSMEngine.m */; };
8EFA08DC1C50E25800F6D790 /* FSMStateUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EFA08C61C50E25800F6D790 /* FSMStateUtil.m */; };
Expand All @@ -38,6 +39,8 @@
8EE0B63D1C40F71900CBABCA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
8EE0B6401C40F71900CBABCA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
8EE0B6421C40F71900CBABCA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
8EF6153220CFEDD100D425CD /* NSObject+SimpleKVO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+SimpleKVO.h"; sourceTree = "<group>"; };
8EF6153320CFEDD100D425CD /* NSObject+SimpleKVO.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+SimpleKVO.m"; sourceTree = "<group>"; };
8EFA08BF1C50E25800F6D790 /* LocalConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocalConnection.h; sourceTree = "<group>"; };
8EFA08C01C50E25800F6D790 /* LocalConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LocalConnection.m; sourceTree = "<group>"; };
8EFA08C21C50E25800F6D790 /* FSMDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSMDefines.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -95,6 +98,7 @@
8EE0B6301C40F71900CBABCA /* testRealReachability */ = {
isa = PBXGroup;
children = (
8EF6153120CFEDD100D425CD /* KVO */,
8EFA08BD1C50E25800F6D790 /* RealReachability */,
8EE0B6341C40F71900CBABCA /* AppDelegate.h */,
8EE0B6351C40F71900CBABCA /* AppDelegate.m */,
Expand All @@ -117,6 +121,15 @@
name = "Supporting Files";
sourceTree = "<group>";
};
8EF6153120CFEDD100D425CD /* KVO */ = {
isa = PBXGroup;
children = (
8EF6153220CFEDD100D425CD /* NSObject+SimpleKVO.h */,
8EF6153320CFEDD100D425CD /* NSObject+SimpleKVO.m */,
);
path = KVO;
sourceTree = "<group>";
};
8EFA08BD1C50E25800F6D790 /* RealReachability */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -204,6 +217,7 @@
TargetAttributes = {
8EE0B62D1C40F71800CBABCA = {
CreatedOnToolsVersion = 7.1.1;
DevelopmentTeam = K93K8C6UUM;
};
};
};
Expand Down Expand Up @@ -255,6 +269,7 @@
8EFA08DC1C50E25800F6D790 /* FSMStateUtil.m in Sources */,
8EFA08DB1C50E25800F6D790 /* FSMEngine.m in Sources */,
8EFA08E21C50E25800F6D790 /* ReachStateWWAN.m in Sources */,
8EF6153420CFEDD100D425CD /* NSObject+SimpleKVO.m in Sources */,
8EFA08E01C50E25800F6D790 /* ReachStateUnReachable.m in Sources */,
8EFA08E11C50E25800F6D790 /* ReachStateWIFI.m in Sources */,
8EFA08DF1C50E25800F6D790 /* ReachStateUnloaded.m in Sources */,
Expand Down Expand Up @@ -367,6 +382,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = K93K8C6UUM;
INFOPLIST_FILE = testRealReachability/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
Expand All @@ -379,6 +395,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = K93K8C6UUM;
INFOPLIST_FILE = testRealReachability/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
Expand Down
34 changes: 34 additions & 0 deletions testRealReachability/KVO/NSObject+SimpleKVO.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// NSObject+SimpleKVO.h
// ExMobi
//
// Created by achen on 16/7/1.
// Simply modified from NSObject+YYAddForKVO.
//
// 一个从YYAddForKVO修改而来的极致简化的KVO封装(从API参数设计到调用方式)
//
// 注意:这里监听的是值的变化,其值确实改变后才会触发回调;
// 其行为和原始KVO以及YYAddForKVO都不同。
// 后两者的行为是只要被赋值就会触发(由KVO的实现原理决定的,而simpleKVO作了特别处理),
// 使其更易用于某些业务场景的需求实现。
//
// 单元测试覆盖率100/100。
//
// Thanks to ibireme!
// Original project:
// YYKit (author ibireme): <https://github.com/ibireme/YYKit>
//

#import <Foundation/Foundation.h>

#define ENABLE_SWIZZ_IN_SIMPLEKVO

@interface NSObject (SimpleKVO)

- (void)addKVOForPath:(NSString*)path withBlock:(void (^)(id newValue))block;

- (void)removeKVOForPath:(NSString *)path;

- (void)removeAllKVOs;

@end
Loading

4 comments on commit fc628c4

@DTown
Copy link

@DTown DTown commented on fc628c4 Jun 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When will this feature be available via cocopods as new version?

@dustturtle
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, today I will release a new version. Haha. hope you like it.

@dustturtle
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DTown 1.3.0 released.

@DTown
Copy link

@DTown DTown commented on fc628c4 Jun 28, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dustturtle Thx a lot :)

Please sign in to comment.