iOS开发中WiFi相关功能总结

1.Ping域名、Ping某IP

有时候可能会遇到ping 某个域名或者ip通不通,再做下一步操作。这里的ping与传统的做get或者post请求还是有很大区别的。比如我们连接了某个WiFi,测试ping www.baidu.com,如果能ping 通,基本可以断定可以上网了,但是如果我们做了一个get 请求(url 是www.baidu.com),路由器可能重定向这个WiFi内的某网页了,依然没有错误返回,就会误认为可以正常上网。

这里有关于ping命令的详细解释:百度百科Ping

iOS中想要ping域名或者ip,苹果提供了一个官方例子SimplePing

在例子中,有一个苹果已经封装过的类【SimplePing.h】和【SimplePing.m】

使用起来也相当的简单:

首先创建一个Ping对象:


1

2

3

4

5

 SimplePing *pinger = [[SimplePing alloc] initWithHostName:self.hostName];

 self.pinger = pinger;

 pinger.delegate = self;

 pinger.addressStyle = SimplePingAddressStyleICMPv4;

 [pinger start];

然后在start成功的代理方法中,发送数据报文:


1

2

3

4

5

6

7

8

9

10

11

12

13

/**

 *  start成功,也就是准备工作做完后的回调

 */

- (void)simplePing:(SimplePing *)pinger didStartWithAddress:(NSData *)address

{

    // 发送测试报文数据

    [self.pinger sendPingWithData:nil];

}

- (void)simplePing:(SimplePing *)pinger didFailWithError:(NSError *)error

{

    NSLog(@"didFailWithError");

    [self.pinger stop];

}

其他几个代理方法也非常简单,就简单记录一下:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

// 发送测试报文成功的回调方法

- (void)simplePing:(SimplePing *)pinger didSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber

{

    NSLog(@"#%u sent", sequenceNumber);

}

//发送测试报文失败的回调方法

- (void)simplePing:(SimplePing *)pinger didFailToSendPacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber error:(NSError *)error

{

    NSLog(@"#%u send failed: %@", sequenceNumber, error);

}

// 接收到ping的地址所返回的数据报文回调方法

- (void)simplePing:(SimplePing *)pinger didReceivePingResponsePacket:(NSData *)packet sequenceNumber:(uint16_t)sequenceNumber

{

    NSLog(@"#%u received, size=%zu", sequenceNumber, packet.length);

}

- (void)simplePing:(SimplePing *)pinger didReceiveUnexpectedPacket:(NSData *)packet

{

    NSLog(@"#%s",__func__);

}

注意点:

iOS 中 ping失败后(即发送测试报文成功后,一直没后收到响应的报文),不会有任何回调方法告知我们。而一般ping 一次的结果也不太准确,ping 花费的时间也非常短,所以我们一般会ping多次,发送一次ping 测试报文0.5s后检测一下这一次ping是否已经收到响应。0.5s后检测时,如果已经收到响应,则可以ping 通;如果没有收到响应,则视为超时。

做法也有很多种,可以用NSTimer或者 {- (void)performSelector: withObject:afterDelay:}

这里有一个别人写的工程:https://github.com/lovesunstar/STPingTest

PingTest效果图

终端ping效果图

2.获取WiFi信息

以前物联网刚火的时候,出现过很多一体式无线路由,所以App里难免会遇到要判断当前所连接的WiFi,以及获取WiFi信息的功能。13年的时候查过一些关于WiFi的方法,后面渐渐都忘记了。惭愧!!!

需要添加SystemConfiguration.framework 并在当前类中添加代码

#import arpa/inet.h>
#import netinet/in.h>
#import ifaddrs.h>


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

//获取WiFi 信息,返回的字典中包含了WiFi的名称、路由器的Mac地址、还有一个Data(转换成字符串打印出来是wifi名称)

