动态信息屏幕

发布于 2024-07-23 05:55:04 字数 95 浏览 4 评论 0原文

我正在尝试找到一种方法,如果互联网连接可用,则可以从网络下载我的应用程序上的信息屏幕(这样我就可以定期更新它)。 如果互联网不可用,则应使用默认的或最后下载的。 这可能吗?

I am trying to find a way to make the info screen on my app download from the web IF an internetconnection is available (so i can update it regularly). If internet is not available, it should use the default or the last downloaded one. Is this possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

绮筵 2024-07-30 05:55:04

请注意上面 James Skitmore 提供的方法是测试连接性的糟糕方法。 不要使用它。 它将不必要地加载 google.com,并且如果网络不可用,则会导致超时,这将使您的应用程序看起来像是已冻结。

以下是检查网络连接的方法。

在您的应用程序中,您可以执行此操作来检查网络是否可用:

if (![[UIDevice currentDevice] networkAvailable])

您现在还可以检查与特定主机的连接,例如 yourwebsite.com,或者您可以检查连接类型、3G 与 Wifi 等。让您通过阅读头文件自己弄清楚这一点。

您需要将以下文件包含到您的应用程序中:
(由 Erica Sadun 提供)

UIDevice-Reachability.h

/*
 Erica Sadun, http://ericasadun.com
 iPhone Developer's Cookbook, 3.0 Edition
 BSD License for anything not specifically marked as developed by a third party.
 Zach Waugh and Apple's code excluded.
 Use at your own risk
 */

#import <UIKit/UIKit.h>

#define SUPPORTS_UNDOCUMENTED_API   1

@interface UIDevice (Reachability)
- (NSString *) hostname;

- (NSString *) localWiFiIPAddress;
- (NSString *) localIPAddress;
- (NSString *) whatismyipdotcom;

- (BOOL) activeWLAN;
- (BOOL) addressFromString:(NSString *)IPAddress address:(struct sockaddr_in *)address; // via Apple
- (void) forceWWAN; // via Apple
- (void) shutdownWWAN; // via Apple
@end

// Methods which rely on undocumented API methods 
#if SUPPORTS_UNDOCUMENTED_API

@interface UIDevice (UIDevice_Undocumented_Reachability)
- (BOOL) networkAvailable;
- (BOOL) activeWWAN;
@end

#endif // SUPPORTS_UNDOCUMENTED_API

UIDevice-Reachability.m

/*
 Erica Sadun, http://ericasadun.com
 iPhone Developer's Cookbook, 3.0 Edition
 BSD License for anything not specifically marked as developed by a third party.
 Apple's code excluded.
 Use at your own risk
 */

// TTD: Add async version of whatsmyip -- thanks rpetrich

#include <unistd.h>
#include <sys/sysctl.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <netinet/in.h>
#include <ifaddrs.h>

#import "UIDevice-Reachability.h"
#import "wwanconnect.h"

@implementation UIDevice (Reachability)

#pragma mark host and ip utils
- (NSString *) hostname
{
    char baseHostName[255];
    int success = gethostname(baseHostName, 255);
    if (success != 0) return nil;
    baseHostName[255] = '\0';

#if !TARGET_IPHONE_SIMULATOR
    return [NSString stringWithFormat:@"%s.local", baseHostName];
#else
    return [NSString stringWithFormat:@"%s", baseHostName];
#endif
}

// Direct from Apple. Thank you Apple
- (BOOL)addressFromString:(NSString *)IPAddress address:(struct sockaddr_in *)address
{
    if (!IPAddress || ![IPAddress length]) {
        return NO;
    }

    memset((char *) address, sizeof(struct sockaddr_in), 0);
    address->sin_family = AF_INET;
    address->sin_len = sizeof(struct sockaddr_in);

    int conversionResult = inet_aton([IPAddress UTF8String], &address->sin_addr);
    if (conversionResult == 0) {
        NSAssert1(conversionResult != 1, @"Failed to convert the IP address string into a sockaddr_in: %@", IPAddress);
        return NO;
    }

    return YES;
}

- (NSString *) getIPAddressForHost: (NSString *) theHost
{
    struct hostent *host = gethostbyname([theHost UTF8String]);

    if (host == NULL) {
        herror("resolv");
        return NULL;
    }

    struct in_addr **list = (struct in_addr **)host->h_addr_list;
    NSString *addressString = [NSString stringWithCString:inet_ntoa(*list[0])];
    return addressString;
}

#if ! defined(IFT_ETHER)
#define IFT_ETHER 0x6   // Ethernet CSMACD
#endif

