內(nèi)購


#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

//typedef NS_ENUM(NSUInteger, APTYPE) {
//    AP_WECHAT,
//    AP_ALIPAY,
//};


//@protocol APDelegate <NSObject>
//-(void)APSuccess:(APTYPE)type;
//-(void)APFail:(APTYPE)type;
//@end


static NSString * const USERDEFAULT_KEY = @"transaction";

typedef enum : NSUInteger {
    VTPaymentTransactionStateNoPaymentPermission,//沒有Payment權(quán)限
    VTPaymentTransactionStateAddPaymentFailed,//addPayment失敗
    VTPaymentTransactionStatePurchasing,//正在購買
    VTPaymentTransactionStatePurchased,//購買完成(銷毀交易)
    VTPaymentTransactionStateFailed,//購買失敗(銷毀交易)
    VTPaymentTransactionStateCancel,//用戶取消
    VTPaymentTransactionStateRestored,//恢復(fù)購買(銷毀交易)
    VTPaymentTransactionStateDeferred,//最終狀態(tài)未確定
} VTPaymentTransactionState;

@class SKPaymentTransaction;

@protocol VTInAppPurchasingDelegate <NSObject>

@required
- (BOOL)isProductIdentifierAvailable:(NSString*)productIdentifier;
@optional
- (void)updatedTransactions:(VTPaymentTransactionState)state;
//購買成功
- (void)buySuccess;
//購買失敗
- (void)buyFailed:(NSString*)errorInfo;

@end



@interface APManager : NSObject

+(instancetype) shared;

@property(nonatomic,weak) id<VTInAppPurchasingDelegate> delegate;
- (void)identifyCanMakePayments:(NSArray*)requestArray;
//-(void)handleOpenURL:(NSURL *)url;
//-(void)sendOrder:(APTYPE)type Order:(NSDictionary *)order;

@end

NS_ASSUME_NONNULL_END
#import "APManager.h"
#import <StoreKit/StoreKit.h>
//#import "WXApi.h"
//#import <AlipaySDK/AlipaySDK.h>

//#define WECHAT @"pay"
//#define WECHATSCHEME @""
//#define ALIPAY @"safepay"
//#define ALIPAYSCHEME @"alipay"
//#define WX_AppID @""


#define ITMS_VERIFY_RECEIPT_URL   @"https://sandbox.itunes.apple.com/verifyReceipt"
//@"https://buy.itunes.apple.com/verifyReceipt"

#define isServiceVerify 0

@interface APManager ()<SKPaymentTransactionObserver,SKProductsRequestDelegate/*WXApiDelegate*/>
@property (nonatomic, strong) SKProductsRequest *request;
@end

@implementation APManager


+(instancetype) shared{
    static APManager *_singleInstance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _singleInstance = [[APManager alloc]init];
    });
    
    return _singleInstance;
}


-(instancetype)init{
    if (self = [super init]) {
        
         [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    //微信支付
//        [WXApi registerApp:WX_AppID];
    }
    return self;
}


- (void)identifyCanMakePayments:(NSArray*)requestArray{
    if (requestArray.count == 0) {
        if (self.delegate && [self.delegate respondsToSelector:@selector(updatedTransactions:)]) {
            [self.delegate updatedTransactions:VTPaymentTransactionStateAddPaymentFailed];
        }
        return;
    }
    
    if ([SKPaymentQueue canMakePayments]) {
        [self releaseRequest];
        self.request = [[SKProductsRequest alloc]initWithProductIdentifiers:[NSSet setWithArray:requestArray]];
        self.request.delegate = self;
        [self.request start];
    }else{
        if (self.delegate && [self.delegate respondsToSelector:@selector(updatedTransactions:)]) {
            [self.delegate updatedTransactions:VTPaymentTransactionStateNoPaymentPermission];
        }
    }
    
}




- (void)releaseRequest{
    if(_request) {
        [_request cancel];
        _request.delegate=nil;
        _request=nil;
    }
}

-(void)dealloc{
    [self releaseRequest];
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}


#pragma mark ------------ SKProductsRequestDelegate

- (void)productsRequest:(SKProductsRequest*)request didReceiveResponse:(SKProductsResponse*)response{
    NSArray * myProducts = response.products;
    for(SKProduct*product in myProducts){
        NSLog(@"SKProduct 描述信息%@", [product description]);
        NSLog(@"產(chǎn)品標題 %@", product.localizedTitle);
        NSLog(@"產(chǎn)品描述信息: %@" , product.localizedDescription);
        NSLog(@"價格: %@", product.price);
        NSLog(@"Product id: %@" , product.productIdentifier);
        
        
        
        if (self.delegate && [self.delegate respondsToSelector:@selector(isProductIdentifierAvailable:)]) {
            if ([self.delegate isProductIdentifierAvailable:product.productIdentifier]) {
                SKPayment *payment = [SKPayment paymentWithProduct:product];
                [[SKPaymentQueue defaultQueue] addPayment:payment];
                return;
            }
        }
    }
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(updatedTransactions:)]) {
        [self.delegate updatedTransactions:VTPaymentTransactionStateAddPaymentFailed];
    }
   
}

- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
    NSLog(@"-------彈出錯誤信息----------");
    
}

#pragma mark -------- SKPaymentTransactionObserver


-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions{
    
    for (SKPaymentTransaction *transaction in transactions) {
        VTPaymentTransactionState state;
        switch (transaction.transactionState) {
            case SKPaymentTransactionStatePurchasing:
                
                state = VTPaymentTransactionStatePurchasing;
                
                break;
            case SKPaymentTransactionStatePurchased:
                
                //防止漏單
//                [[NSUserDefaults standardUserDefaults] setObject:transaction forKey:USERDEFAULT_KEY];
//                [[NSUserDefaults standardUserDefaults] synchronize];
                
                state = VTPaymentTransactionStatePurchased;
                if (isServiceVerify) {
                    [self completeTransaction:transaction];
                }else{
                    [self verifyPurchase:transaction];
                }
                
                break;
            case SKPaymentTransactionStateFailed:
            {
                if (transaction.error.code!= SKErrorPaymentCancelled) {
                    state = VTPaymentTransactionStateFailed;
                }else{
                    state = VTPaymentTransactionStateCancel;
                }
                [self finshTransaction:transaction];
            }
                break;
            case SKPaymentTransactionStateRestored:
                state = VTPaymentTransactionStateRestored;
                [self finshTransaction:transaction];
                break;
            case SKPaymentTransactionStateDeferred:
                state = VTPaymentTransactionStateDeferred;
                break;
            default:
                break;
        }
        
        
        if (self.delegate && [self.delegate respondsToSelector:@selector(updatedTransactions:)]) {
            [self.delegate updatedTransactions:state];
        }
    }
}

// Sent when an error is encountered while adding transactions from the user's purchase history back to the queue.
- (void)paymentQueue:(SKPaymentQueue*)queue restoreCompletedTransactionsFailedWithError:(NSError*)error
{
    NSLog(@"restoreCompletedTransactionsFailedWithError");
}
// Sent when all transactions from the user's purchase history have successfully been added back to the queue.
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue*)queue
{
    NSLog(@"paymentQueueRestoreCompletedTransactionsFinished");
}
// Sent when the download state has changed.
- (void)paymentQueue:(SKPaymentQueue*)queue updatedDownloads:(NSArray *)downloads
{
    NSLog(@"updatedDownloads");
}


- (void)paymentQueue:(SKPaymentQueue*)queue removedTransactions:(NSArray *)transactions
{
    NSLog(@"---removedTransactions");
}


#pragma mark ------ private methods

- (void)completeTransaction:(SKPaymentTransaction*)transaction{
    //服務(wù)器校驗
    
}

- (void)verifyPurchase:(SKPaymentTransaction*)transaction{
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    NSData*receiptData = [NSData dataWithContentsOfURL:receiptURL];
    NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
    NSURL *url = [NSURL URLWithString:ITMS_VERIFY_RECEIPT_URL];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];
    
    NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
    NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];
    [request setHTTPBody:payloadData];
    [request setHTTPMethod:@"POST"];
    NSURLResponse*response = nil;
    // 此請求返回的是一個json結(jié)果  將數(shù)據(jù)反序列化為數(shù)據(jù)字典
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
    if(data ==nil) {
        return;
    }
    NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
    if(jsonResponse !=nil) {
        if([[jsonResponse objectForKey:@"status"]intValue] ==0)
            {
                //通常需要校驗:bid轩拨,product_id,purchase_date徘六,status
                if (self.delegate && [self.delegate respondsToSelector:@selector(buySuccess)]) {
                    [self.delegate buySuccess];
                }
            }
        else
            {
                if (self.delegate && [self.delegate respondsToSelector:@selector(buyFailed:)]) {
                    [self.delegate buyFailed:@""];
                }
                //驗證失敗字逗,檢查你的機器是否越獄
            }
        
        [[NSUserDefaults standardUserDefaults] removeObjectForKey:USERDEFAULT_KEY];
        
    }else{
        if (self.delegate && [self.delegate respondsToSelector:@selector(buyFailed:)]) {
            [self.delegate buyFailed:@""];
        }
    }
    
    
    
    //結(jié)束交易
    [self finshTransaction:transaction];
    
}

- (void)finshTransaction:(SKPaymentTransaction*)transaction
{
    //結(jié)束交易
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}


