检查网络状态
最近在做iphone 网络链接部分,于是鄙人将各路的好贴整合了一下并且加了自己的一些想法,希望对大家有所帮助~~
写的不好的地方还请各位大大多多指教啊
iPhone SDK中附带了
SCNetworkReachabilityCre ateWithAddress用于检查ip地址是否可以访问。传入清零地址(0.0.0.0)可用来查询网络状态。
网络可使用 时返回YES,否则为NO。
返回标记:
kSCNetworkReachabilityFl agsIsWWAN :测试用户使用的时运营商的网络还是本地wifi。
kSCNetworkFlagsConnectio nRequired:无需更多链接。
kSCNetworkFlagsReachable :表明网络可以访问。
代码 如下:
头文件:
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>
#import <netdb.h>
#import
<SystemConfiguration/SCNetworkReachability.h>
frameworks:/System/Library/Frameworks/SystemConfiguration.framework
- (BOOL) connectedToNetwork
{
//
Create zero addy
struct
sockaddr_in zeroAddress;
bzero(&zeroAddress,
sizeof(zeroAddress));
zeroAddress.sin_len
= sizeof(zeroAddress);
zeroAddress.sin_family
= AF_INET;
//
Recover reachability flags
SCNetworkReachabilityRef
defaultRouteReachability =
SCNetworkReachabilityCre ateWithAddress(NULL, (struct sockaddr
*)&zeroAddress);
SCNetworkReachabilityFla gs
flags;
BOOL
didRetrieveFlags =
SCNetworkReachabilityGet Flags(defaultRouteReachability ,
&flags);
CFRelease(defaultRouteReachability );
if
(!didRetrieveFlags)
{
return
NO;
}
BOOL
isReachable = flags &
kSCNetworkFlagsReachable ;
BOOL
needsConnection = flags &
kSCNetworkFlagsConnectio nRequired;
return
(isReachable && !needsConnection) ?
YES : NO;
}
//call like:
-(void) start {
if
(![self connectedToNetwork]) {
UIAlertView
*alert = [[UIAlertView alloc]
initWithTitle:@"Network Connection Error"
message:@"You need to be connected to the internet to use this
feature."
delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert
show];
[alert
release];
}
else {
//do something
}
}
使用上述方法可能会出现以下问题:
当使用者在使用你的应用程式的时候,如果关掉萤幕,将装置放在锁定状态(就是那个重新打开 时
需要在萤幕上画一下「解锁」的状态)一阵子,然后再按一下按钮恢复使用,这个时候你想要做一些网路操作,其实是可以连线,但是Reachability
API
还是告诉你无法连线;或刚打开应用程式的时候,也告诉你无法连线。当你需要判断能不能连线,使用者用了哪种连线而应不应该继续连线的时候,其实使用者可以
连线,API 却始终一直告诉你不能连线。
把装置设定为锁定,然后恢复使用的状况是这样的-苹果的设计是,为了节省电力消耗,会在进入锁定状态后,自动关闭无线网路介面,而当你解除锁定后,才会把 无线网路再度打开。而Reachability
基本上只询问「目前的网路状态」,如果装置的无线网路正处于从关闭的状态恢复的阶段,这时后回传的结果便是无法连线。
顺道一提,在第三方应用程式中,可以在Info.plist
档案中,设定UIRequiresPersistentWifi
这个选项,文件中说这个设定可以让应用程式持续保持无线网路的连线状态,但是,就算设了这 项设定,在进入锁定状态后,系统仍然会自动关闭无线网路介面,这项设定仅局限于iPhone
一直开着、你不去把萤幕关掉的状况。
至于怎样在锁定状态下继续保持连线,那又是另外一个话题了。
刚进入应用程式的时候,也往往回传无法连线-猜测应该是使用iPhone
主画面(Springboard)的时候,无线网路介面大概也是关闭的。 在点选要用什么应用程式的时候,好像也用不到什么网路功能,为了节电把网路介面关了也好。 至于定时检查信箱、或从AppStore
下载软体什么的,应该是苹果有其他自己的背景程序,负责呼叫网路介面。
简言之,就是你常会遇到「问的时候说没有,但是下一秒钟网路就通」的状况,遇到这种状况,要使用比较白烂的作法,可以向Reachability
连续问两次 ,如果第一次说没有第二次却说有,那就代表其实还是有网路…可能比较好的作法,可以是,我们不要叫一个method
直接回传给我们网路状态,而是变成delegate 的方式 来处理。
流程大概是这样,这边稍微有些啰嗦-
1. 设计两个delegate
method,分别用于有网路与没网路两种状况。
2.
先生出一个SCNetworkReachabilityRef 物件,然后用SCNetworkReachabilityGet Flags()
抓取目前的网路状态,如果是有,就呼叫「有网路」的那组delegate method,直接结束。
3.
如果这一次抓取网路状态的结果是没有连线,我们就对刚刚产生的SCNetworkReachabilityRef
物件设定一个SCNetworkReachabilityCal lBack function。 因为只要连线状态出现变化,就会呼叫这个function,所以,在呼叫到的时候,再用SCNetworkReachabilityGet Flags()
抓一次目前的网路状态,决定要回传是「有网路」或「没网路 」的delegate method。如果有呼叫到,通常是会有,如此一来,我们可以捕捉到了「第一次说没有,但是后来又有网路」的状况,并且成功回传「有网路」。
4.
同时设一组timer(或用NSObject 的perform selector after delay
之类的),如果超过一段时间,SCNetworkReachability API
都没有被呼叫前一点中提到的SCNetworkReachabilityCal lBack
function,就代表不但一开始没网路, 而且后来一直还是那个状态,那…就代表一直没网路。 这时后呼叫「没网路」的delegate
method。
5. 记得要release 那个SCNetworkReachabilityRef
物件…。
采用这种实作,在没有网路连线的状态下,就会需要几秒钟的等待,确定目前的确没有网路连线。 不过嘛,反正没有网路连线,也不能够做什么别的事情,所以等个几秒钟也无所谓嘛。
顺道一提,iPhone SDK 关于SCNetworkReachability
的说明文件里头有个错误 ,在讲如何设定SCNetworkReachabilityCal lBack
的部份提到-
Here
is an example of a function declared to conform to this type:
-
(void)MyReachabilityCallback(SCNetworkReachabilityRef target,
SCNetworkReachabilityFla gs flags, void *info);