iOS 当 WiFi 处于活动状态时,可达性报告没有 WiFi

iOS Reachability reports no WiFi, when WiFi is active

我正在使用 Apple 的 Reachability class 来检测对我的应用程序功能有影响的网络事件。这是一个使用 setKeepAliveTimeout 的 voip 应用程序,因此每约 10 分钟醒来读取网络状态并决定是否应刷新连接。

BOOL res = [app setKeepAliveTimeout:600 handler:^{        
      [[WIFI instance] isWifiConnected];
      [[AClass an_instance] refresh];
  }
}];

因此,每 10 分钟调用一次 isWifiConnected,应用再次读取网络状态。

- (BOOL) isWifiConnected {

    self.wifiReach = [Reachability reachabilityForLocalWiFi];
    NetworkStatus wifiStatus = [self.wifiReach currentReachabilityStatus];

    switch (wifiStatus) {
        case NotReachable: {
            m_wifiConnected = NO;  
            LOG(@"NetStatus:NotReachable");
            break;
        }
        case ReachableViaWiFi: {
            m_wifiConnected = YES;   
            m_wwanConnected = NO;
            LOG(@"NetStatus:ReachableViaWiFi");
            break;
        }
    }
    return m_wifiConnected;
}

虽然我的设备中有 WiFi,但调用 returns 错误,即没有 WiFi,而且网络状态为 NotReachable。

但是,在很短的时间间隔后,再次调用可达性回调,wifi 似乎已连接。但是,由于错误值,我已经触发了一个事件,并且应用程序关闭了与服务器的连接,认为没有 wi-fi。

经过一些研究,我在 Reachability.m 文件(由 Apple 提供)的自述文件中找到了这个

默认情况下,应用程序使用 www.apple.com 作为其远程主机。您可以通过修改 -viewDidLoad 中的 remoteHostName 变量的值来更改它在 APLViewController.m 中使用的主机。

IMPORTANT: Reachability must use DNS to resolve the host name before it can determine the Reachability of that host, and this may take time on certain network connections. Because of this, the API will return NotReachable until name resolution has completed. This delay may be visible in the interface on some networks

.

会不会是这个问题? dns 查找的延迟?或者我还需要增强我的代码吗?

当我初始化应用程序时,我调用这个

self.hostReach = [Reachability reachabilityWithHostName: @"www.apple.com"];

如果我使用这样的 IP 地址是否正确?

self.hostReach = [Reachability reachabilityWithHostName: @"1.2.3.4"];

使用 public IP 安全吗?例如,“17.178.96.59”是 apple.com

的 nslookup 的结果

Reachability class中有一个方法似乎是从苹果的演示中使用的。

- (BOOL)connectionRequired
{
    NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
    SCNetworkReachabilityFlags flags;

    if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
    {
        return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
    }

    return NO;
}

为什么需要 connectionRequired?可以用来解决问题吗?

应使用主机名而不是显式地址创建可达性。 DNS 系统的全部要点是主机的地址有时会发生变化。直接链接到名称服务器应该在这方面提供一些安全性,但这不是它应该如何工作的。

可达性通常是最好的猜测,而不是一成不变的。唯一可以确定的方法是实际尝试。需要连接与此有关,因为它是设备说“一切正常,我只是没有尝试真正连接”。

因此,可以说您应该在不检查可达性状态的情况下触发保持活动状态,并使用请求的结果来确定是否存在错误。如果您需要确定,请发送实际请求并查看实际结果。

为了节省电池电量,iOS 将在未使用时关闭网络硬件。这意味着关闭 WiFi 和蜂窝无线电。在这种情况下,Reachability 将无法报告完整的结果,因为它无法在不重新打开所有内容的情况下检查情况。这就是 kSCNetworkReachabilityFlagsConnectionRequired 的用途——告诉您需要建立连接以唤醒硬件备份。

您看到的可能是 phone 解锁时某些东西被唤醒(您的应用程序或其他具有后台权限的应用程序),所以一切都被唤醒,您立即看到错误,但随后 WiFi 连接你又连接上了。

您需要处理可达性,就像它可以告诉您 "definitely reachable" 或 "definitely not reachable" 以及 "situation unknown" 一样。你需要决定在未知情况下你要做什么。如果您立即建立网络连接,那么您将比平时更快地耗尽电池电量。另一种方法可能只是等待网络因其他原因被唤醒。这真的取决于你。