// Matt Brown's get WiFi IP addy solution
// Author gave permission to use in Cookbook under cookbook license
// http://mattbsoftware.blogspot.com/2009/04/how-to-get-ip-address-of-iphone-os-v221.html
- (NSString *) localWiFiIPAddress
{
    BOOL success;
    struct ifaddrs * addrs;
    const struct ifaddrs * cursor;

    success = getifaddrs(&addrs) == 0;
    if (success) {
        cursor = addrs;
        while (cursor != NULL) {
            // the second test keeps from picking up the loopback address
            if (cursor->ifa_addr->sa_family == AF_INET && (cursor->ifa_flags & IFF_LOOPBACK) == 0) 
            {
                NSString *name = [NSString stringWithUTF8String:cursor->ifa_name];
                if ([name isEqualToString:@"en0"]) { // found the WiFi adapter
                    return [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)cursor->ifa_addr)->sin_addr)];
                }
            }
            cursor = cursor->ifa_next;
        }
        freeifaddrs(addrs);
    }
    return nil;
}

// Return the local IP address
- (NSString *) localIPAddress
{
    struct hostent *host = gethostbyname([[self hostname] UTF8String]);
    if (host == NULL)
    {
        herror("resolv");
        return nil;
    }
    else {
        struct in_addr **list = (struct in_addr **)host->h_addr_list;
        return [NSString stringWithCString:inet_ntoa(*list[0])];
    }
    return nil;
}

- (NSString *) whatismyipdotcom
{
    NSError *error;
    NSURL *ipURL = [NSURL URLWithString:@"http://www.whatismyip.com/automation/n09230945.asp"];
    NSString *ip = [NSString stringWithContentsOfURL:ipURL encoding:1 error:&error];
    if (!ip) return [error localizedDescription];
    return ip;
}

- (BOOL) activeWLAN
{
    return ([self localWiFiIPAddress] != nil);
}

#pragma mark Forcing WWAN connection

MyStreamInfoPtr myInfoPtr;

static void myClientCallback(void *refCon)
{
    int  *val = (int*)refCon;
    printf("myClientCallback entered - value from refCon is %d\n", *val);
}

- (void) forceWWAN
{
    int value = 0;
    myInfoPtr = (MyStreamInfoPtr) StartWWAN(myClientCallback, &value);
    if (myInfoPtr)  
    {
        printf("Started WWAN\n");
    }
    else
    {
        printf("Failed to start WWAN\n");
    }
}

- (void) shutdownWWAN
{
    if (myInfoPtr) StopWWAN((MyInfoRef) myInfoPtr);
}
@end

#if SUPPORTS_UNDOCUMENTED_API
@implementation UIDevice (UIDevice_Undocumented_Reachability)
- (BOOL) networkAvailable
{
    // Unavailable has only one address: 127.0.0.1
    return !(([[[NSHost currentHost] addresses] count] == 1) && [[self localIPAddress] isEqualToString:@"127.0.0.1"]);
}

- (BOOL) activeWWAN
{
    return ([self networkAvailable] && ![self localWiFiIPAddress]);
}
@end
#endif  // SUPPORTS_UNDOCUMENTED_API

wwanconnect.h

// Direct from Apple. Thank you Apple

#if !defined(__WWAN_CONNECT__)
#define __WWAN_CONNECT__    1

#include <CoreFoundation/CoreFoundation.h>
#include <assert.h>

#define kTestHost   "www.whatismyip.com"
#define kTestPort   80      

typedef void (*ConnectClientCallBack)(void *refCon);


struct MyStreamInfoStruct{
    CFWriteStreamRef        wStreamRef;
    CFReadStreamRef         rStreamRef;
    ConnectClientCallBack   clientCB;
    void                    *refCon;
    CFStreamError           error;
    Boolean                 errorOccurred;
    Boolean                 isConnected;
    Boolean                 isStreamInitd;
    Boolean                 isClientSet;
};

typedef struct MyStreamInfoStruct MyStreamInfo;
typedef struct MyStreamInfoStruct *MyStreamInfoPtr;
typedef struct __MyInfoRef *MyInfoRef;

/*
 *  StartWWAN()
 *  
 *  Discussion:
 *    This function will initiate a Wireless Wide Area Network (WWAN)
 *     connection by using the CFSocketStream API to connect with a 
 *     server system defined by kTestHost:kTestPort above.
 *     No communications are expected to happen over the CFSocketStream
 *     connection.
 *  
 *    clientCB:
 *     if the connection is opened, the callback routine, if not NULL
 *     will be called. function defintion - see ConnectClientCallBack above
 *     
 *    refCon:
 *     if a client callback, clientCB is defined, then the refCon
 *      parameter will be the argument to the client callback
 *
 *    return:
 *     if the WWAN connection is successful, a MyInfoRef value is returned
 *     The MyInfoRef value must be passed to StopWWAN to stop the WWAN
 *     connection.
 *     A NULL result indicates that the connection was unsuccessful
 *    
 */
extern MyInfoRef StartWWAN(ConnectClientCallBack clientCB, void *refCon);

