CIapProcess.h
#import <Foundation/Foundation.h> #import <StoreKit/StoreKit.h> @protocol IapProcessDelegate <NSObject> -(void)iapProcessBegin; -(void)iapProcessEndWithError:(NSString*)errorString; -(void)showProductByArray:(NSArray*)profuctArray; -(void)transactionSuccess:(SKPaymentTransaction*)transaction; -(void)transactionFail:(SKPaymentTransaction*)transaction; -(void)restoredSuccess:(SKPaymentTransaction*)transaction; -(void)restoredFailWithString:(NSString*)error; @end @interface CIapProcess : NSObject<SKProductsRequestDelegate, SKPaymentTransactionObserver> @property(nonatomic,copy)NSString* productId; @property(nonatomic,assign)id<IapProcessDelegate> delegate; -(void)resquestProductList:(NSArray*)identifierArray;//请求产品列表 -(void)resquestProductByIdentifier:(NSString*)identifier;//请求产品 -(void)restorePurchas;//恢复产品 -(void)payforProductByIdentifier:(NSString*)identifier;//进入付费处理 @end
CIapProcess.m
#import "CIapProcess.h"
#import "Reachability.h"
@interface CIapProcess()
-(BOOL)checkNetWork;
-(BOOL)iapBegin;
@end
@implementation CIapProcess
@synthesize delegate;
@synthesize productId;
//请求产品列表,有多个id
-(void)resquestProductList:(NSArray*)identifierArray{
if (![self iapBegin]) {
return;
}
self.productId = nil;
SKProductsRequest* request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:identifierArray]];
request.delegate = self;
[request start];
}
//请求产品,一个id
-(void)resquestProductByIdentifier:(NSString*)identifier{
if (![self iapBegin]) {
return;
}
self.productId = identifier;
SKProductsRequest* productRequest=[[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:identifier]];
productRequest.delegate=self;
[productRequest start];
}
//恢复产品
-(void)restorePurchas{
if (![self iapBegin]) {
return;
}
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
//开始进行IAP处理
-(BOOL)iapBegin{
if ([self.delegate respondsToSelector:@selector(iapProcessBegin)]) {
[self.delegate iapProcessBegin];
}
return [self checkNetWork];
}
-(BOOL)checkNetWork{
Reachability* reachability = [Reachability reachabilityWithHostName:@"www.apple.com"];
NetworkStatus status = [reachability currentReachabilityStatus];
if (NotReachable != status) {
return YES;
}
if ([self.delegate respondsToSelector:@selector(iapProcessEndWithError:)]) {
[self.delegate iapProcessEndWithError:@"没有可用的网络"];
}
return NO;
}
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
-(void)payforProductByIdentifier:(NSString*)identifier{
if ([SKPaymentQueue canMakePayments]) {
SKPayment* payment = [SKPayment paymentWithProductIdentifier:identifier];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}else{
if ([self.delegate respondsToSelector:@selector(iapProcessEndWithError:)]) {
[self.delegate iapProcessEndWithError:@"You are not authorized to purchase from AppStore"];
}
}
}
#pragma mark-
#pragma mark SKProductsRequestDelegate
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
NSArray* productArray = [[NSArray alloc] initWithArray:response.products];
switch ([productArray count]) {
case 0:
if ([self.delegate respondsToSelector:@selector(iapProcessEndWithError:)]) {
[self.delegate iapProcessEndWithError:@"产品不存在"];
}
break;
case 1:
[self payforProductByIdentifier:[[productArray objectAtIndex:0] productIdentifier]];
break;
default:
if ([self.delegate respondsToSelector:@selector(showProductByArray:)]) {
[self.delegate showProductByArray:productArray];
}
break;
}
[request autorelease];
}
#pragma mark -
#pragma mark SKPaymentTransactionObserver
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
for (SKPaymentTransaction* transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased:
if ([self.delegate respondsToSelector:@selector(transactionSuccess:)]) {
[self.delegate transactionSuccess:transaction];
}
break;
case SKPaymentTransactionStateFailed:
if ([self.delegate respondsToSelector:@selector(transactionFail:)]) {
[self.delegate transactionFail:transaction];
}
break;
case SKPaymentTransactionStateRestored:
if ([self.delegate respondsToSelector:@selector(restoredSuccess:)]) {
[self.delegate restoredSuccess:transaction];
}
break;
default:
break;
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
}
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error{
if ([self.delegate respondsToSelector:@selector(restoredFailWithString:)]) {
[self.delegate restoredFailWithString:[error description]];
}
}
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue{
if (0 >= [queue.transactions count]) {
if ([self.delegate respondsToSelector:@selector(restoredFailWithString:)]) {
[self.delegate restoredFailWithString:@"没有可以恢复的交易"];
}
}
}
@end
为了方便,这里将那几个代理方法设置为必需实现,你可以只实现部分。
附上检测网络用的那个类:
Reachability.h
#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
typedef enum {
NotReachable = 0,
ReachableViaWiFi,
ReachableViaWWAN
} NetworkStatus;
#define kReachabilityChangedNotification @"kNetworkReachabilityChangedNotification"
@interface Reachability: NSObject
{
BOOL localWiFiRef;
SCNetworkReachabilityRef reachabilityRef;
}
//reachabilityWithHostName- Use to check the reachability of a particular host name.
+ (Reachability*) reachabilityWithHostName: (NSString*) hostName;
//reachabilityWithAddress- Use to check the reachability of a particular IP address.
+ (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress;
//reachabilityForInternetConnection- checks whether the default route is available.
// Should be used by applications that do not connect to a particular host
+ (Reachability*) reachabilityForInternetConnection;
//reachabilityForLocalWiFi- checks whether a local wifi connection is available.
+ (Reachability*) reachabilityForLocalWiFi;
//Start listening for reachability notifications on the current run loop
- (BOOL) startNotifier;
- (void) stopNotifier;
- (NetworkStatus) currentReachabilityStatus;
//WWAN may be available, but not active until a connection has been established.
//WiFi may require a connection for VPN on Demand.
- (BOOL) connectionRequired;
@end
Reachability.m
#import <sys/socket.h>
#import <netinet/in.h>
#import <netinet6/in6.h>
#import <arpa/inet.h>
#import <ifaddrs.h>
#import <netdb.h>
#import <CoreFoundation/CoreFoundation.h>
#import "Reachability.h"
#define kShouldPrintReachabilityFlags 1
static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
{
#if kShouldPrintReachabilityFlags
NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
(flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
(flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
(flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-',
(flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
(flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-',
(flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
(flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-',
comment
);
#endif
}
@implementation Reachability
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
{
#pragma unused (target, flags)
NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
//We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively
// in case someon uses the Reachablity object in a different thread.
NSAutoreleasePool* myPool = [[NSAutoreleasePool alloc] init];
Reachability* noteObject = (Reachability*) info;
// Post a notification to notify the client that the network reachability changed.
[[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];
[myPool release];
}
- (BOOL) startNotifier
{
BOOL retVal = NO;
SCNetworkReachabilityContext context = {0, self, NULL, NULL, NULL};
if(SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context))
{
if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
{
retVal = YES;
}
}
return retVal;
}
- (void) stopNotifier
{
if(reachabilityRef!= NULL)
{
SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}
}
- (void) dealloc
{
[self stopNotifier];
if(reachabilityRef!= NULL)
{
CFRelease(reachabilityRef);
}
[super dealloc];
}
+ (Reachability*) reachabilityWithHostName: (NSString*) hostName;
{
Reachability* retVal = NULL;
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
if(reachability!= NULL)
{
retVal= [[[self alloc] init] autorelease];
if(retVal!= NULL)
{
retVal->reachabilityRef = reachability;
retVal->localWiFiRef = NO;
}
}
return retVal;
}
+ (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress;
{
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress);
Reachability* retVal = NULL;
if(reachability!= NULL)
{
retVal= [[[self alloc] init] autorelease];
if(retVal!= NULL)
{
retVal->reachabilityRef = reachability;
retVal->localWiFiRef = NO;
}
}
return retVal;
}
+ (Reachability*) reachabilityForInternetConnection;
{
struct sockaddr_in zeroAddress;
bzero(&zeroAddress, sizeof(zeroAddress));
zeroAddress.sin_len = sizeof(zeroAddress);
zeroAddress.sin_family = AF_INET;
return [self reachabilityWithAddress: &zeroAddress];
}
+ (Reachability*) reachabilityForLocalWiFi;
{
struct sockaddr_in localWifiAddress;
bzero(&localWifiAddress, sizeof(localWifiAddress));
localWifiAddress.sin_len = sizeof(localWifiAddress);
localWifiAddress.sin_family = AF_INET;
// IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
Reachability* retVal = [self reachabilityWithAddress: &localWifiAddress];
if(retVal!= NULL)
{
retVal->localWiFiRef = YES;
}
return retVal;
}
#pragma mark Network Flag Handling
- (NetworkStatus) localWiFiStatusForFlags: (SCNetworkReachabilityFlags) flags
{
PrintReachabilityFlags(flags, "localWiFiStatusForFlags");
BOOL retVal = NotReachable;
if((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect))
{
retVal = ReachableViaWiFi;
}
return retVal;
}
- (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags
{
PrintReachabilityFlags(flags, "networkStatusForFlags");
if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
{
// if target host is not reachable
return NotReachable;
}
BOOL retVal = NotReachable;
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
retVal = ReachableViaWiFi;
}
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
retVal = ReachableViaWiFi;
}
}
if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
{
// ... but WWAN connections are OK if the calling application
// is using the CFNetwork (CFSocketStream?) APIs.
retVal = ReachableViaWWAN;
}
return retVal;
}
- (BOOL) connectionRequired;
{
NSAssert(reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
{
return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
}
return NO;
}
- (NetworkStatus) currentReachabilityStatus
{
NSAssert(reachabilityRef != NULL, @"currentNetworkStatus called with NULL reachabilityRef");
NetworkStatus retVal = NotReachable;
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
{
if(localWiFiRef)
{
retVal = [self localWiFiStatusForFlags: flags];
}
else
{
retVal = [self networkStatusForFlags: flags];
}
}
return retVal;
}
@end