Skip to content

Commit 868187c

Browse files
committed
import new feature here: double check introduced, please try!
1 parent 1fbb0d6 commit 868187c

File tree

3 files changed

+106
-73
lines changed

3 files changed

+106
-73
lines changed

RealReachability/RealReachability.h

+19-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//
22
// RealReachability.h
3-
// Version 1.1.0
3+
// Version 1.1.9
44
//
55
// Created by Dustturtle on 16/1/9.
66
// Copyright (c) 2016 Dustturtle. All rights reserved.
@@ -50,11 +50,26 @@ typedef NS_ENUM(NSInteger, WWANAccessType) {
5050
WWANType2G = 3
5151
};
5252

53+
@protocol RealReachabilityDelegate <NSObject>
54+
@optional
55+
/// TODO:通过挂载一个定制的代理请求来检查网络,需要用户自己实现,我们会给出一个示例。
56+
/// 可以通过这种方式规避解决http可用但icmp被阻止的场景下框架判断不正确的问题。
57+
/// 此方法阻塞?同步返回?还是异步?如果阻塞主线程超过n秒是不行的。
58+
/// 当CustomAgent的doubleCheck被启用时,ping的doubleCheck将不再工作。
59+
/// TODO: We introduce a custom agent to check the network by making http request, that need
60+
/// the user to achieve this.
61+
/// We want to solve the issue on special case(http available but icmp prevented).
62+
/// NOTE: When the double check of the custom agent was used, the double check by ping will work no longer.
63+
- (BOOL)doubleCheckByCustomAgent;
64+
@end
65+
5366
@interface RealReachability : NSObject
5467

5568
/// Please make sure this host is available for pinging! default host:www.apple.com
5669
@property (nonatomic, copy) NSString *hostForPing;
5770

71+
@property (nonatomic, copy) NSString *hostForCheck;
72+
5873
/// Interval in minutes; default is 2.0f, suggest value from 0.3f to 60.0f;
5974
/// If exceeded, the value will be reset to 0.3f or 60.0f (the closer one).
6075
@property (nonatomic, assign) float autoCheckInterval;
@@ -71,8 +86,10 @@ typedef NS_ENUM(NSInteger, WWANAccessType) {
7186
/**
7287
* To get real reachability we need to do async request,
7388
* then we use the block blow for invoker to handle business request(need real reachability).
89+
* Now we have introduced a double check to make our result more reliable.
7490
*
75-
* @param asyncHandler async request handler, return in 2 seconds(max limit).
91+
* @param asyncHandler async request handler, return in 5 seconds(max limit).
92+
* The limit time may be adjusted later for better experience.
7693
*/
7794
- (void)reachabilityWithBlock:(void (^)(ReachabilityStatus status))asyncHandler;
7895

RealReachability/RealReachability.m

+85-71
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ @interface RealReachability()
3535
@property (nonatomic,strong) NSArray *typeStrings2G;
3636

3737
@property (nonatomic, assign) ReachabilityStatus previousStatus;
38+
39+
/// main helper
40+
@property (nonatomic, strong) PingHelper *pingHelper;
41+
42+
/// for double check
43+
@property (nonatomic, strong) PingHelper *pingChecker;
3844
@end
3945

4046
@implementation RealReachability
@@ -63,13 +69,17 @@ - (id)init
6369
_typeStrings4G = @[CTRadioAccessTechnologyLTE];
6470

6571
_hostForPing = kDefaultHost;
72+
_hostForCheck = kDefaultHost;
6673
_autoCheckInterval = kDefaultCheckInterval;
6774
_pingTimeout = kDefaultPingTimeout;
6875

6976
[[NSNotificationCenter defaultCenter] addObserver:self
7077
selector:@selector(appBecomeActive)
7178
name:UIApplicationDidBecomeActiveNotification
7279
object:nil];
80+
81+
_pingHelper = [[PingHelper alloc] init];
82+
_pingChecker = [[PingHelper alloc] init];
7383
}
7484
return self;
7585
}
@@ -124,16 +134,20 @@ - (void)startNotifier
124134

125135
[GLocalConnection startNotifier];
126136
[[NSNotificationCenter defaultCenter] addObserver:self
127-
selector:@selector(localConnectionChanged:)
137+
selector:@selector(localConnectionHandler:)
128138
name:kLocalConnectionChangedNotification
129139
object:nil];
130140
[[NSNotificationCenter defaultCenter] addObserver:self
131-
selector:@selector(localConnectionInitialized:)
141+
selector:@selector(localConnectionHandler:)
132142
name:kLocalConnectionInitializedNotification
133143
object:nil];
134144

