Câu hỏi Cách kiểm tra kết nối Internet đang hoạt động trên iOS hoặc macOS?


Tôi muốn kiểm tra xem tôi có kết nối Internet trên iOS bằng cách sử dụng Cocoa Touch thư viện hoặc trên hệ điều hành MacOS bằng cách sử dụng Ca cao thư viện.

Tôi đã tìm ra cách để làm điều này bằng cách sử dụng NSURL. Cách tôi làm dường như không đáng tin cậy (bởi vì ngay cả Google có thể xuống một ngày và dựa vào bên thứ ba có vẻ xấu), và trong khi tôi có thể kiểm tra để xem phản hồi từ một số trang web khác nếu Google không trả lời, có vẻ lãng phí và một chi phí không cần thiết trên ứng dụng của tôi.

- (BOOL) connectedToInternet
{
    NSString *URLString = [NSString stringWithContentsOfURL:[NSURL URLWithString:@"http://www.google.com"]];
    return ( URLString != NULL ) ? YES : NO;
}

Là những gì tôi đã làm xấu, (chưa kể đến stringWithContentsOfURL không được chấp nhận trong iOS 3.0 và macOS 10.4) và nếu vậy, cách tốt hơn để thực hiện điều này là gì?


1225
2017-07-05 08:45


gốc


Hơn return (BOOL)URLString;hoặc thậm chí tốt hơn, return !!URLString hoặc là return URLString != nil
Tôi không biết trường hợp sử dụng của bạn là gì, nhưng nếu bạn có thể thích hợp hơn để thử yêu cầu và xử lý bất kỳ lỗi nào như thiếu kết nối phát sinh. Nếu bạn không thể làm điều này, thì có rất nhiều lời khuyên tốt ở đây trong trường hợp này. - SK9
Giải pháp của bạn là thông minh, và tôi thích nó. Bạn cũng có thể dùng NSString *URLString = [NSString stringWithContentsOfURL:[NSURL URLWithString:@"https://twitter.com/getibox"] encoding:NSUTF8StringEncoding error:nil]; Để thoát khỏi cảnh báo khó chịu. - Abdelrahman Eid
hãy thử sử dụng lớp Khả năng hiển thị từ liên kết bên dưới, lớp này sẽ hoạt động cho bạn github.com/tonymillion/Reachability - Dhaval H. Nena
Đối với những người mới tìm câu trả lời này: stackoverflow.com/a/8813279 - afollestad


Các câu trả lời:


Quan trọng: Séc này nên luôn luôn được thực hiện không đồng bộ. Phần lớn các câu trả lời dưới đây đều đồng bộ nên hãy cẩn thận nếu không bạn sẽ đóng băng ứng dụng của mình.


Nhanh

1) Cài đặt qua CocoaPods hoặc Carthage: https://github.com/ashleymills/Reachability.swift

2) Kiểm tra khả năng hiển thị thông qua đóng cửa

let reachability = Reachability()!

reachability.whenReachable = { reachability in
    if reachability.connection == .wifi {
        print("Reachable via WiFi")
    } else {
        print("Reachable via Cellular")
    }
}

reachability.whenUnreachable = { _ in
    print("Not reachable")
}

do {
    try reachability.startNotifier()
} catch {
    print("Unable to start notifier")
}

Mục tiêu-C

1) Thêm SystemConfiguration khuôn khổ cho dự án nhưng đừng lo lắng về việc đưa nó vào bất kỳ đâu

2) Thêm phiên bản Tony Million của Reachability.h và Reachability.m cho dự án (tìm thấy ở đây: https://github.com/tonymillion/Reachability)

3) Cập nhật phần giao diện

#import "Reachability.h"

// Add this to the interface in the .m file of your view controller
@interface MyViewController ()
{
    Reachability *internetReachableFoo;
}
@end

4) Sau đó, thực hiện phương pháp này trong tập tin .m của bộ điều khiển xem của bạn mà bạn có thể gọi