- (NSDictionary *)fetchSSIDInfo {

    NSArray *ifs = (__bridge_transfer NSArray *)CNCopySupportedInterfaces();

    if (!ifs) {

        return nil;

    }

    NSDictionary *info = nil;

    for (NSString *ifnam in ifs) {

        info = (__bridge_transfer NSDictionary *)CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam);

        if (info && [info count]) { break; }

    }

    return info;

}

//打印出来的结果:

2016-05-12 15:28:51.674 SimplePing[18883:6790207] WIFI_INFO:{

    BSSID = "a4:2b:8c:c:7f:bd";

    SSID = bdmy06;

    SSIDDATA = ;

}

3.获取WiFi名称

有了上一步,获取WiFi名称就非常简单了。


1

2

3

NSString *WiFiName = info[@"SSID"];

//打印结果:

2016-05-12 15:35:13.059 SimplePing[18887:6791418] bdmy06

完整的:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

- (NSString *)fetchWiFiName {

    NSArray *ifs = (__bridge_transfer NSArray *)CNCopySupportedInterfaces();

    if (!ifs) {

        return nil;

    }

    NSString *WiFiName = nil;

    for (NSString *ifnam in ifs) {

        NSDictionary *info = (__bridge_transfer NSDictionary *)CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam);

        if (info && [info count]) {

            // 这里其实对应的有三个key:kCNNetworkInfoKeySSID、kCNNetworkInfoKeyBSSID、kCNNetworkInfoKeySSIDData,

            // 不过它们都是CFStringRef类型的

            WiFiName = [info objectForKey:(__bridge NSString *)kCNNetworkInfoKeySSID];

//            WiFiName = [info objectForKey:@"SSID"];

            break;

        }

    }

    return WiFiName;

}

4.获取当前所连接WiFi的网关地址

例如自己家的路由器一般默认的网关地址是192.168.1.1,获取的就是这个192.168.1.1。

为什么不直接写死呢?

因为一些商场或者有多个路由器的网关地址是不一样的,比如之前有个公司的网关是192.168.89.1。

这里有篇博客,这是地址

需要导入的库:


1

#import #import #import

获取网关的方法


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

- (NSString *)getGatewayIpForCurrentWiFi {

    NSString *address = @"error";

    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) {

        /*/

         int i=255;

         while((i--)>0)

         //*/

            if(temp_addr->ifa_addr->sa_family == AF_INET) {

                // Check if interface is en0 which is the wifi connection on the iPhone

                if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"])

                {

                    // Get NSString from C String //ifa_addr

                    //ifa->ifa_dstaddr is the broadcast address, which explains the "255's"

                    //                    address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_dstaddr)->sin_addr)];

                    address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];

                    //routerIP----192.168.1.255 广播地址

                    NSLog(@"broadcast address--%@",[NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_dstaddr)->sin_addr)]);

                    //--192.168.1.106 本机地址

                    NSLog(@"local device ip--%@",[NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)]);

                    //--255.255.255.0 子网掩码地址

                    NSLog(@"netmask--%@",[NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_netmask)->sin_addr)]);

                    //--en0 端口地址

                    NSLog(@"interface--%@",[NSString stringWithUTF8String:temp_addr->ifa_name]);

                }

            }

            temp_addr = temp_addr->ifa_next;

        }

    }

    // Free memory

    freeifaddrs(interfaces);

    in_addr_t i = inet_addr([address cStringUsingEncoding:NSUTF8StringEncoding]);

    in_addr_t* x = &i;

    unsigned char *s = getdefaultgateway(x);

    NSString *ip=[NSString stringWithFormat:@"%d.%d.%d.%d",s[0],s[1],s[2],s[3]];

    free(s);

    return ip;

}

其中 getdefaultgateway 是一个C语言文件中的方法,在工程里可以找到。

5.获取本机在WiFi环境下的IP地址

获取本机在WiFi环境下的ip地址,在上一节中其实已经写过,这里将其提取出来即可:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