135-
GPingHelper.host = _hostForPing;
136-
GPingHelper.timeout = self.pingTimeout;
145+
self.pingHelper.host = _hostForPing;
146+
self.pingHelper.timeout = self.pingTimeout;
147+
148+
self.pingChecker.host = _hostForCheck;
149+
self.pingChecker.timeout = self.pingTimeout;
150+
137151
[self autoCheckReachability];
138152
}
139153

@@ -168,56 +182,31 @@ - (void)reachabilityWithBlock:(void (^)(ReachabilityStatus status))asyncHandler
168182
return;
169183
}
170184

171-
ReachabilityStatus status = [self currentReachabilityStatus];
172185
__weak __typeof(self)weakSelf = self;
173-
[GPingHelper pingWithBlock:^(BOOL isSuccess)
186+
[self.pingHelper pingWithBlock:^(BOOL isSuccess)
174187
{
175188
__strong __typeof(weakSelf)strongSelf = weakSelf;
176-
NSDictionary *inputDic = @{kEventKeyID:@(RREventPingCallback), kEventKeyParam:@(isSuccess)};
177-
NSInteger rtn = [strongSelf.engine receiveInput:inputDic];
178-
if (rtn == 0) // state changed & state available, post notification.
189+
if (isSuccess)
179190
{
180-
if ([strongSelf.engine isCurrentStateAvailable])
191+
// no need to post the notification because the status is not changing.
192+
NSDictionary *inputDic = @{kEventKeyID:@(RREventPingCallback), kEventKeyParam:@(YES)};
193+
[strongSelf.engine receiveInput:inputDic];
194+
195+
if (asyncHandler != nil)
181196
{
182-
strongSelf.previousStatus = status;
183-
// this makes sure the change notification happens on the MAIN THREAD
184-
__weak __typeof(strongSelf)deepWeakSelf = strongSelf;
185-
dispatch_async(dispatch_get_main_queue(), ^{
186-
__strong __typeof(deepWeakSelf)deepStrongSelf = deepWeakSelf;
187-
[[NSNotificationCenter defaultCenter] postNotificationName:kRealReachabilityChangedNotification
188-
object:deepStrongSelf];
189-
});
197+
ReachabilityStatus currentStatus = [strongSelf currentReachabilityStatus];
198+
asyncHandler(currentStatus);
190199
}
191200
}
192-
193-
if (asyncHandler != nil)
201+
else
194202
{
195-
RRStateID currentID = strongSelf.engine.currentStateID;
196-
switch (currentID)
197-
{
198-
case RRStateUnReachable:
199-
{
200-
asyncHandler(RealStatusNotReachable);
201-
break;
202-
}
203-
case RRStateWIFI:
204-
{
205-
asyncHandler(RealStatusViaWiFi);
206-
break;
207-
}
208-
case RRStateWWAN:
209-
{
210-
asyncHandler(RealStatusViaWWAN);
211-
break;
212-
}
213-
214-
default:
215-
{
216-
NSLog(@"warning! reachState uncertain! state unmatched, treat as unreachable temporary");
217-
asyncHandler(RealStatusNotReachable);
218-
break;
219-
}
220-
}
203+
// delay 1 seconds, then make a double check.
204+
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1*NSEC_PER_SEC));
205+
__weak __typeof(self)weakSelf = self;
206+
dispatch_after(time, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
207+
__strong __typeof(weakSelf)self = weakSelf;
208+
[self makeDoubleCheck:asyncHandler];
209+
});
221210
}
222211
}];
223212
}
@@ -264,12 +253,22 @@ - (void)setHostForPing:(NSString *)hostForPing
264253
_hostForPing = nil;
265254
_hostForPing = [hostForPing copy];
266255

267-
GPingHelper.host = _hostForPing;
256+
self.pingHelper.host = _hostForPing;
257+
}
258+
259+
- (void)setHostForCheck:(NSString *)hostForCheck
260+
{
261+
_hostForCheck = nil;
262+
_hostForCheck = [hostForCheck copy];
263+
264+
self.pingChecker.host = _hostForCheck;
268265
}
269266

270-
- (void)setPingTimeout:(NSTimeInterval)pingTimeout {
267+
- (void)setPingTimeout:(NSTimeInterval)pingTimeout
268+
{
271269
_pingTimeout = pingTimeout;
272-
GPingHelper.timeout = pingTimeout;
270+
self.pingHelper.timeout = pingTimeout;
271+
self.pingChecker.timeout = pingTimeout;
273272
}
274273

275274
- (WWANAccessType)currentWWANtype
@@ -294,6 +293,34 @@ - (WWANAccessType)currentWWANtype
294293
}
295294

