Files
LayaNative2.0/Conch/build/wkwebview/proj.ios/WKWebview/iap/IAPManager.m
T
2020-11-11 16:17:13 +08:00

340 lines
14 KiB
Objective-C

#import "IAPManager.h"
#define __MAX_GAME_ID_SIZE 32
typedef void (^IAPProductsResponseBlock)(SKProductsRequest* request , SKProductsResponse* response);
typedef void (^IAPcheckReceiptCompleteResponseBlock)(NSString* response,NSError* error);
@interface IAPManager()<NSURLConnectionDataDelegate>
@property (nonatomic,copy) IAPProductsResponseBlock requestProductsBlock;
@property (nonatomic,copy) IAPcheckReceiptCompleteResponseBlock checkReceiptCompleteBlock;
@property (nonatomic,assign) id<JCIapProcessCtrlDelegate> delegate;
@property (nonatomic,strong) NSString* gameAppID;
@property (nonatomic,strong) SKProductsRequest *request;
@property (nonatomic,strong) NSString *strPlateform;
@property (nonatomic,assign) BOOL isProcessing;
@property (nonatomic,strong) NSMutableData* receiptRequestData;
@end
@implementation IAPManager
+ (IAPManager*) getInstance{
static IAPManager* iap = nil;
if (iap == nil){
iap = [IAPManager alloc];
}
return iap;
}
- (id)initWithGameID:(NSString*)gameID andDelegate:(id<JCIapProcessCtrlDelegate>)delegate{
if ((self = [super init])) {
NSAssert(gameID != nil,@"[IAP] gameID can not be nil");
NSAssert(gameID.length <= __MAX_GAME_ID_SIZE,@"gameID is too long");
self.gameAppID = [NSString stringWithString:gameID];
NSAssert(delegate != nil, @"[IAP] delegate can not be nil");
self.delegate = delegate;
self.strPlateform = [NSString stringWithFormat:@"%@,%@,%@", [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemName],[[UIDevice currentDevice] systemVersion]];
NSLog(@"[IAP]plateform info: %@\n", self.strPlateform);
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
self.isProcessing = NO;
}
return self;
}
- (void)dealloc
{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}
- (void)requestProducts:(NSSet *)productIdentifiers onCompletion:(IAPProductsResponseBlock)completion {
self.request = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
self.request.delegate = self;
self.requestProductsBlock = completion;
[self.request start];
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
self.request = nil;
if(self.requestProductsBlock) {
self.requestProductsBlock (request,response);
}
}
//-------------------------------------------------------------------------------
- (void)completeTransaction:(SKPaymentTransaction *)transaction {
NSLog(@"[IAP] SKPaymentTransactionStatePurchased");
[self doVerifyTransaction:transaction];
}
- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
NSLog(@"[IAP] SKPaymentTransactionStateRestored");
[self doVerifyTransaction:transaction];
}
- (void)failedTransaction:(SKPaymentTransaction *)transaction {
NSLog(@"[IAP] Transaction error: %@ %ld", transaction.error.localizedDescription,(long)transaction.error.code);
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
NSLog(@"[IAP] SKPaymentTransactionStateFailed");
NSMutableDictionary *paymentmulti =(NSMutableDictionary *)[NSKeyedUnarchiver unarchiveObjectWithData:transaction.payment.requestData];
NSString* _order_id = [paymentmulti objectForKey:@"order_id"];
self.isProcessing = NO;
[self.delegate onFailed:transaction.payment.productIdentifier quantity:transaction.payment.quantity orderID:_order_id];
}
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased:
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
[self restoreTransaction:transaction];
default:
break;
}
}
}
//-------------------------------------------------------------------------------
-(void)recharge:(NSString*) jsonParam
{
if (self.isProcessing == YES){
self.isProcessing = NO;
NSLog(@"[IAP] another payments is processing!\n");
return;
}
self.isProcessing = YES;
NSLog(@"[IAP] this is MarketAppStore method pay param=%@",jsonParam);
if(jsonParam==NULL)
{
self.isProcessing = NO;
NSLog(@"[IAP] recharge param is nil!\n");
[self.delegate onFailed:@"nill" quantity:0 orderID:@"nill"];
return;
}
NSData* pJsonData = [jsonParam dataUsingEncoding:NSUTF8StringEncoding];
NSError* pError;
NSDictionary* pJson = [NSJSONSerialization JSONObjectWithData:pJsonData options:kNilOptions error:&pError];
if( !pError )
{
NSString* sProductID = [pJson objectForKey:@"product_id"];
int nNum = [[pJson objectForKey:@"amount"] intValue];
NSString* sOrderID = [pJson objectForKey:@"order_id"];
NSString* sCallbackURL = [pJson objectForKey:@"callback_uri"];
NSLog(@"[IAP] buyProps: product_id=%@, amount=%d, order_id=%@,callbackurl=%@",sProductID, nNum, sOrderID,sCallbackURL );
if( nNum <= 0 || nil == sProductID || nil == sOrderID || nil == sCallbackURL)
{
self.isProcessing = NO;
NSLog(@"[IAP] param error!\n");
[self.delegate onFailed:sProductID quantity:nNum orderID:sOrderID];
return;
}
if([SKPaymentQueue canMakePayments] == NO)
{
self.isProcessing = NO;
NSLog(@"[IAP] can not make payments!\n");
[self.delegate onFailed:sProductID quantity:nNum orderID:sOrderID];
return;
}
NSArray* transactions = [SKPaymentQueue defaultQueue].transactions;
if (transactions.count > 0)
{
//检测是否有未完成的交易
SKPaymentTransaction* transaction = [transactions firstObject];
if (transaction.transactionState == SKPaymentTransactionStatePurchased)
{
NSLog(@"[IAP] process uncompleteed transaction");
[self doVerifyTransaction:transaction];
}
}
NSLog(@"[IAP] 开始向苹果请求产品信息");
[self requestProducts:[[NSSet alloc] initWithObjects:sProductID, nil] onCompletion:^(SKProductsRequest* request,SKProductsResponse* response)
{
NSLog(@"[IAP] 苹果返回产品信息。");
if(response.products.count > 0 ) {
SKProduct* product =response.products[0];
NSMutableString *resOutput = [[NSMutableString alloc] init];
[resOutput appendString:@"[IAP] IAP Response Info\n"];
[resOutput appendFormat:@"%@,%@,%@,%@,%@\n",
product.localizedTitle, // 本地化标题
product.localizedDescription, // 本地化描述
product.price, // 价格
product.priceLocale, // 地域
product.productIdentifier]; // 产品标识符
NSLog(@"%@",resOutput);
SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:product];
NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
[dict setObject:sOrderID forKey:@"order_id"];
[dict setObject:sCallbackURL forKey:@"backurl"];
[dict setObject:self.gameAppID forKey:@"gameid"];
NSData* pData = [NSKeyedArchiver archivedDataWithRootObject:dict];
payment.requestData = pData;
payment.quantity = nNum;
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
else{
self.isProcessing = NO;
NSLog(@"[IAP] invalid product!\n");
[self.delegate onFailed:sProductID quantity:nNum orderID:sOrderID];
}
// 错误的产品 ID 回馈
NSMutableString *resOutput = [[NSMutableString alloc] init];
for( NSString *invalidProductId in response.invalidProductIdentifiers )
{
[resOutput appendFormat:@"[IAP] Invalid product id: %@\n",invalidProductId];
}
NSLog(@"%@",resOutput);
}];
}
else
{
self.isProcessing = NO;
NSLog(@"[IAP] buyProps:parser json error");
[self.delegate onFailed:@"nill" quantity:0 orderID:@"nill"];
}
}
// 向验证服务器发起验证请求
- (void)doVerifyTransaction: (SKPaymentTransaction *)transaction
{
if (transaction == nil)
return;
if(NULL==transaction.payment.requestData)
{
self.isProcessing = NO;
NSLog(@"[IAP] transDoVerifyTransaction requestData is null");
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
[self.delegate onFailed:@"nill" quantity:0 orderID:@"nill"];
return;
}
NSMutableDictionary *paymentmulti =(NSMutableDictionary *)[NSKeyedUnarchiver unarchiveObjectWithData:transaction.payment.requestData];//
NSString* _order_id = [paymentmulti objectForKey:@"order_id"];
NSString* _backurl = [paymentmulti objectForKey:@"backurl"];
NSString* _gameid = [paymentmulti objectForKey:@"gameid"];
NSLog(@"[IAP] order:%@backurl:%@gameid:%@",_order_id,_backurl,_gameid);
NSString* pszBase64 = [transaction.transactionReceipt base64Encoding];
if(NULL==_order_id||NULL==_backurl||NULL==_gameid||NULL==self.strPlateform||NULL==transaction.payment.productIdentifier||NULL==transaction.transactionIdentifier)
{
self.isProcessing = NO;
NSLog(@"[IAP] doVerifyTransaction something is NULL");
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
[self.delegate onFailed:@"nill" quantity:0 orderID:@"nill"];
return;
}
NSMutableString *sendParam = [[NSMutableString alloc] init];
[sendParam appendFormat:@"plateform=%@",self.strPlateform];
[sendParam appendFormat:@"&order-id=%@",_order_id];
[sendParam appendFormat:@"&game-id=%@",_gameid];
[sendParam appendFormat:@"&production-id=%@",transaction.payment.productIdentifier];
[sendParam appendFormat:@"&transaction-id=%@",transaction.transactionIdentifier];
[sendParam appendFormat:@"&receipt-data=%@",pszBase64];
NSData* data = [sendParam dataUsingEncoding:NSUTF8StringEncoding];
NSLog(@"[IAP] pruchase backurl = %@",_backurl);
NSLog(@"[IAP] pruchase param = %@",sendParam);
NSInteger amount = transaction.payment.quantity;
[self checkReceipt:_backurl withData:data onCompletion:^(NSString* response,NSError* error){
if (error == nil){
NSLog(@"[IAP] web result = %@",response);
NSData* pJsonData = [response dataUsingEncoding:NSUTF8StringEncoding];
NSError* pError;
NSDictionary* pJson = [NSJSONSerialization JSONObjectWithData:pJsonData options:kNilOptions error:&pError];
if( !pError ){
NSString* resultCode = [pJson objectForKey:@"error-code"];
int nCode = [resultCode intValue];
if (nCode == 0){
NSLog(@"[IAP] verify success!");
self.isProcessing = NO;
[self.delegate onSuccess:transaction.payment.productIdentifier quantity:amount orderID:_order_id];
}
else{
NSLog(@"[IAP] verify err code = %@ info = %@",resultCode,[pJson objectForKey:@"error-info"]);
self.isProcessing = NO;
[self.delegate onFailed:transaction.payment.productIdentifier quantity:amount orderID:_order_id];
}
}
else{
self.isProcessing = NO;
NSLog(@"[IAP] An error happened while serializing the JSON data.");
[self.delegate onFailed:transaction.payment.productIdentifier quantity:amount orderID:_order_id];
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
else{
self.isProcessing = NO;
[self.delegate onFailed:transaction.payment.productIdentifier quantity:amount orderID:_order_id];
}
}];
}
- (void)checkReceipt:(NSString*)url withData:(NSData*)receiptData onCompletion:(IAPcheckReceiptCompleteResponseBlock)completion
{
self.checkReceiptCompleteBlock = completion;
NSURL* requestURL = [NSURL URLWithString:url];
NSMutableURLRequest* req = [[NSMutableURLRequest alloc] initWithURL:requestURL];
[req setHTTPMethod:@"POST"];
[req setHTTPBody:receiptData];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
if(conn) {
self.receiptRequestData = [[NSMutableData alloc] init];
} else {
NSError* error = nil;
NSMutableDictionary* errorDetail = [[NSMutableDictionary alloc] init];
[errorDetail setValue:@"Can't create connection" forKey:NSLocalizedDescriptionKey];
error = [NSError errorWithDomain:@"IAPManagerError" code:100 userInfo:errorDetail];
if(self.checkReceiptCompleteBlock) {
self.checkReceiptCompleteBlock(nil,error);
}
}
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"[IAP] Cannot transmit receipt data. %@",[error localizedDescription]);
if(self.checkReceiptCompleteBlock) {
self.checkReceiptCompleteBlock(nil,error);
}
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[self.receiptRequestData setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.receiptRequestData appendData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *response = [[NSString alloc] initWithData:self.receiptRequestData encoding:NSUTF8StringEncoding];
if(self.checkReceiptCompleteBlock) {
self.checkReceiptCompleteBlock(response,nil);
}
}
@end