- (NSString *)getLocalIPAddressForCurrentWiFi

{

    NSString *address = nil;

    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) {

            if(temp_addr->ifa_addr->sa_family == AF_INET) {

                // Check if interface is en0 which is the wifi connection on the iPhone

                if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {

                    address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];

                    return address;

                }

            }

            temp_addr = temp_addr->ifa_next;

        }

        freeifaddrs(interfaces);

    }

    return nil;

}

同样的方式也可以获取广播地址、子网掩码、端口等,组装成一个字典。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

- (NSMutableDictionary *)getLocalInfoForCurrentWiFi {

    NSMutableDictionary *dict = [NSMutableDictionary dictionary];

    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) {

            if(temp_addr->ifa_addr->sa_family == AF_INET) {

                // Check if interface is en0 which is the wifi connection on the iPhone

                if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {

                    //----192.168.1.255 广播地址

                    NSString *broadcast = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_dstaddr)->sin_addr)];

                    if (broadcast) {

                        [dict setObject:broadcast forKey:@"broadcast"];

                    }

                    NSLog(@"broadcast address--%@",broadcast);

                    //--192.168.1.106 本机地址

                    NSString *localIp = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];

                    if (localIp) {

                        [dict setObject:localIp forKey:@"localIp"];

                    }

                    NSLog(@"local device ip--%@",localIp);

                    //--255.255.255.0 子网掩码地址

                    NSString *netmask = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_netmask)->sin_addr)];

                    if (netmask) {

                        [dict setObject:netmask forKey:@"netmask"];

                    }

                    NSLog(@"netmask--%@",netmask);

                    //--en0 端口地址

                    NSString *interface = [NSString stringWithUTF8String:temp_addr->ifa_name];

                    if (interface) {

                        [dict setObject:interface forKey:@"interface"];

                    }

                    NSLog(@"interface--%@",interface);

                    return dict;

                }

            }

            temp_addr = temp_addr->ifa_next;

        }

    }

    // Free memory

    freeifaddrs(interfaces);

    return dict;

}

将返回的字典打印出来:


1

2

3

4

5

6

2016-05-12 17:59:09.257 SimplePing[19141:6830567] wifi:{

    broadcast = "192.168.1.255";

    interface = en0;

    localIp = "192.168.1.7";

    netmask = "255.255.255.0";

}

时间: 2024-10-31 06:14:19

iOS开发中WiFi相关功能总结的相关文章

iOS开发中打电话发短信等功能的实现