296295
#pragma mark - inner methods
296+
- (void)makeDoubleCheck:(void (^)(ReachabilityStatus status))asyncHandler
297+
{
298+
__weak __typeof(self)weakSelf = self;
299+
[self.pingChecker pingWithBlock:^(BOOL isSuccess) {
300+
__strong __typeof(weakSelf)strongSelf = weakSelf;
301+
302+
NSDictionary *inputDic = @{kEventKeyID:@(RREventPingCallback), kEventKeyParam:@(isSuccess)};
303+
[strongSelf.engine receiveInput:inputDic];
304+
305+
if (!isSuccess)
306+
{
307+
// Only fail make the change; then we post the fail notification.
308+
__weak __typeof(strongSelf)deepWeakSelf = strongSelf;
309+
dispatch_async(dispatch_get_main_queue(), ^{
310+
__strong __typeof(deepWeakSelf)deepStrongSelf = deepWeakSelf;
311+
[[NSNotificationCenter defaultCenter] postNotificationName:kRealReachabilityChangedNotification
312+
object:deepStrongSelf];
313+
});
314+
}
315+
316+
if (asyncHandler != nil)
317+
{
318+
ReachabilityStatus currentStatus = [strongSelf currentReachabilityStatus];
319+
asyncHandler(currentStatus);
320+
}
321+
}];
322+
}
323+
297324
- (NSString *)paramValueFromStatus:(LocalConnectionStatus)status
298325
{
299326
switch (status)
@@ -368,11 +395,11 @@ - (WWANAccessType)accessTypeForString:(NSString *)accessString
368395
}
369396

370397
#pragma mark - Notification observer
371-
- (void)localConnectionChanged:(NSNotification *)notification
398+
- (void)localConnectionHandler:(NSNotification *)notification
372399
{
373400
LocalConnection *lc = (LocalConnection *)notification.object;
374401
LocalConnectionStatus lcStatus = [lc currentLocalConnectionStatus];
375-
//NSLog(@"currentLocalConnectionStatus:%@",@(lcStatus));
402+
//NSLog(@"currentLocalConnectionStatus:%@, receive notification:%@",@(lcStatus), notification.name);
376403
ReachabilityStatus status = [self currentReachabilityStatus];
377404

378405
NSDictionary *inputDic = @{kEventKeyID:@(RREventLocalConnectionCallback), kEventKeyParam:[self paramValueFromStatus:lcStatus]};
@@ -383,10 +410,14 @@ - (void)localConnectionChanged:(NSNotification *)notification
383410
if ([self.engine isCurrentStateAvailable])
384411
{
385412
self.previousStatus = status;
386-
// already in main thread.
387-
[[NSNotificationCenter defaultCenter] postNotificationName:kRealReachabilityChangedNotification
388-
object:self];
389413

414+
// already in main thread.
415+
if ([notification.name isEqualToString:kLocalConnectionChangedNotification])
416+
{
417+
[[NSNotificationCenter defaultCenter] postNotificationName:kRealReachabilityChangedNotification
418+
object:self];
419+
}
420+
390421
if (lcStatus != LC_UnReachable)
391422
{
392423
// To make sure your reachability is "Real".
@@ -396,22 +427,5 @@ - (void)localConnectionChanged:(NSNotification *)notification
396427
}
397428
}
398429

399-
- (void)localConnectionInitialized:(NSNotification *)notification
400-
{
401-
LocalConnection *lc = (LocalConnection *)notification.object;
402-
LocalConnectionStatus lcStatus = [lc currentLocalConnectionStatus];
403-
NSLog(@"localConnectionInitializedStatus:%@",@(lcStatus));
404-
405-
NSDictionary *inputDic = @{kEventKeyID:@(RREventLocalConnectionCallback), kEventKeyParam:[self paramValueFromStatus:lcStatus]};
406-
NSInteger rtn = [self.engine receiveInput:inputDic];
407-
408-
// Initialized state, ping once to check the reachability(if local status reachable).
409-
if ((rtn == 0) && [self.engine isCurrentStateAvailable] && (lcStatus != LC_UnReachable))
410-
{
411-
// To make sure your reachability is "Real".
412-
[self reachabilityWithBlock:nil];
413-
}
414-
}
415-
416430
@end
417431

testRealReachability/AppDelegate.m

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ @implementation AppDelegate
1818

1919
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
2020
// Override point for customization after application launch.
21+
GLobalRealReachability.hostForPing = @"www.baidu.com";
22+
GLobalRealReachability.hostForCheck = @"www.apple.com";
2123
[GLobalRealReachability startNotifier];
2224
return YES;
2325
}

0 commit comments

Comments
 (0)