/*
 *  StopWWAN()
 *  
 *  Discussion:
 *    This function closes the CFSocketStream which was used to establish the
 *    WWAN connection. Once the WWAN connection has been started, BSD
 *    network functions can be used to communicate across the WWAN connection.
 *    As of the writing of this sample, there is no guarantee that the use of
 *    only BSD socket API's will maintain the WWAN connection.
 *  
 *    infoRef:
 *     pass in the MyInfoRef result from the StartWWAN function.
 *     
 */

extern void StopWWAN(MyInfoRef infoRef);

#endif // __WWAN_CONNECT__

wwanconnect.c

// Direct from Apple. Thank you Apple

#include "wwanconnect.h"
#include <CFNetwork/CFSocketStream.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <ifaddrs.h>
#include <stdio.h>

static Boolean TestGetIFAddrs(void);
static void MyCFWriteStreamClientCallBack(CFWriteStreamRef stream, CFStreamEventType type, void *clientCallBackInfo);
static void CleanupAfterWAAN(MyStreamInfoPtr myInfoPtr);
static void CloseStreams(MyStreamInfoPtr myInfoPtr);

static Boolean TestGetIFAddrs(void)
{
    int             result;
    struct  ifaddrs *ifbase, *ifiterator;
    int             done = 0;
    Boolean         addrFound = FALSE;
    char            loopbackname[] = "lo0/0";

    result = getifaddrs(&ifbase);
    ifiterator = ifbase;
    while (!done && (ifiterator != NULL))
    {
        if (ifiterator->ifa_addr->sa_family == AF_INET)
        {
            if (memcmp(ifiterator->ifa_name, loopbackname, 3))
            {
                struct  sockaddr *saddr, *netmask, *daddr;
                saddr = ifiterator->ifa_addr;
                netmask = ifiterator->ifa_netmask;
                daddr = ifiterator->ifa_dstaddr;

                // we've found an entry for the IP address
                struct sockaddr_in  *iaddr;
                char                addrstr[64];
                iaddr = (struct sockaddr_in *)saddr;
                inet_ntop(saddr->sa_family, &iaddr->sin_addr, addrstr, sizeof(addrstr));
                fprintf(stderr, "ipv4 interface name %s, source IP addr %s ", ifiterator->ifa_name, addrstr);

                iaddr = (struct sockaddr_in *)netmask;
                if (iaddr)
                {
                    inet_ntop(saddr->sa_family, &iaddr->sin_addr, addrstr, sizeof(addrstr));
                    fprintf(stderr, "netmask IP addr %s ", addrstr);
                }

                iaddr = (struct sockaddr_in *)daddr;
                if (iaddr)
                {
                    inet_ntop(saddr->sa_family, &iaddr->sin_addr, addrstr, sizeof(addrstr));
                    fprintf(stderr, "dest/broadcast IP addr %s.\n\n", addrstr);
                }
                return TRUE;
            }

        }
        else if (ifiterator->ifa_addr->sa_family == AF_INET6)
        {
            // we've found an entry for the IP address
            struct sockaddr_in6 *iaddr6 = (struct sockaddr_in6 *)ifiterator->ifa_addr;
            char                addrstr[256];
            inet_ntop(ifiterator->ifa_addr->sa_family, iaddr6, addrstr, sizeof(addrstr));
            fprintf(stderr, "ipv6 interface name %s, source IP addr %s \n\n", ifiterator->ifa_name, addrstr);
        }
        ifiterator = ifiterator->ifa_next;
    }
    if (ifbase)
        freeifaddrs(ifbase);    /* done with the memory allocated by getifaddrs */

    return addrFound;
}

static void MyCFWriteStreamClientCallBack(CFWriteStreamRef stream, CFStreamEventType type, void *clientCallBackInfo)
{
    MyStreamInfoPtr myInfoPtr = (MyStreamInfoPtr) clientCallBackInfo;

    printf("MyCFWriteStreamClientCallBack entered - event is %d\n", type);

    switch (type)
    {
        case kCFStreamEventOpenCompleted:
            myInfoPtr->isConnected = TRUE;
            TestGetIFAddrs();       // call the test function to return the local ip address associated with this connection.
            if (myInfoPtr->clientCB)
            {
                // call client callback routine
                myInfoPtr->clientCB(myInfoPtr->refCon);
            }
            printf("write stream connected\n");
            break;

        case kCFStreamEventErrorOccurred:
            myInfoPtr->errorOccurred = TRUE;
            myInfoPtr->error = CFWriteStreamGetError(myInfoPtr->wStreamRef);
            printf("write stream error %d .. giving up\n", myInfoPtr->error.error);
            break;

        default:
            printf("event type %d occurred\n");
            break;
    }
    // stop the run loop at this point
    CFRunLoopStop(CFRunLoopGetCurrent());
}

