如果互联网连接可用,我正在尝试找到一种方法让我的应用程序上的信息屏幕从网上下载(这样我就可以定期更新它)。如果互联网不可用,它应该使用默认或最后下载的。这可能吗?
问问题
2681 次
1 回答
2
请注意,上面 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);
}
于 2009-05-30T09:00:35.717 回答