2009-05-30 5 views
1

J'essaie de trouver un moyen de télécharger l'écran d'information sur mon application à partir du Web SI une connexion Internet est disponible (pour que je puisse la mettre à jour régulièrement). Si Internet n'est pas disponible, il doit utiliser la valeur par défaut ou la dernière téléchargée. Est-ce possible?Écran d'informations dynamiques

Répondre

2

S'il vous plaît noter que la méthode proposée par James Skitmore ci-dessus est un moyen terrible pour tester la connectivité. S'il vous plaît faire pas l'utiliser. Il chargera inutilement google.com, ce qui entraînera un timeout si le réseau n'est pas disponible, ce qui rendra votre application figée.

Voici comment vous pouvez vérifier la connectivité réseau.

Dans votre application, vous pouvez le faire pour vérifier si le réseau est disponible:

if (![[UIDevice currentDevice] networkAvailable]) 

Vous pouvez maintenant vérifier également la connectivité à un certain hôte, comme yourwebsite.com, ou vous pouvez vérifier la type de connexion, 3G vs Wifi, etc. Je vous laisse le découvrir en lisant les fichiers d'en-tête.

Vous allez avoir besoin d'inclure les fichiers suivants à votre application: (avec la permission de 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); 
}