extern MyInfoRef StartWWAN(ConnectClientCallBack clientCB, void *refCon)
{ 
    char                        host[] = kTestHost;
    int                         portNum = kTestPort;
    CFDataRef                   addressData;
    MyStreamInfoPtr             myInfoPtr;
    CFStreamClientContext       ctxt = {0, NULL, NULL, NULL, NULL};
    Boolean                     errorOccurred = FALSE;

    myInfoPtr = malloc(sizeof(MyStreamInfo));
    if (!myInfoPtr)
    {
        return NULL;
    }

    // init the allocated memory
    memset(myInfoPtr, 0, sizeof(MyStreamInfo));
    myInfoPtr->clientCB = clientCB;
    myInfoPtr->refCon = refCon; 
    ctxt.info = myInfoPtr;

    // Check for a dotted-quad address, if so skip any host lookups 
    in_addr_t addr = inet_addr(host); 
    if (addr != INADDR_NONE) { 
        // Create the streams from numberical host 
        struct sockaddr_in sin; 
        memset(&sin, 0, sizeof(sin)); 

        sin.sin_len= sizeof(sin); 
        sin.sin_family = AF_INET; 
        sin.sin_addr.s_addr = addr; 
        sin.sin_port = htons(portNum); 

        addressData = CFDataCreate(NULL, (UInt8 *)&sin, sizeof(sin)); 
        CFSocketSignature sig = { AF_INET, SOCK_STREAM, IPPROTO_TCP, addressData }; 

        // Create the streams. 
        CFStreamCreatePairWithPeerSocketSignature(kCFAllocatorDefault, &sig, &(myInfoPtr->rStreamRef), &(myInfoPtr->wStreamRef));       
        CFRelease(addressData); 
    } else { 
        // Create the streams from ascii host name 
        CFStringRef hostStr = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, host, kCFStringEncodingUTF8, kCFAllocatorNull); 
        CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, hostStr, portNum, &(myInfoPtr->rStreamRef), &(myInfoPtr->wStreamRef)); 
    } 

    myInfoPtr->isConnected = FALSE;
    myInfoPtr->isStreamInitd = TRUE;
    myInfoPtr->isClientSet = FALSE;

    // Inform the streams to kill the socket when it is done with it. 
    // This effects the write stream too since the pair shares the 
    // one socket. 
    CFWriteStreamSetProperty(myInfoPtr->wStreamRef, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue); 

    // set up the client
    if (!CFWriteStreamSetClient(myInfoPtr->wStreamRef, kCFStreamEventOpenCompleted | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, 
                                MyCFWriteStreamClientCallBack, &ctxt))
    {
        printf("CFWriteStreamSetClient failed\n");
        errorOccurred = TRUE;
    }
    else
        myInfoPtr->isClientSet = TRUE;

    if (!errorOccurred)
    {
        // schedule the stream
        CFWriteStreamScheduleWithRunLoop(myInfoPtr->wStreamRef, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);

        // Try to open the stream.
        if (!CFWriteStreamOpen(myInfoPtr->wStreamRef))
        {
            printf("CFWriteStreamOpen failed\n");
            errorOccurred = TRUE;
        }
    }

    if (!errorOccurred)
    {
        // everything worked so far, so run the runloop - when the callback gets called, it will stop the run loop
        printf("CFWriteStreamOpen returned with no error - calling CFRunLoopRun\n");
        CFRunLoopRun();
        if (myInfoPtr->errorOccurred)
            errorOccurred = TRUE;
        printf("after CFRunLoopRun - returning\n");
    }

    if (errorOccurred)
    {
        myInfoPtr->isConnected = FALSE;
        CleanupAfterWAAN(myInfoPtr);
        CloseStreams(myInfoPtr);

        if (myInfoPtr->isStreamInitd)
        {
            CFRelease(myInfoPtr->rStreamRef);
            CFRelease(myInfoPtr->wStreamRef);
            myInfoPtr->isStreamInitd = FALSE;
        }
        free(myInfoPtr);
        return NULL;
    }
    return (MyInfoRef)myInfoPtr;
} 