//-(void)handleOpenURL:(NSURL *)url{
//    if ([url.host isEqualToString:WECHAT]) {
//        [WXApi handleOpenURL:url delegate:self];
//    }else if ([url.host isEqualToString:ALIPAY]){
//        // 支付跳轉(zhuǎn)支付寶錢包進行支付赛糟,處理支付結(jié)果
//        [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
//            NSLog(@"result = %@",resultDic);
//        }];
//
////        // 授權(quán)跳轉(zhuǎn)支付寶錢包進行支付疚沐,處理支付結(jié)果
////        [[AlipaySDK defaultService] processAuth_V2Result:url standbyCallback:^(NSDictionary *resultDic) {
////            NSLog(@"result = %@",resultDic);
////            // 解析 auth code
////            NSString *result = resultDic[@"result"];
////            NSString *authCode = nil;
////            if (result.length>0) {
////                NSArray *resultArr = [result componentsSeparatedByString:@"&"];
////                for (NSString *subResult in resultArr) {
////                    if (subResult.length > 10 && [subResult hasPrefix:@"auth_code="]) {
////                        authCode = [subResult substringFromIndex:10];
////                        break;
////                    }
////                }
////            }
////            NSLog(@"授權(quán)結(jié)果 authCode = %@", authCode?:@"");
////        }];
//    }
//}
//
//-(void)sendOrder:(APTYPE)type Order:(NSDictionary *)order{
//    switch (type) {
//        case AP_ALIPAY:
//        {
//            NSString *orderString = [order objectForKey:@"orderString"];
//            [[AlipaySDK defaultService] payOrder:orderString fromScheme:ALIPAYSCHEME callback:^(NSDictionary *resultDic) {
//                NSLog(@"reslut = %@",resultDic);
//            }];
//        }
//            break;
//        case AP_WECHAT:
//        {
//            PayReq *request = [[PayReq alloc] init];
//            request.openID = [order objectForKey:@"appid"];
//            request.partnerId = [order objectForKey:@"partnerid"];
//            request.prepayId= [order objectForKey:@"prepayid"];
//            request.package = [order objectForKey:@"package"];
//            request.nonceStr= [order objectForKey:@"noncestr"];
//            request.timeStamp = [[order objectForKey:@"timestamp"] intValue];
//            request.sign = [order objectForKey:@"sign"];
//            [WXApi sendReq:request];
//        }
//            break;
//        default:
//            break;
//    }
//}


//#pragma mark ----WXApiDelegate-----

//- (void)onResp:(BaseResp *)resp{
//    if ([resp isKindOfClass:[PayResp class]]) {
//        PayResp*response=(PayResp*)resp;  // 微信終端返回給第三方的關(guān)于支付結(jié)果的結(jié)構(gòu)體
//        switch (response.errCode) {
//            case WXSuccess:
//            {// 支付成功魄宏,向后臺發(fā)送消息
//                NSLog(@"支付成功");
//            }
//                break;
//            case WXErrCodeCommon:
//            { //簽名錯誤、未注冊APPID台盯、項目設(shè)置APPID不正確罢绽、注冊的APPID與設(shè)置的不匹配、其他異常等
//                NSLog(@"支付失敗");
//            }
//                break;
//            case WXErrCodeUserCancel:
//            { //用戶點擊取消并返回
//                NSLog(@"取消支付");
//            }
//                break;
//            case WXErrCodeSentFail:
//            { //發(fā)送失敗
//                NSLog(@"發(fā)送失敗");
//            }
//                break;
//            case WXErrCodeUnsupport:
//            { //微信不支持
//                NSLog(@"微信不支持");
//            }
//                break;
//            case WXErrCodeAuthDeny:
//            { //授權(quán)失敗
//                NSLog(@"授權(quán)失敗");
//            }
//                break;
//            default:
//                break;
//        }
//    }
//}

@end
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末静盅,一起剝皮案震驚了整個濱河市良价,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌温亲,老刑警劉巖棚壁,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異栈虚,居然都是意外死亡袖外,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門魂务,熙熙樓的掌柜王于貴愁眉苦臉地迎上來曼验,“玉大人,你說我怎么就攤上這事粘姜△拚眨” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵孤紧,是天一觀的道長豺裆。 經(jīng)常有香客問我,道長号显,這世上最難降的妖魔是什么臭猜? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮押蚤,結(jié)果婚禮上蔑歌,老公的妹妹穿的比我還像新娘。我一直安慰自己揽碘,他們只是感情好次屠,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著雳刺,像睡著了一般劫灶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上掖桦,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天浑此,我揣著相機與錄音,去河邊找鬼滞详。 笑死凛俱,一個胖子當著我的面吹牛紊馏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蒲犬,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼朱监,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了原叮?” 一聲冷哼從身側(cè)響起赫编,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎奋隶,沒想到半個月后擂送,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡唯欣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年嘹吨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片境氢。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蟀拷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出萍聊,到底是詐尸還是另有隱情问芬,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布寿桨,位于F島的核電站此衅,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏亭螟。R本人自食惡果不足惜挡鞍,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望媒佣。 院中可真熱鬧匕累,春花似錦陵刹、人聲如沸默伍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽也糊。三九已至,卻和暖如春羡宙,著一層夾襖步出監(jiān)牢的瞬間狸剃,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工狗热, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留钞馁,地道東北人虑省。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像僧凰,于是被迫代替她去往敵國和親探颈。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容