// Checks if we have an internet connection or not
- (void)testInternetConnection
{   
    internetReachableFoo = [Reachability reachabilityWithHostname:@"www.google.com"];

    // Internet is reachable
    internetReachableFoo.reachableBlock = ^(Reachability*reach)
    {
        // Update the UI on the main thread
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"Yayyy, we have the interwebs!");
        });
    };

    // Internet is not reachable
    internetReachableFoo.unreachableBlock = ^(Reachability*reach)
    {
        // Update the UI on the main thread
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"Someone broke the internet :(");
        });
    };

    [internetReachableFoo startNotifier];
}

Lưu ý quan trọng: Các Reachability class là một trong những lớp được sử dụng nhiều nhất trong các dự án, do đó bạn có thể chạy vào các xung đột đặt tên với các dự án khác. Nếu điều này xảy ra, bạn sẽ phải đổi tên một trong các cặp Reachability.h và Reachability.m các tệp khác để giải quyết vấn đề.

Chú thích: Tên miền bạn sử dụng không quan trọng. Nó chỉ là thử nghiệm cho một cổng vào bất kỳ tên miền nào.


1220
2017-08-29 23:58



@gonzobrains: Tên miền bạn sử dụng không quan trọng. Nó chỉ là thử nghiệm cho một cổng vào bất kì miền. - iwasrobbed
@KaanDedeoglu Nó chỉ là một ví dụ, sử dụng bất cứ tên miền nào bạn muốn. Nó chỉ đơn giản là kiểm tra một cổng vào internet, không phải là miền thực sự có sẵn. - iwasrobbed
Oh, btw bạn cần phải thêm SystemConfiguration.framework cho dự án (theo phương pháp 1). - wiseindy
google.com không hoạt động trên Trung Quốc! - Dmitry
Sử dụng www.appleiphonecell.com thay vì google.com - url này được tạo ra bởi táo vì lý do chính xác này. - Smikey


Tôi muốn giữ cho mọi thứ đơn giản. Cách tôi làm điều này là:

//Class.h
#import "Reachability.h"
#import <SystemConfiguration/SystemConfiguration.h>

- (BOOL)connected;

//Class.m
- (BOOL)connected
{
    Reachability *reachability = [Reachability reachabilityForInternetConnection];
    NetworkStatus networkStatus = [reachability currentReachabilityStatus];
    return networkStatus != NotReachable;
}

Sau đó, tôi sử dụng điều này bất cứ khi nào tôi muốn xem nếu tôi có một kết nối:

if (![self connected]) {
    // Not connected
} else {
    // Connected. Do some Internet stuff
}

Phương pháp này không chờ trạng thái mạng đã thay đổi để thực hiện công việc. Nó chỉ kiểm tra trạng thái khi bạn yêu cầu.


303
2017-08-26 13:34



Hi @ msec, bạn có thể thử giải pháp Andrew Zimmer trong trang này, nó hoạt động tốt với adsl bị ngắt kết nối (và kết nối wifi) - Williew
TẠI SAO bạn đang quay trở lại! = NotReachable thay vì "return netWorkStatus;" ??? - Fede Cugliandolo
Đối với những người chỉ cần sao chép và dán như tôi đã làm với các mã trên. Ngoài ra, thêm SystemConfiguration.framework theo cách thủ công hoặc bạn sẽ nhận được lỗi liên kết. - Iftikhar
khả năng truy cập không xác định ??? - coolcool1994


Sử dụng mã Reachability của Apple, tôi đã tạo một hàm sẽ kiểm tra chính xác điều này mà không cần phải bao gồm bất kỳ lớp nào.

Bao gồm SystemConfiguration.framework trong dự án của bạn.

Thực hiện một số nhập khẩu:

#import <sys/socket.h>
#import <netinet/in.h>
#import <SystemConfiguration/SystemConfiguration.h>

Bây giờ chỉ cần gọi hàm này:

/*
Connectivity testing code pulled from Apple's Reachability Example: https://developer.apple.com/library/content/samplecode/Reachability
 */