static void CleanupAfterWAAN(MyStreamInfoPtr myInfoPtr)
{
    assert(myInfoPtr != NULL);
    if (myInfoPtr->isClientSet)
    {
        CFWriteStreamSetClient(myInfoPtr->wStreamRef, 0, NULL, NULL);
        CFWriteStreamUnscheduleFromRunLoop(myInfoPtr->wStreamRef, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
        myInfoPtr->isClientSet = FALSE;
    }
}

static void CloseStreams(MyStreamInfoPtr myInfoPtr)
{
    assert(myInfoPtr != NULL);
    if (myInfoPtr->rStreamRef)
    {
        CFReadStreamClose(myInfoPtr->rStreamRef);
        myInfoPtr->rStreamRef = NULL;
    }
    if (myInfoPtr->wStreamRef)
    {
        CFWriteStreamClose(myInfoPtr->wStreamRef);
        myInfoPtr->wStreamRef = NULL;
    }
}

extern void StopWWAN(MyInfoRef infoRef)
{
    MyStreamInfoPtr myInfoPtr = (MyStreamInfoPtr)infoRef;

    printf("stopWWAN entered\n");
    assert(myInfoPtr != NULL);
    myInfoPtr->isConnected = FALSE;
    CleanupAfterWAAN(myInfoPtr);
    CloseStreams(myInfoPtr);
    free(myInfoPtr);
}

Please note the method offered by James Skitmore above is a terrible way to test connectivity. Please do not use it. It will unnecessarily load google.com, and it will cause a timeout should the network not be available, which will make your app look like it has frozen.

Here's how you could check for net connectivity.

In your app, you can do this to check for whether network is available:

if (![[UIDevice currentDevice] networkAvailable])

You can now also check connectivity to a certain host, such as yourwebsite.com, or you could check for the type of conenction, 3G vs Wifi, etc. I'll let you figure this out yourself by reading the header files.

You're going to need to include the following files to your app:
(courtesy of Erica Sadun)

UIDevice-Reachability.h

/*
 Erica Sadun, http://ericasadun.com
 iPhone Developer's Cookbook, 3.0 Edition
 BSD License for anything not specifically marked as developed by a third party.
 Zach Waugh and Apple's code excluded.
 Use at your own risk
 */

#import <UIKit/UIKit.h>

#define SUPPORTS_UNDOCUMENTED_API   1

@interface UIDevice (Reachability)
- (NSString *) hostname;

- (NSString *) localWiFiIPAddress;
- (NSString *) localIPAddress;
- (NSString *) whatismyipdotcom;

- (BOOL) activeWLAN;
- (BOOL) addressFromString:(NSString *)IPAddress address:(struct sockaddr_in *)address; // via Apple
- (void) forceWWAN; // via Apple
- (void) shutdownWWAN; // via Apple
@end

// Methods which rely on undocumented API methods 
#if SUPPORTS_UNDOCUMENTED_API

@interface UIDevice (UIDevice_Undocumented_Reachability)
- (BOOL) networkAvailable;
- (BOOL) activeWWAN;
@end

#endif // SUPPORTS_UNDOCUMENTED_API

UIDevice-Reachability.m

/*
 Erica Sadun, http://ericasadun.com
 iPhone Developer's Cookbook, 3.0 Edition
 BSD License for anything not specifically marked as developed by a third party.
 Apple's code excluded.
 Use at your own risk
 */

// TTD: Add async version of whatsmyip -- thanks rpetrich

#include <unistd.h>
#include <sys/sysctl.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <netinet/in.h>
#include <ifaddrs.h>

#import "UIDevice-Reachability.h"
#import "wwanconnect.h"

@implementation UIDevice (Reachability)

#pragma mark host and ip utils
- (NSString *) hostname
{
    char baseHostName[255];
    int success = gethostname(baseHostName, 255);
    if (success != 0) return nil;
    baseHostName[255] = '\0';

#if !TARGET_IPHONE_SIMULATOR
    return [NSString stringWithFormat:@"%s.local", baseHostName];
#else
    return [NSString stringWithFormat:@"%s", baseHostName];
#endif
}

// Direct from Apple. Thank you Apple
- (BOOL)addressFromString:(NSString *)IPAddress address:(struct sockaddr_in *)address
{
    if (!IPAddress || ![IPAddress length]) {
        return NO;
    }

    memset((char *) address, sizeof(struct sockaddr_in), 0);
    address->sin_family = AF_INET;
    address->sin_len = sizeof(struct sockaddr_in);

    int conversionResult = inet_aton([IPAddress UTF8String], &address->sin_addr);
    if (conversionResult == 0) {
        NSAssert1(conversionResult != 1, @"Failed to convert the IP address string into a sockaddr_in: %@", IPAddress);
        return NO;
    }

    return YES;
}

- (NSString *) getIPAddressForHost: (NSString *) theHost
{
    struct hostent *host = gethostbyname([theHost UTF8String]);

    if (host == NULL) {
        herror("resolv");
        return NULL;
    }

    struct in_addr **list = (struct in_addr **)host->h_addr_list;
    NSString *addressString = [NSString stringWithCString:inet_ntoa(*list[0])];
    return addressString;
}

#if ! defined(IFT_ETHER)
#define IFT_ETHER 0x6   // Ethernet CSMACD
#endif

// Matt Brown's get WiFi IP addy solution
// Author gave permission to use in Cookbook under cookbook license
// http://mattbsoftware.blogspot.com/2009/04/how-to-get-ip-address-of-iphone-os-v221.html
- (NSString *) localWiFiIPAddress
{
    BOOL success;
    struct ifaddrs * addrs;
    const struct ifaddrs * cursor;

    success = getifaddrs(&addrs) == 0;
    if (success) {
        cursor = addrs;
        while (cursor != NULL) {
            // the second test keeps from picking up the loopback address
            if (cursor->ifa_addr->sa_family == AF_INET && (cursor->ifa_flags & IFF_LOOPBACK) == 0) 
            {
                NSString *name = [NSString stringWithUTF8String:cursor->ifa_name];
                if ([name isEqualToString:@"en0"]) { // found the WiFi adapter
                    return [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)cursor->ifa_addr)->sin_addr)];
                }
            }
            cursor = cursor->ifa_next;
        }
        freeifaddrs(addrs);
    }
    return nil;
}

