网上可以找到Cocos2d-X或者Cocos2d-Js接IOS支付的参考,但是没有Lua的,所以就暂且提供一个我的版本。
没有折腾Lua和C++之间的交互,暂且用着Cocos2d框架提供的LuaObjcBridge,非常简单。一些类名取自IAP Js版本作者。
第一个文件:IAPDelegates.h
#import <Foundation/Foundation.h>
#import <StoreKit/StoreKit.h>
@class AppController;
@interface iAPProductsRequestDelegate : NSObject<SKProductsRequestDelegate>
@property (nonatomic,assign) AppController *iosiap;
@end
@interface iAPTransactionObserver : NSObject<SKPaymentTransactionObserver>
@property (nonatomic,assign) AppController *iosiap;
@end
第二个文件:IAPDelegates.m
#import <Foundation/Foundation.h>
#import "IAPDelegates.h"
#import "AppController.h"
@implementation iAPProductsRequestDelegate
- (void)productsRequest:(SKProductsRequest *)request
didReceiveResponse:(SKProductsResponse *)response
{
if (_iosiap.skProducts) {
[(NSArray *)(_iosiap.skProducts) release];
}
_iosiap.skProducts = [response.products retain];
}
- (void)requestDidFinish:(SKRequest *)request
{
[request.delegate release];
[request release];
}
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
NSLog(@"%@",error);
}
@end
@implementation iAPTransactionObserver
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions) {
if(transaction.transactionState == SKPaymentTransactionStatePurchased){
[_iosiap onPaymentEvent:transaction.payment.productIdentifier andQuantity:transaction.payment.quantity];
}
if (transaction.transactionState != SKPaymentTransactionStatePurchasing) {
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
}
}
- (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions
{
}
@end
主文件,也就是Cocos2d提供的AppController.mm:
#import <UIKit/UIKit.h>
#import "cocos2d.h"
#import "platform/ios/CCLuaObjcBridge.h"
#import "AppController.h"
#import "AppDelegate.h"
#import "RootViewController.h"
#import "platform/ios/CCEAGLView-ios.h"
#import "IAPDelegates.h"
@implementation AppController
{
iAPTransactionObserver* skTransactionObserver;
int nLuaFunctionMemoryWarningCallback;
int nLuaFunctionPaySuccessCallback;
NSMutableDictionary* dictOfPayInfo;
BOOL bTriggerAd;
}
#pragma mark -
#pragma mark Application lifecycle
// cocos2d application instance
static AppDelegate s_sharedApplication;
static AppController* s_sharedAppController;
+ (void)InitIAp:(NSDictionary *) dict{
[s_sharedAppController applicationInitiAP:dict];
}
+ (void)Charge:(NSDictionary *) dict{
[s_sharedAppController applicationPayRequest:dict];
}
+ (void)ListenMemoryWarning:(NSDictionary *) dict{
s_sharedAppController->nLuaFunctionMemoryWarningCallback = [[dict objectForKey:@"callback"] intValue];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
cocos2d::Application *app = cocos2d::Application::getInstance();
app->initGLContextAttrs();
cocos2d::GLViewImpl::convertAttrs();
// Override point for customization after application launch.
// Add the view controller's view to the window and display.
window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
CCEAGLView *eaglView = [CCEAGLView viewWithFrame: [window bounds]
pixelFormat: (NSString*)cocos2d::GLViewImpl::_pixelFormat
depthFormat: cocos2d::GLViewImpl::_depthFormat
preserveBackbuffer: NO
sharegroup: nil
multiSampling: NO
numberOfSamples: 0 ];
[eaglView setMultipleTouchEnabled:YES];
// Use RootViewController manage CCEAGLView
viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];
viewController.wantsFullScreenLayout = YES;
viewController.view = eaglView;
// Set RootViewController to window
if ( [[UIDevice currentDevice].systemVersion floatValue] < 6.0)
{
// warning: addSubView doesn't work on iOS6
[window addSubview: viewController.view];
}
else
{
// use this method on ios6
[window setRootViewController:viewController];
}
[window makeKeyAndVisible];
[[UIApplication sharedApplication] setStatusBarHidden: YES];
// IMPORTANT: Setting the GLView should be done after creating the RootViewController
cocos2d::GLView *glview = cocos2d::GLViewImpl::createWithEAGLView(eaglView);
cocos2d::Director::getInstance()->setOpenGLView(glview);
s_sharedAppController = self;
app->run();
return YES;
}
//初始化IAP
- (void)applicationInitiAP:(NSDictionary *) dict{
// Initialize iAp Observer
skTransactionObserver = [[iAPTransactionObserver alloc] init];
((iAPTransactionObserver *)skTransactionObserver).iosiap = self;
[[SKPaymentQueue defaultQueue] addTransactionObserver:(iAPTransactionObserver *)skTransactionObserver];
int productId = 1;
NSMutableSet *set = [NSMutableSet setWithCapacity:4];//MagicNumber,but doesn't matter.
NSString *productName = nil;
while ((productName = [dict objectForKey:[NSString stringWithFormat:@"productid_%d",productId]]) != nil) {
productId++;
[set addObject:productName];
}
SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
iAPProductsRequestDelegate *delegate = [[iAPProductsRequestDelegate alloc] init];
delegate.iosiap = self;
productsRequest.delegate = delegate;
[productsRequest start];
}
//调用IAP支付, dict中含有{"productId":"xxx","quantity":1,"callback":xx}
- (void)applicationPayRequest:(NSDictionary *) dict{
NSString *productId = [dict objectForKey:@"productId"];
for(int i = 0; i < [self.skProducts count]; i++){
SKProduct *skProduct = [self.skProducts objectAtIndex:i];
if([skProduct.productIdentifier isEqualToString:productId]){
SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:skProduct];
payment.quantity = [[dict objectForKey:@"quantity"] intValue];
[[SKPaymentQueue defaultQueue] addPayment:payment];
self->nLuaFunctionPaySuccessCallback = [[dict objectForKey:@"callback"] intValue];
break;
}
}
}
- (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. */
cocos2d::Director::getInstance()->pause();
}
- (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. */
cocos2d::Director::getInstance()->resume();
}
- (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,called instead of applicationWillTerminate: when the user quits. */
cocos2d::Application::getInstance()->applicationDidEnterBackground();
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
/* Called as part of transition from the background to the inactive state: here you can undo many of the changes made on entering the background. */
cocos2d::Application::getInstance()->applicationWillEnterForeground();
}
- (void)applicationWillTerminate:(UIApplication *)application {
/* Called when the application is about to terminate. See also applicationDidEnterBackground:. */
}
//支付成功的回调
- (void) onPaymentEvent:(NSString *)productId andQuantity:(NSInteger)count{
cocos2d::LuaObjcBridge::pushLuaFunctionById(self->nLuaFunctionPaySuccessCallback);
cocos2d::LuaObjcBridge::getStack()->pushLuaValue(cocos2d::LuaValue::stringValue([productId UTF8String]));
cocos2d::LuaObjcBridge::getStack()->executeFunction(1);
cocos2d::LuaObjcBridge::releaseLuaFunctionById(self->nLuaFunctionPaySuccessCallback);
}
#pragma mark -
#pragma mark Memory management
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
/* Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later. */
cocos2d::Director::getInstance()->purgeCachedData();
cocos2d::LuaObjcBridge::pushLuaFunctionById(self->nLuaFunctionMemoryWarningCallback);
cocos2d::LuaObjcBridge::getStack()->executeFunction(0);
//cocos2d::LuaObjcBridge::releaseLuaFunctionById(self->nLuaFunctionMemoryWarningCallback);
}
- (void)dealloc {
[super dealloc];
}
@end
function IsIOS() --Lua的区分了iPad和iPhone,估计是历史包袱。
return (cc.Application:getInstance():getTargetPlatform() == cc.PLATFORM_OS_IPHONE) or (cc.Application:getInstance():getTargetPlatform() == cc.PLATFORM_OS_IPAD)
end
--下面的是函数里的片段
if IsIOS() then
local ok,ret = LuaObjcBridge.callStaticMethod("AppController","Charge",{
["productId"]=InfoAboutSDKPay[id],["quantity"]=1,["callback"]=PaySuccess
})
if(not ok) then
print("AppController.Charge() err",ret)
end
end