+(BOOL)hasConnectivity {
    struct sockaddr_in zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.sin_len = sizeof(zeroAddress);
    zeroAddress.sin_family = AF_INET;

    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)&zeroAddress);
    if (reachability != NULL) {
        //NetworkStatus retVal = NotReachable;
        SCNetworkReachabilityFlags flags;
        if (SCNetworkReachabilityGetFlags(reachability, &flags)) {
            if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
            {
                // If target host is not reachable
                return NO;
            }

            if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
            {
                // If target host is reachable and no connection is required
                //  then we'll assume (for now) that your on Wi-Fi
                return YES;
            }


            if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
                 (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
            {
                // ... and the connection is on-demand (or on-traffic) if the
                //     calling application is using the CFSocketStream or higher APIs.

                if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
                {
                    // ... and no [user] intervention is needed
                    return YES;
                }
            }

            if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
            {
                // ... but WWAN connections are OK if the calling application
                //     is using the CFNetwork (CFSocketStream?) APIs.
                return YES;
            }
        }
    }

    return NO;
}

Và đó là iOS 5 thử nghiệm cho bạn.


143
2017-10-28 20:37



Bạn có thể mô tả mã này không? Kiểm tra này hoạt động như thế nào? - Valerii Pavlov
Hoạt động tốt trên iOS3.0, thx - RocketMan
@ JezenThomas Điều này không thực hiện kiểm tra internet không đồng bộ, đó là lý do tại sao nó "mỏng hơn nhiều" ... Bạn nên luôn làm điều này một cách không đồng bộ bằng cách đăng ký thông báo để không treo ứng dụng lên quá trình này. - iwasrobbed
Cảm ơn, công việc này ngay cả khi bạn đang sử dụng wifi adsl và adsl không được kết nối, chính xác là những gì tôi cần. - Williew
Điều này làm rò rỉ bộ nhớ - cấu trúc 'dễ đọc' (đối tượng, điều) cần được giải phóng với CFRelease (). - Russell Mull


Đây từng là câu trả lời đúng, nhưng bây giờ đã lỗi thời vì bạn nên đăng ký thông báo về khả năng truy cập. Phương pháp này kiểm tra đồng bộ:


Bạn có thể sử dụng lớp Khả năng hiển thị của Apple. Nó cũng sẽ cho phép bạn kiểm tra xem Wi-Fi có được bật hay không:

Reachability* reachability = [Reachability sharedReachability];
[reachability setHostName:@"www.example.com"];    // Set your host name here
NetworkStatus remoteHostStatus = [reachability remoteHostStatus];

if (remoteHostStatus == NotReachable) { }
else if (remoteHostStatus == ReachableViaWiFiNetwork) { }
else if (remoteHostStatus == ReachableViaCarrierDataNetwork) { }

Lớp Khả năng hiển thị không được gửi cùng với SDK, mà là một phần của ứng dụng mẫu Apple này. Chỉ cần tải xuống và sao chép Reachability.h / m vào dự án của bạn. Ngoài ra, bạn phải thêm khung SystemConfiguration vào dự án của bạn.


118
2017-07-05 10:58



Xem nhận xét của tôi ở trên về việc không sử dụng Khả năng hiển thị như thế. Sử dụng nó trong chế độ không đồng bộ và đăng ký với các thông báo nó gửi - không. - Kendall Helmstetter Gelner
Mã này là một điểm khởi đầu tốt cho những thứ mà bạn cần phải thiết lập trước khi bạn có thể sử dụng các phương thức ủy nhiệm cho lớp khả năng truy cập. - Brock Woolf


Đây là một câu trả lời rất đơn giản:

NSURL *scriptUrl = [NSURL URLWithString:@"http://www.google.com/m"];
NSData *data = [NSData dataWithContentsOfURL:scriptUrl];
if (data)
    NSLog(@"Device is connected to the Internet");
else
    NSLog(@"Device is not connected to the Internet");

URL phải trỏ đến một trang web cực kỳ nhỏ. Tôi sử dụng trang web di động của Google tại đây, nhưng nếu tôi có một máy chủ web đáng tin cậy, tôi sẽ tải lên một tệp nhỏ chỉ với một ký tự trong đó cho tốc độ tối đa.

Nếu kiểm tra xem thiết bị có bằng cách nào đó kết nối với Internet là mọi thứ bạn muốn làm, tôi chắc chắn khuyên bạn nên sử dụng giải pháp đơn giản này. Nếu bạn cần biết cách người dùng được kết nối, sử dụng Reachability là cách để đi.