// Return the local IP address
- (NSString *) localIPAddress
{
    struct hostent *host = gethostbyname([[self hostname] UTF8String]);
    if (host == NULL)
    {
        herror("resolv");
        return nil;
    }
    else {
        struct in_addr **list = (struct in_addr **)host->h_addr_list;
        return [NSString stringWithCString:inet_ntoa(*list[0])];
    }
    return nil;
}

- (NSString *) whatismyipdotcom
{
    NSError *error;
    NSURL *ipURL = [NSURL URLWithString:@"http://www.whatismyip.com/automation/n09230945.asp"];
    NSString *ip = [NSString stringWithContentsOfURL:ipURL encoding:1 error:&error];
    if (!ip) return [error localizedDescription];
    return ip;
}

- (BOOL) activeWLAN
{
    return ([self localWiFiIPAddress] != nil);
}

#pragma mark Forcing WWAN connection

MyStreamInfoPtr myInfoPtr;

static void myClientCallback(void *refCon)
{
    int  *val = (int*)refCon;
    printf("myClientCallback entered - value from refCon is %d\n", *val);
}

- (void) forceWWAN
{
    int value = 0;
    myInfoPtr = (MyStreamInfoPtr) StartWWAN(myClientCallback, &value);
    if (myInfoPtr)  
    {
        printf("Started WWAN\n");
    }
    else
    {
        printf("Failed to start WWAN\n");
    }
}

- (void) shutdownWWAN
{
    if (myInfoPtr) StopWWAN((MyInfoRef) myInfoPtr);
}
@end

#if SUPPORTS_UNDOCUMENTED_API
@implementation UIDevice (UIDevice_Undocumented_Reachability)
- (BOOL) networkAvailable
{
    // Unavailable has only one address: 127.0.0.1
    return !(([[[NSHost currentHost] addresses] count] == 1) && [[self localIPAddress] isEqualToString:@"127.0.0.1"]);
}

- (BOOL) activeWWAN
{
    return ([self networkAvailable] && ![self localWiFiIPAddress]);
}
@end
#endif  // SUPPORTS_UNDOCUMENTED_API

wwanconnect.h

// Direct from Apple. Thank you Apple

#if !defined(__WWAN_CONNECT__)
#define __WWAN_CONNECT__    1

#include <CoreFoundation/CoreFoundation.h>
#include <assert.h>

#define kTestHost   "www.whatismyip.com"
#define kTestPort   80      

typedef void (*ConnectClientCallBack)(void *refCon);


struct MyStreamInfoStruct{
    CFWriteStreamRef        wStreamRef;
    CFReadStreamRef         rStreamRef;
    ConnectClientCallBack   clientCB;
    void                    *refCon;
    CFStreamError           error;
    Boolean                 errorOccurred;
    Boolean                 isConnected;
    Boolean                 isStreamInitd;
    Boolean                 isClientSet;
};

typedef struct MyStreamInfoStruct MyStreamInfo;
typedef struct MyStreamInfoStruct *MyStreamInfoPtr;
typedef struct __MyInfoRef *MyInfoRef;

/*
 *  StartWWAN()
 *  
 *  Discussion:
 *    This function will initiate a Wireless Wide Area Network (WWAN)
 *     connection by using the CFSocketStream API to connect with a 
 *     server system defined by kTestHost:kTestPort above.
 *     No communications are expected to happen over the CFSocketStream
 *     connection.
 *  
 *    clientCB:
 *     if the connection is opened, the callback routine, if not NULL
 *     will be called. function defintion - see ConnectClientCallBack above
 *     
 *    refCon:
 *     if a client callback, clientCB is defined, then the refCon
 *      parameter will be the argument to the client callback
 *
 *    return:
 *     if the WWAN connection is successful, a MyInfoRef value is returned
 *     The MyInfoRef value must be passed to StopWWAN to stop the WWAN
 *     connection.
 *     A NULL result indicates that the connection was unsuccessful
 *    
 */
extern MyInfoRef StartWWAN(ConnectClientCallBack clientCB, void *refCon);

/*
 *  StopWWAN()
 *  
 *  Discussion:
 *    This function closes the CFSocketStream which was used to establish the
 *    WWAN connection. Once the WWAN connection has been started, BSD
 *    network functions can be used to communicate across the WWAN connection.
 *    As of the writing of this sample, there is no guarantee that the use of
 *    only BSD socket API's will maintain the WWAN connection.
 *  
 *    infoRef:
 *     pass in the MyInfoRef result from the StartWWAN function.
 *     
 */

