open source

This commit is contained in:
lvfulong
2020-11-11 16:17:13 +08:00
parent 4d989f3ecb
commit bc4ca748de
2441 changed files with 623057 additions and 2 deletions
@@ -0,0 +1,9 @@
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
@@ -0,0 +1,42 @@
#import "AppDelegate.h"
#import "ViewController.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ViewController* pViewController = [[ViewController alloc] init];
self.window.rootViewController = pViewController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
@end
@@ -0,0 +1,98 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8150" systemVersion="15A204g" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8122"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6211" systemVersion="14A298i" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
@@ -0,0 +1,7 @@
#import <Foundation/NSObject.h>
@interface Test: NSObject
@end
@@ -0,0 +1,21 @@
#import <Foundation/Foundation.h>
#import "Test.h"
#import <LayaWKWebview.h>
@implementation Test
+(void)test:(NSString*)json
{
NSError* error = nil;
NSData* jsonData = [json dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary* dict = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
NSLog(@"OC: %@", [dict objectForKey:@"value"]);
{
NSDictionary* dic = [NSDictionary dictionaryWithObject:@"Hello JS!" forKey:@"value"];
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:dic options:0 error:&error];
NSString* jsonStr = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[[LayaWKWebview GetLayaWKWebview] callbackToJSWithClass:self.class methodName:@"test:" ret:jsonStr];
}
}
@end
@@ -0,0 +1,8 @@
#import <UIKit/UIKit.h>
#import <WebKit/WKUIDelegate.h>
#import <WebKit/WKScriptMessageHandler.h>
#import <WebKit/WKNavigationDelegate.h>
@interface ViewController : UIViewController<WKScriptMessageHandler,WKUIDelegate,WKNavigationDelegate>
-(id)init;
@end
@@ -0,0 +1,176 @@
#import "ViewController.h"
#import "conchConfig.h"
#import "LayaWKWebview.h"
@implementation ViewController
{
LayaWKWebview* _layaWKWebview;
NSString* _scriptsPath;
BOOL _addScriptMessageHandler;
}
-(id)init
{
self = [super init];
if( self != nil )
{
_addScriptMessageHandler = NO;
return self;
}
return nil;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
[conchConfig GetInstance];
WKWebViewConfiguration* config = [[WKWebViewConfiguration alloc]init];
config.preferences.javaScriptEnabled=true;
config.preferences.javaScriptCanOpenWindowsAutomatically = true;
config.userContentController = [[WKUserContentController alloc] init];
NSString* scriptsPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/scripts/init.js"];
NSString* iniScript = [NSString stringWithContentsOfFile:scriptsPath encoding:NSUTF8StringEncoding error:nil];
WKUserScript *script = [[WKUserScript alloc] initWithSource:iniScript injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
[config.userContentController addUserScript:script];
WKWebView* webview = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
webview.allowsBackForwardNavigationGestures = YES;
webview.UIDelegate = self;
webview.navigationDelegate = self;
webview.scrollView.bounces = false;
webview.scrollView.bouncesZoom = false;
if (@available(iOS 11.0, *))
{
webview.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
[self setNeedsStatusBarAppearanceUpdate];
[self prefersStatusBarHidden];
_layaWKWebview = [[LayaWKWebview alloc] initWithWebview:webview url:[conchConfig GetInstance]->m_sUrl hostPort:[conchConfig GetInstance]->m_nHostPort];
[self.view addSubview:_layaWKWebview.webview];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
//-------------------------------------------------------------------------------
-(NSUInteger)supportedInterfaceOrientations
{
/*
UIInterfaceOrientationMaskPortrait, ===2
UIInterfaceOrientationMaskPortraitUpsideDown, ===4
UIInterfaceOrientationMaskLandscapeLeft, ===8
UIInterfaceOrientationMaskLandscapeRight, ===16
*/
return [conchConfig GetInstance]->m_nOrientationType;
}
//-------------------------------------------------------------------------------
- (BOOL)prefersStatusBarHidden
{
return YES;
}
- (BOOL)shouldAutorotate
{
return YES;//支持转屏
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (!_addScriptMessageHandler)
{
[_layaWKWebview.webview.configuration.userContentController addScriptMessageHandler:self name:@"reflection"];
[_layaWKWebview.webview.configuration.userContentController addScriptMessageHandler:self name:@"log"];
_addScriptMessageHandler = YES;
}
}
- (void)viewWillDisppear:(BOOL)animated
{
[super viewWillDisappear:animated];
if (_addScriptMessageHandler)
{
[_layaWKWebview.webview.configuration.userContentController removeScriptMessageHandlerForName:@"reflection"];
[_layaWKWebview.webview.configuration.userContentController removeScriptMessageHandlerForName:@"log"];
_addScriptMessageHandler = NO;
}
}
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
if (![message.body isKindOfClass:NSString.class])
{
return;
}
NSString* data = message.body;
if (data == nil)
{
return;
}
//NSLog(@"JS-->OC %@",message.body);
if ([message.name isEqualToString:@"log"])
{
NSLog(@"JSLog:%@", data);
}
else if ([message.name isEqualToString:@"reflection"])
{
NSError* error = nil;
NSData* jsonData = [message.body dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary* dict = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&error];
NSNumber* ID = [dict objectForKey:@"id"];
NSString* className = [dict objectForKey:@"className"];
NSString* methodName = [dict objectForKey:@"methodName"];
NSString* param = [dict objectForKey:@"param"];
[_layaWKWebview callMethod:ID.intValue className:className methodName:methodName param:param];
}
}
-(void) callbackToJS:(NSString*)name data:(NSString*)jsonParam
{
NSString* js = [NSString stringWithFormat:@"window.wkbridge.callback('%@','%@');",name, jsonParam];
[_layaWKWebview.webview evaluateJavaScript:js completionHandler:^(id _Nullable response, NSError * _Nullable error) {
if (response || error)
{
NSLog(@"value: %@ error: %@", response, error);
}
}];
}
/*- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
NSDictionary* pDictionary =
[NSDictionary dictionaryWithObjectsAndKeys:
[conchConfig GetInstance]->m_sPlatformClassName,@"market_name",
[NSNumber numberWithInt:[conchConfig GetInstance]->m_nChargeType],@"charge_type",
[NSNumber numberWithInt:[conchConfig GetInstance]->m_nPayType],@"pay_type",
[NSNumber numberWithInt:[conchConfig GetInstance]->m_nEnterPlatformType],@"enter_platform_type",
[NSNumber numberWithInt:[conchConfig GetInstance]->m_nLoginType],@"login_type",nil];
NSError* pError = nil;
NSString* pJsonString = nil;
NSData* pJsonData = [NSJSONSerialization dataWithJSONObject:pDictionary options:0 error:&pError];
if( !pError )
{
pJsonString = [[NSString alloc] initWithData:pJsonData encoding:NSUTF8StringEncoding];
}
NSString* js = [NSString stringWithFormat:@"if(!window.conchMarketData){window.conchMarketData=JSON.parse('%@')}",pJsonString];
[_layaWKWebview.webview evaluateJavaScript:js completionHandler:^(id _Nullable response, NSError * _Nullable error) {
if (response || error)
{
NSLog(@"value: %@ error: %@;", response, error);
}
}];
decisionHandler(WKNavigationActionPolicyAllow);
}*/
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
// 确定按钮
UIAlertAction *alertAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler();
}];
// alert弹出框
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message message:nil preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:alertAction];
[self presentViewController:alertController animated:YES completion:nil];
}
@end
@@ -0,0 +1,16 @@
#import <Foundation/Foundation.h>
#import <StoreKit/StoreKit.h>
@protocol JCIapProcessCtrlDelegate <NSObject>
@required
- (void)onSuccess:(NSString *)p_pProductionIdentifier quantity:(NSInteger)p_iNumber orderID:(NSString *)p_pszOrderID;
- (void)onFailed:(NSString *)p_pProductionIdentifier quantity:(NSInteger)p_iNumber orderID:(NSString *)p_pszOrderID;
@end
@interface IAPManager : NSObject<SKProductsRequestDelegate,SKPaymentTransactionObserver>
+ (IAPManager*) getInstance;
-(void)recharge:(NSString*) jsonParam;
- (id)initWithGameID:(NSString*)gameID andDelegate:(id<JCIapProcessCtrlDelegate>)delegate;
@end
@@ -0,0 +1,339 @@
#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
@@ -0,0 +1,16 @@
//
// main.m
// WKWebview
//
// Created by LayaBox on 1/11/16.
// Copyright © 2016 LayaBox. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}