Cẩn thận: Thao tác này sẽ chặn ngắn chuỗi của bạn trong khi tải trang web. Trong trường hợp của tôi, đây không phải là một vấn đề, nhưng bạn nên xem xét điều này (tín dụng cho Brad để chỉ ra điều này).


78
2018-05-14 22:25



Tôi thực sự thích ý tưởng này, nhưng tôi sẽ nói về độ tin cậy 99.999% trong khi vẫn duy trì kích thước phản hồi nhỏ, đi với www.google.com/m là chế độ xem di động cho google. - rwyland
Giải pháp tuyệt vời @Erik. Những gì tôi cũng khuyên bạn nên sử dụng www.google.com, thay vì www.google.com/m, như rwyland nói. Thật kỳ lạ, nhưng từ thử nghiệm của tôi, phiên bản di động luôn mất khoảng 120ms so với www.google.com - Sebyddd
Tài liệu của Apple khuyên bạn không nên làm điều này vì nó có thể chặn luồng trên mạng chậm, có thể khiến ứng dụng bị chấm dứt trong iOS - Brad Thomas
Cảm ơn bạn đã phản hồi tích cực, đồng ý rằng www.google.com/m là giải pháp tốt nhất vì độ tin cậy! - Erik Wegener
LOL, tôi chắc chắn Google đánh giá cao việc bạn đề xuất mọi người sử dụng chúng làm tài nguyên kiểm tra Internet. - mxcl


Đây là cách tôi làm điều đó trong các ứng dụng của tôi: Trong khi một mã phản hồi trạng thái 200 không đảm bảo bất cứ điều gì, nó là đủ ổn định đối với tôi. Điều này không yêu cầu tải nhiều như các câu trả lời NSData được đăng ở đây, vì tôi chỉ kiểm tra phản hồi HEAD.

Mã Swift

func checkInternet(flag:Bool, completionHandler:(internet:Bool) -> Void)
{
    UIApplication.sharedApplication().networkActivityIndicatorVisible = true

    let url = NSURL(string: "http://www.appleiphonecell.com/")
    let request = NSMutableURLRequest(URL: url!)

    request.HTTPMethod = "HEAD"
    request.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData
    request.timeoutInterval = 10.0

    NSURLConnection.sendAsynchronousRequest(request, queue:NSOperationQueue.mainQueue(), completionHandler:
    {(response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in

        UIApplication.sharedApplication().networkActivityIndicatorVisible = false

        let rsp = response as! NSHTTPURLResponse?

        completionHandler(internet:rsp?.statusCode == 200)
    })
}

func yourMethod()
{
    self.checkInternet(false, completionHandler:
    {(internet:Bool) -> Void in

        if (internet)
        {
            // "Internet" aka Apple's region universal URL reachable
        }
        else
        {
            // No "Internet" aka Apple's region universal URL un-reachable
        }
    })
}

Mã mục tiêu-C

typedef void(^connection)(BOOL);

- (void)checkInternet:(connection)block
{
    NSURL *url = [NSURL URLWithString:@"http://www.appleiphonecell.com/"];
    NSMutableURLRequest *headRequest = [NSMutableURLRequest requestWithURL:url];
    headRequest.HTTPMethod = @"HEAD";

    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    defaultConfigObject.timeoutIntervalForResource = 10.0;
    defaultConfigObject.requestCachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;

    NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue: [NSOperationQueue mainQueue]];

    NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithRequest:headRequest
        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
    {
        if (!error && response)
        {
            block([(NSHTTPURLResponse *)response statusCode] == 200);
        }
    }];
    [dataTask resume];
}

- (void)yourMethod
{
    [self checkInternet:^(BOOL internet)
    {
         if (internet)
         {
             // "Internet" aka Apple's region universal URL reachable
         }
         else
         {
             // No "Internet" aka Apple's region universal URL un-reachable
         }
    }];
}

70
2017-11-30 03:26