原文:iOS开发中打电话发短信等功能的实现 在APP开发中,可能会涉及到打电话.发短信.发邮件等功能.比如说,通常一个产品的"关于"页面,会有开发者的联系方式,理想情况下,当用户点击该电话号码时,能够自动的帮用户拨出去,就涉及到了打电话的功能. iOS开发中,有三种方式可以打电话: (1)直接跳到拨号界面,代码如下 NSURL *url = [NSURL URLWithString:@"tel://10010"]; [[UIApplication sharedApp

iOS开发中文件的上传和下载功能的基本实现_IOS

文件的上传 说明:文件上传使用的时POST请求,通常把要上传的数据保存在请求体中.本文介绍如何不借助第三方框架实现iOS开发中得文件上传. 由于过程较为复杂,因此本文只贴出部分关键代码. 主控制器的关键代码: 复制代码 代码如下: YYViewController.m #import "YYViewController.h" #define YYEncode(str) [str dataUsingEncoding:NSUTF8StringEncoding] @interface YYV

iOS开发中的单元测试(二) 让断言活泼起来的匹配引擎

上一篇文章简单介绍了OCUnit和GHUnit两款iOS开发中较为常见的单元测试框架,本文进一步介绍单元测试 中的另一利器--匹配引擎(Matcher Engine).匹配引擎可以替代断言方法,配合单元测试引擎使用,测试 用例可以更多样化,更细致. 传统断言提供的方法数量和功能都有限,以导读中提到的两款框架为例 ,即使是断言相对丰富的GHUnit也只是提供了38种断言方法,范围仅涵盖了逻辑比较,异常和出错等少数几方 面,仍然很单一.而使用匹配引擎代替断言,可能性就大大丰富了,除了普通断言支持的规

[译]iOS 开发中使用 Swift 进行 iBeacons 交互指南

本文讲的是[译]iOS 开发中使用 Swift 进行 iBeacons 交互指南, 原文地址:A Guide to Interacting with iBeacons in iOS using Swift 原文作者:MATT NEDRICH 译文出自:掘金翻译计划 译者:lovelyCiTY 校对者:Gocy015.Danny1451 #iOS 开发中使用 Swift 进行 iBeacons 交互指南 我最近致力于研究一个关于 iBeacons 的 iOS 项目.本文中,我将全面的介绍如何使用 

总结iOS开发中的断点续传与实践_IOS

前言 断点续传概述 断点续传就是从文件上次中断的地方开始重新下载或上传数据,而不是从文件开头.(本文的断点续传仅涉及下载,上传不在讨论之内)当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会去重头下载,这样很浪费时间.所以项目中要实现大文件下载,断点续传功能就必不可少了.当然,断点续传有一种特殊的情况,就是 iOS 应用被用户 kill 掉或者应用 crash,要实现应用重启之后的断点续传.这种特殊情况是本文要解决的问题. 断点续传原理 要实现断点续传 , 服

iOS开发中使用UIScrollView实现无限循环的图片浏览器_IOS

一.概述 UIKit框架中有大量的控件供开发者使用,在iOS开发中不仅可以直接使用这些控件还可以在这些控件的基础上进行扩展打造自己的控件.在这个系列中如果每个控件都介绍一遍确实没有必要,所谓授人以鱼不如授人以渔,这里会尽可能让大家明白其中的原理,找一些典型的控件进行说明,这样一来大家就可以触类旁通.今天我们主要来看一下UIScrollView的内容: UIView UIScrollView 实战--图片浏览器 二.UIView 在熟悉UIScrollView之前很有必要说一下UIView的内容.

ios开发中两个常见问题解决方法

  ios开发中两个常见问题解决方法来啦!大家知道苹果手机使用的是ios系统,而且用户量很庞大,所以ios开发也成了很热门的行业.下文小乐哥给大家带来ios开发中两个常见问题解决方法,希望给技术员在ios开发中起到帮助作用! ios开发中两个常见问题解决方法 一."Unknown class XXViewController in Interface Builder file."问题处理 最近在静态库中写了一个XXViewController类,然后在主工程的xib中,将xib的类指定

iOS开发中标签控制器的使用——UITabBarController

iOS开发中标签控制器的使用--UITabBarController 一.引言         与导航控制器相类似,标签控制器也是用于管理视图控制器的一个UI控件,在其内部封装了一个标签栏,与导航不同的是,导航的管理方式是纵向的,采用push与pop切换控制器,标签的管理是横向的,通过标签的切换来改变控制器,一般我们习惯将tabBar作为应用程序的根视图控制器,在其中添加导航,导航中在对ViewController进行管理. 二.创建一个标签控制器         通过如下的步骤,我们可以很简便

iOS开发中的手势体系——UIGestureRecognizer分析及其子类的使用

iOS开发中的手势体系--UIGestureRecognizer分析及其子类的使用 一.引言         在iOS系统中,手势是进行用户交互的重要方式,通过UIGestureRecognizer类,我们可以轻松的创建出各种手势应用于app中.关于UIGestureRecognizer类,是对iOS中的事件传递机制面向应用的封装,将手势消息的传递抽象为了对象.有关消息传递的一些讨论,在前面的博客中有提到: iOS事件响应控制:http://my.oschina.net/u/2340880/bl