extern void StopWWAN(MyInfoRef infoRef);

#endif // __WWAN_CONNECT__

wwanconnect.c

// Direct from Apple. Thank you Apple

#include "wwanconnect.h"
#include <CFNetwork/CFSocketStream.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <ifaddrs.h>
#include <stdio.h>

static Boolean TestGetIFAddrs(void);
static void MyCFWriteStreamClientCallBack(CFWriteStreamRef stream, CFStreamEventType type, void *clientCallBackInfo);
static void CleanupAfterWAAN(MyStreamInfoPtr myInfoPtr);
static void CloseStreams(MyStreamInfoPtr myInfoPtr);

static Boolean TestGetIFAddrs(void)
{
    int             result;
    struct  ifaddrs *ifbase, *ifiterator;
    int             done = 0;
    Boolean         addrFound = FALSE;
    char            loopbackname[] = "lo0/0";

    result = getifaddrs(&ifbase);
    ifiterator = ifbase;
    while (!done && (ifiterator != NULL))
    {
        if (ifiterator->ifa_addr->sa_family == AF_INET)
        {
            if (memcmp(ifiterator->ifa_name, loopbackname, 3))
            {
                struct  sockaddr *saddr, *netmask, *daddr;
                saddr = ifiterator->ifa_addr;
                netmask = ifiterator->ifa_netmask;
                daddr = ifiterator->ifa_dstaddr;

                // we've found an entry for the IP address
                struct sockaddr_in  *iaddr;
                char                addrstr[64];
                iaddr = (struct sockaddr_in *)saddr;
                inet_ntop(saddr->sa_family, &iaddr->sin_addr, addrstr, sizeof(addrstr));
                fprintf(stderr, "ipv4 interface name %s, source IP addr %s ", ifiterator->ifa_name, addrstr);

                iaddr = (struct sockaddr_in *)netmask;
                if (iaddr)
                {
                    inet_ntop(saddr->sa_family, &iaddr->sin_addr, addrstr, sizeof(addrstr));
                    fprintf(stderr, "netmask IP addr %s ", addrstr);
                }

                iaddr = (struct sockaddr_in *)daddr;
                if (iaddr)
                {
                    inet_ntop(saddr->sa_family, &iaddr->sin_addr, addrstr, sizeof(addrstr));
                    fprintf(stderr, "dest/broadcast IP addr %s.\n\n", addrstr);
                }
                return TRUE;
            }

        }
        else if (ifiterator->ifa_addr->sa_family == AF_INET6)
        {
            // we've found an entry for the IP address
            struct sockaddr_in6 *iaddr6 = (struct sockaddr_in6 *)ifiterator->ifa_addr;
            char                addrstr[256];
            inet_ntop(ifiterator->ifa_addr->sa_family, iaddr6, addrstr, sizeof(addrstr));
            fprintf(stderr, "ipv6 interface name %s, source IP addr %s \n\n", ifiterator->ifa_name, addrstr);
        }
        ifiterator = ifiterator->ifa_next;
    }
    if (ifbase)
        freeifaddrs(ifbase);    /* done with the memory allocated by getifaddrs */

    return addrFound;
}

static void MyCFWriteStreamClientCallBack(CFWriteStreamRef stream, CFStreamEventType type, void *clientCallBackInfo)
{
    MyStreamInfoPtr myInfoPtr = (MyStreamInfoPtr) clientCallBackInfo;

    printf("MyCFWriteStreamClientCallBack entered - event is %d\n", type);

    switch (type)
    {
        case kCFStreamEventOpenCompleted:
            myInfoPtr->isConnected = TRUE;
            TestGetIFAddrs();       // call the test function to return the local ip address associated with this connection.
            if (myInfoPtr->clientCB)
            {
                // call client callback routine
                myInfoPtr->clientCB(myInfoPtr->refCon);
            }
            printf("write stream connected\n");
            break;

        case kCFStreamEventErrorOccurred:
            myInfoPtr->errorOccurred = TRUE;
            myInfoPtr->error = CFWriteStreamGetError(myInfoPtr->wStreamRef);
            printf("write stream error %d .. giving up\n", myInfoPtr->error.error);
            break;

        default:
            printf("event type %d occurred\n");
            break;
    }
    // stop the run loop at this point
    CFRunLoopStop(CFRunLoopGetCurrent());
}