Có vẻ như đây là cách nhanh nhất - Pavel
Thận trọng: Theo kinh nghiệm của tôi, giải pháp này không hoạt động mọi lúc. Trong nhiều trường hợp, phản ứng trả về là 403, sau khi uống thời gian ngọt ngào của nó. Giải pháp này có vẻ hoàn hảo, nhưng không đảm bảo 100% kết quả. - Mustafa
"Không có google, không có internet" ?? - Kiran Ruth R
Tính đến tháng 6 năm 2014, điều này sẽ thất bại ở Trung Quốc đại lục, do chính phủ Trung Quốc bây giờ hoàn toàn chặn google.com. (google.cn hoạt động, mặc dù, nhưng ở Trung Quốc đại lục, không có baidu.com, không có internet) Có lẽ tốt hơn để ping bất cứ máy chủ bạn cần phải giao tiếp với. - prewett
Sử dụng www.appleiphonecell.com thay vào đó - apple đã tạo url này vì lý do chính xác này. - Smikey


Nguồn cung cấp của Apple mã mẫu để kiểm tra các loại mạng khả dụng khác nhau. Ngoài ra còn có một thí dụ trong sách dạy nấu ăn dành cho nhà phát triển iPhone.

Chú thích: Vui lòng xem nhận xét của @ KHG về câu trả lời này liên quan đến việc sử dụng mã khả năng truy cập của Apple.


54
2017-07-05 08:59



Cảm ơn. Tôi phát hiện ra rằng tài liệu Xcode trong 3.0 cũng chứa mã nguồn, được tìm thấy bằng cách tìm kiếm "reachability" trong tài liệu. - Brock Woolf
Lưu ý rằng bản sửa đổi mới (09-08-09) của mã mẫu Khả năng hiển thị từ Apple là không đồng bộ. - Daniel Hepper


Bạn đã có thể sử dụng Reachability bởi  (có sẵn ở đây).

#import "Reachability.h"

- (BOOL)networkConnection {
    return [[Reachability reachabilityWithHostName:@"www.google.com"] currentReachabilityStatus];
}

if ([self networkConnection] == NotReachable) { /* No Network */ } else { /* Network */ } //Use ReachableViaWiFi / ReachableViaWWAN to get the type of connection.

43
2018-04-25 12:20





Apple cung cấp một ứng dụng mẫu thực hiện chính xác điều này:

Khả năng hiển thị


39
2017-07-05 08:58



Bạn nên lưu ý rằng mẫu Reachability chỉ phát hiện giao diện nào đang hoạt động, nhưng không phát hiện ra giao diện nào có kết nối internet hợp lệ. Các ứng dụng nên xử lý thất bại một cách duyên dáng ngay cả khi Reachability báo cáo rằng mọi thứ đã sẵn sàng để sử dụng. - rpetrich
Thật may là tình hình sẽ tốt hơn rất nhiều trong 3.0, vì hệ thống sẽ trình bày một trang đăng nhập cho người dùng phía sau WiFi bị khóa nơi bạn phải đăng nhập để sử dụng ... bạn sử dụng để kiểm tra chuyển hướng theo cách thủ công (và bạn vẫn làm nếu phát triển 2.2.1 ứng dụng) - Kendall Helmstetter Gelner


Chỉ có lớp Khả năng hiển thị đã được cập nhật. Bây giờ bạn có thể sử dụng:

Reachability* reachability = [Reachability reachabilityWithHostName:@"www.apple.com"];
NetworkStatus remoteHostStatus = [reachability currentReachabilityStatus];

if (remoteHostStatus == NotReachable) { NSLog(@"not reachable");}
else if (remoteHostStatus == ReachableViaWWAN) { NSLog(@"reachable via wwan");}
else if (remoteHostStatus == ReachableViaWiFi) { NSLog(@"reachable via wifi");}

32
2017-08-27 09:41



Trừ khi một cái gì đó thay đổi kể từ 4,0 đã được phát hành, mã đó không phải là không đồng bộ và bạn được đảm bảo để xem nó hiển thị trong báo cáo sự cố - đã xảy ra với tôi trước đây. - bpapa
Tôi đồng ý với bpapa. Bạn không nên sử dụng mã đồng bộ. Cảm ơn thông tin mặc dù - Brock Woolf