extern MyInfoRef StartWWAN(ConnectClientCallBack clientCB, void *refCon)
{ 
    char                        host[] = kTestHost;
    int                         portNum = kTestPort;
    CFDataRef                   addressData;
    MyStreamInfoPtr             myInfoPtr;
    CFStreamClientContext       ctxt = {0, NULL, NULL, NULL, NULL};
    Boolean                     errorOccurred = FALSE;

    myInfoPtr = malloc(sizeof(MyStreamInfo));
    if (!myInfoPtr)
    {
        return NULL;
    }

    // init the allocated memory
    memset(myInfoPtr, 0, sizeof(MyStreamInfo));
    myInfoPtr->clientCB = clientCB;
    myInfoPtr->refCon = refCon; 
    ctxt.info = myInfoPtr;

    // Check for a dotted-quad address, if so skip any host lookups 
    in_addr_t addr = inet_addr(host); 
    if (addr != INADDR_NONE) { 
        // Create the streams from numberical host 
        struct sockaddr_in sin; 
        memset(&sin, 0, sizeof(sin)); 

        sin.sin_len= sizeof(sin); 
        sin.sin_family = AF_INET; 
        sin.sin_addr.s_addr = addr; 
        sin.sin_port = htons(portNum); 

        addressData = CFDataCreate(NULL, (UInt8 *)&sin, sizeof(sin)); 
        CFSocketSignature sig = { AF_INET, SOCK_STREAM, IPPROTO_TCP, addressData }; 

        // Create the streams. 
        CFStreamCreatePairWithPeerSocketSignature(kCFAllocatorDefault, &sig, &(myInfoPtr->rStreamRef), &(myInfoPtr->wStreamRef));       
        CFRelease(addressData); 
    } else { 
        // Create the streams from ascii host name 
        CFStringRef hostStr = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, host, kCFStringEncodingUTF8, kCFAllocatorNull); 
        CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, hostStr, portNum, &(myInfoPtr->rStreamRef), &(myInfoPtr->wStreamRef)); 
    } 

    myInfoPtr->isConnected = FALSE;
    myInfoPtr->isStreamInitd = TRUE;
    myInfoPtr->isClientSet = FALSE;

    // Inform the streams to kill the socket when it is done with it. 
    // This effects the write stream too since the pair shares the 
    // one socket. 
    CFWriteStreamSetProperty(myInfoPtr->wStreamRef, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue); 

    // set up the client
    if (!CFWriteStreamSetClient(myInfoPtr->wStreamRef, kCFStreamEventOpenCompleted | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, 
                                MyCFWriteStreamClientCallBack, &ctxt))
    {
        printf("CFWriteStreamSetClient failed\n");
        errorOccurred = TRUE;
    }
    else
        myInfoPtr->isClientSet = TRUE;

    if (!errorOccurred)
    {
        // schedule the stream
        CFWriteStreamScheduleWithRunLoop(myInfoPtr->wStreamRef, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);

        // Try to open the stream.
        if (!CFWriteStreamOpen(myInfoPtr->wStreamRef))
        {
            printf("CFWriteStreamOpen failed\n");
            errorOccurred = TRUE;
        }
    }

    if (!errorOccurred)
    {
        // everything worked so far, so run the runloop - when the callback gets called, it will stop the run loop
        printf("CFWriteStreamOpen returned with no error - calling CFRunLoopRun\n");
        CFRunLoopRun();
        if (myInfoPtr->errorOccurred)
            errorOccurred = TRUE;
        printf("after CFRunLoopRun - returning\n");
    }

    if (errorOccurred)
    {
        myInfoPtr->isConnected = FALSE;
        CleanupAfterWAAN(myInfoPtr);
        CloseStreams(myInfoPtr);

        if (myInfoPtr->isStreamInitd)
        {
            CFRelease(myInfoPtr->rStreamRef);
            CFRelease(myInfoPtr->wStreamRef);
            myInfoPtr->isStreamInitd = FALSE;
        }
        free(myInfoPtr);
        return NULL;
    }
    return (MyInfoRef)myInfoPtr;
} 

static void CleanupAfterWAAN(MyStreamInfoPtr myInfoPtr)
{
    assert(myInfoPtr != NULL);
    if (myInfoPtr->isClientSet)
    {
        CFWriteStreamSetClient(myInfoPtr->wStreamRef, 0, NULL, NULL);
        CFWriteStreamUnscheduleFromRunLoop(myInfoPtr->wStreamRef, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
        myInfoPtr->isClientSet = FALSE;
    }
}

static void CloseStreams(MyStreamInfoPtr myInfoPtr)
{
    assert(myInfoPtr != NULL);
    if (myInfoPtr->rStreamRef)
    {
        CFReadStreamClose(myInfoPtr->rStreamRef);
        myInfoPtr->rStreamRef = NULL;
    }
    if (myInfoPtr->wStreamRef)
    {
        CFWriteStreamClose(myInfoPtr->wStreamRef);
        myInfoPtr->wStreamRef = NULL;
    }
}

extern void StopWWAN(MyInfoRef infoRef)
{
    MyStreamInfoPtr myInfoPtr = (MyStreamInfoPtr)infoRef;

    printf("stopWWAN entered\n");
    assert(myInfoPtr != NULL);
    myInfoPtr->isConnected = FALSE;
    CleanupAfterWAAN(myInfoPtr);
    CloseStreams(myInfoPtr);
    free(myInfoPtr);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文