登录文件
SignInWithAppleView.h
#import <AuthenticationServices/AuthenticationServices.h>
NS_ASSUME_NONNULL_BEGIN
@interface SignInWithAppleView : UIViewController <ASAuthorizationControllerDelegate,ASAuthorizationControllerPresentationContextProviding>
{
}
+(SignInWithAppleView *) getInstance; //用来获取实例的方法
-(void)showAppleButton;
-(void)hideAppleButton;
-(void)signInWithApple;
@end
NS_ASSUME_NONNULL_END
SignInWithAppleView.mm
#import "SignInWithAppleView.h"
#import "YCSDKModule.h"
static SignInWithAppleView *instance; //这里声明一下静态实例,方便javascript层调用
@implementation SignInWithAppleView
//获取实例的方法,方便javascript层调用
+(SignInWithAppleView *) getInstance{
return instance;
}
- (void)viewDidLoad {
instance = self;
if (@available(iOS 13.0, *)) {
ASAuthorizationAppleIDButton *appleBtn = [[ASAuthorizationAppleIDButton alloc] initWithAuthorizationButtonType:ASAuthorizationAppleIDButtonTypeSignIn authorizationButtonStyle:ASAuthorizationAppleIDButtonStyleWhiteOutline];
appleBtn.frame = CGRectMake(0, 0, 132, 44);
appleBtn.center = CGPointMake(self.view.center.x, self.view.center.y+250);
appleBtn.cornerRadius = 15;
[appleBtn addTarget:self action:@selector(signInWithApple) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:appleBtn];
}
[self.view setHidden:YES];
}
-(void)showAppleButton API_AVAILABLE(ios(13.0)){
[self.view setHidden:NO];
}
-(void)hideAppleButton API_AVAILABLE(ios(13.0)){
[self.view setHidden:YES];
}
-(void)signInWithApple API_AVAILABLE(ios(13.0)){
if (@available(iOS 13.0, *)) {
ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
ASAuthorizationAppleIDRequest *request = appleIDProvider.createRequest;
request.requestedScopes = @[ASAuthorizationScopeFullName, ASAuthorizationScopeEmail];
ASAuthorizationController *vc = [[ASAuthorizationController alloc] initWithAuthorizationRequests:@[request]];
vc.delegate = self;
vc.presentationContextProvider = self;
[vc performRequests];
}
}
// ASAuthorizationControllerDelegate 授权回调
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization API_AVAILABLE(ios(13.0))
{
if ([authorization.credential isKindOfClass:[ASAuthorizationAppleIDCredential class]]) {
ASAuthorizationAppleIDCredential *credential = authorization.credential;
NSString *state = credential.state;
NSString *userID = credential.user;
NSPersonNameComponents *fullName = credential.fullName;
NSString *nickname = @"";
if (fullName.nickname != nullptr) {
nickname = fullName.nickname;
}
NSString *email = credential.email;
NSString *authorizationCode = [[NSString alloc] initWithData:credential.authorizationCode encoding:NSUTF8StringEncoding]; // refresh token
NSString *identityToken = [[NSString alloc] initWithData:credential.identityToken encoding:NSUTF8StringEncoding]; // access token
ASUserDetectionStatus realUserStatus = credential.realUserStatus;
NSLog(@"state: %@", state);
NSLog(@"userID: %@", userID);
NSLog(@"fullName: %@", fullName);
NSLog(@"email: %@", email);
NSLog(@"authorizationCode: %@", authorizationCode);
NSLog(@"identityToken: %@", identityToken);
NSLog(@"realUserStatus: %@", @(realUserStatus));
YCSDKModule::onAppleLoginSuccess(userID,nickname,identityToken);
}
}
- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error API_AVAILABLE(ios(13.0))
{
NSString *errorMsg = nil;
switch (error.code) {
case ASAuthorizationErrorCanceled:
errorMsg = @"用户取消了授权请求";
break;
case ASAuthorizationErrorFailed:
errorMsg = @"授权请求失败";
break;
case ASAuthorizationErrorInvalidResponse:
errorMsg = @"授权请求响应无效";
break;
case ASAuthorizationErrorNotHandled:
errorMsg = @"未能处理授权请求";
break;
case ASAuthorizationErrorUnknown:
errorMsg = @"授权请求失败未知原因";
break;
}
NSLog(@"%@", errorMsg);
}
@end
充值文件
RechargeVC.h
#import <StoreKit/StoreKit.h> //注意这个头文件要加入,是内购必须
//#import <conchRuntime.h> //想要oc调用ts的方法,就要加入这个.h
@interface RechargeVC : UIViewController <SKPaymentTransactionObserver,SKProductsRequestDelegate >
{
int buyTypeInt;//定义一个整型变量,.m文件用
}
- (void)viewDidLoad;
- (void) requestProUpgradeProductData;
- (void)RequestProductData:(NSString*)pId;
- (void)doPay:(NSString*)pId;
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions;
- (void) PurchasedTransaction: (SKPaymentTransaction *)transaction;
- (void) completeTransaction: (SKPaymentTransaction *)transaction;
- (void) failedTransaction: (SKPaymentTransaction *)transaction;
- (void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction;
- (void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error;
- (void) restoreTransaction: (SKPaymentTransaction *)transaction;
- (void)provideContent:(NSString *)product;
- (void)recordTransaction:(NSString *)product;
@end
RechargeVC.mm
#import "RechargeVC.h"
#import "YCSDKModule.h"
@interface RechargeVC ()
@end
@implementation RechargeVC
- (void)viewDidLoad //百度这个oc函数的作用,这里可以理解为整个类的初始化。
{
NSLog(@"---------RechargeVC.viewDidLoad------------");
//内购支付监听,不可或缺,没有这个ios不会给你回调↓↓↓↓
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
-(void) LogBox:(NSString*) msgStr
{
UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:@"提示" message:msgStr
delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];
[alerView show];
}
- (void)doPay:(NSString*)pId
{ //ts调用oc的接口,在游戏ts逻辑代码里需要调用这个oc的函数,怎样调用则在下篇讲解
buyTypeInt = [pId intValue];//要转为int类型,因为之后的函数使用的是这个id的整数值而不是字符串
buyTypeStr = pId ; //记录下来这个id字符串
NSLog(@"---------请求doPay的产品信息------------%@",pId);
if ([SKPaymentQueue canMakePayments]) {
[self RequestProductData:pId];
} else {
[self LogBox:@"不允许程序内付费购买"];
}
}
//请求产品信息
- (void)RequestProductData:(NSString*)pId
//苹果内购IPA函数,向苹果请求你的产品信息,这个函数你只需要根据实际去改switch和case的内容。
{
NSLog(@"---------请求对应的产品信息------------%@",pId);
//[self LogBox:@"---------请求对应的产品信息------------"];
NSArray *product = [[NSArray alloc] initWithObjects:pId,nil];
NSSet *nsset = [NSSet setWithArray:product];
SKProductsRequest *request=[[SKProductsRequest alloc] initWithProductIdentifiers: nsset];
request.delegate=self;//代理 (这一步很重要,可以百度查SKProductsRequest 相关知识).
[request start];
}
//收到的产品信息
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
//苹果内购IPA函数,苹果返回你的产品信息,这个函数你也只需要根据实际去改switch和case的内容。
NSArray *myProduct = response.products;
NSLog(@"产品Product ID:%@",response.invalidProductIdentifiers);
NSLog(@"产品付费数量: %d", (int)[myProduct count]);
// populate UI
for(SKProduct *product in myProduct){
NSLog(@"product info");
NSLog(@"SKProduct 描述信息%@", [product description]);
NSLog(@"产品标题 %@" , product.localizedTitle);
NSLog(@"产品描述信息: %@" , product.localizedDescription);
NSLog(@"价格: %@" , product.price);
NSLog(@"Product id: %@" , product.productIdentifier);
SKPayment *payment = [SKPayment paymentWithProductIdentifier:product.productIdentifier];
[[SKPaymentQueue defaultQueue] addPayment:payment];
break;
}
}
- (void)requestProUpgradeProductData
{
//苹果的内购IPA函数,这是请求升级的函数
NSLog(@"------请求升级数据---------");
NSSet *productIdentifiers = [NSSet setWithObject:@"com.productid"];
SKProductsRequest* productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
productsRequest.delegate = self;
[productsRequest start];
}
//弹出错误信息
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
//[self LogBox:@"-----------弹出错误信息--------------"];//苹果的内购IPA函数,请求商品信息有错误就会调用
UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Alert",NULL) message:[error localizedDescription]
delegate:nil cancelButtonTitle:NSLocalizedString(@"Close",nil) otherButtonTitles:nil];
[alerView show];
}
- (void) requestDidFinish:(SKRequest *)request
{
NSLog(@"----------反馈信息结束--------------");
}
- (void) PurchasedTransaction: (SKPaymentTransaction *)transaction
{
NSLog(@"-----PurchasedTransaction----");
NSArray *transactions =[[NSArray alloc] initWithObjects:transaction, nil];
[self paymentQueue:[SKPaymentQueue defaultQueue] updatedTransactions:transactions];
}
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions//交易结果
{
//苹果的内购IPA函数、这是支付操作的返回。支付结果成功与失败都在这里做处理
NSLog(@"-----paymentQueue--------");
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased:
{
NSData *receipt = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]]; // Sent to the server by the device
NSString* encodeString = [receipt base64EncodedStringWithOptions:0];
NSLog(@"encodeString:%@",encodeString);
//交易完成
[self completeTransaction:transaction];
NSLog(@"-----交易完成 --------");
NSLog(@"productIdentifier:%@",transaction.payment.productIdentifier);
NSLog(@"transactionIdentifier:%@",transaction.transactionIdentifier);
YCSDKModule::onAppleRecharge(@"100",encodeString,transaction.transactionIdentifier);
//客户端验证
NSError *error;
NSDictionary *requestContents = @{
@"receipt-data": encodeString
};
NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents
options:0
error:&error];
if (!requestData) { // 交易凭证为空验证失败
NSLog(@"-----交易凭证为空验证失败 --------");
return;
}
NSLog(@"requestData:%@",requestData);
// NSString *serverString = @"https://sandbox.itunes.apple.com/verifyReceipt";
// NSURL *storeURL = [NSURL URLWithString:serverString];
// NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
// [storeRequest setHTTPMethod:@"POST"];
// [storeRequest setHTTPBody:requestData];
// [storeRequest setTimeoutInterval:30];
// NSURLSession *session = [NSURLSession sharedSession];
// NSURLSessionDataTask * dataTask = [session dataTaskWithRequest:storeRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// //服务器返回的responseObject是gbk编码的字符串,通过gbk编码转码就行了,转码方法如下:
// NSString*gbkStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
// //转码之后再转utf8解析
// NSDictionary * jsonDict = [NSJSONSerialization JSONObjectWithData:[gbkStr dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
// if (jsonDict.allKeys.count > 0) {
// if ([[jsonDict objectForKey:@"code"]intValue] == 0) {
// NSLog(@"-----服务器验签成功 --------");
// NSDictionary * dataDict = jsonDict[@"data"];
// }else if ([[jsonDict objectForKey:@"code"]intValue] == 1){
// NSLog(@"-----服务器验签失败 --------");
// }
// }
// }];
//
// [dataTask resume];
}
break;
case SKPaymentTransactionStateFailed://交易失败
{
[self failedTransaction:transaction];
NSLog(@"-----交易失败 --------");
UIAlertView *alerView2 = [[UIAlertView alloc] initWithTitle:@"提示"
message:@"购买失败,请重新尝试购买" delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];
[alerView2 show];
// YCSDKModule::onAppleRecharge(@"102",nil,nil);
// [self callbackToJs:false];//注意看这个函数,oc如何调用js代码的技巧
}
break;
case SKPaymentTransactionStateRestored://已经购买过该商品
{
[self restoreTransaction:transaction];
NSLog(@"-----已经购买过该商品 --------");
// [self callbackToJs:false];
}
break;
case SKPaymentTransactionStatePurchasing: //商品添加进列表
NSLog(@"-----商品添加进列表 --------");
break;
default:
break;
}
}
}
- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
//苹果的内购IPA函数,交易完成会进来这里,这个不用改
NSLog(@"-----completeTransaction--------");
//[self LogBox:@"-----------completeTransaction--------------"];
// Your application should implement these two methods.
NSString *product = transaction.payment.productIdentifier;
if ([product length] > 0) {
NSLog(@"product = %@",product);
NSArray *tt = [product componentsSeparatedByString:@"."];
NSString *bookid = [tt lastObject];
if ([bookid length] > 0) {
[self recordTransaction:bookid];
[self provideContent:bookid];
}
}
// Remove the transaction from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
//↓↓↓↓下面的函数都是苹果的内购IPA函数,只需理解就好,不用添加我们自己的代码了↓↓↓↓
//记录交易
- (void)recordTransaction:(NSString *)product
{
NSLog(@"-----记录交易--------%@",product);
}
//处理下载内容
- (void)provideContent:(NSString *)product
{
NSLog(@"-----下载--------%@",product);
}
- (void) failedTransaction: (SKPaymentTransaction *)transaction{
NSLog(@"失败");
//[self LogBox:@"-----------失败--------------"];
if (transaction.error.code != SKErrorPaymentCancelled)
{
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction
{
}
- (void) restoreTransaction: (SKPaymentTransaction *)transaction
{
NSLog(@" 交易恢复处理");
}
- (void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error{
NSLog(@"-------paymentQueue----");
//[self LogBox:@"-----------paymentQueue--------------"];
}
#pragma mark connection delegate
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
switch([(NSHTTPURLResponse *)response statusCode])
{
case 200:
case 206:
break;
case 304:
break;
case 400:
break;
case 404:
break;
case 416:
break;
case 403:
break;
case 401:
case 500:
break;
default:
break;
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"test");
}
- (void)dealloc
{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];//解除监听
}
@end
lua调用OC文件
YCSDKModule.h
#ifndef YCSDKModule_h
#define YCSDKModule_h
#include "CoronaLua.h"
class YCSDKModule
{
public:
static const char * Name();
static int Open( lua_State *L);
static int Finalizer( lua_State *L);
static NSString * convertToJsonData(NSDictionary * dict);
static NSDictionary * dictionaryWithJsonString(NSString * jsonString);
static void onAppleLoginSuccess(NSString * userID,NSString * nickName,NSString * identityToken);
static void onAppleRecharge(NSString * code,NSString * transactionReceipt,NSString * transactionIdentifier);
};
//CORONA_EXPORT int luaopen_plugin_library( lua_State *L );
#endif /* YCSDKModule_h */
YCSDKModule.mm
#import <Foundation/Foundation.h>
#import "YCSDKModule.h"
#import "CoronaRuntime.h"
#import "SignInWithAppleView.h"
#import "RechargeVC.h"
//--------functions----------
//SDK登录(must call)
static int doSDKLogin(lua_State *L )
{
return 0;
}
const char* YCSDKModule::Name()
{
static const char sName[] = "YCSDKModule";
return sName;
}
static SignInWithAppleView * _signInWithAppleView;
static int showAppleButton(lua_State *L )
{
if (_signInWithAppleView) {
[_signInWithAppleView showAppleButton];
}
return 0;
}
static int hideAppleButton(lua_State *L )
{
if (_signInWithAppleView) {
[_signInWithAppleView hideAppleButton];
}
return 0;
}
static int signInWithApple(lua_State *L )
{
if (_signInWithAppleView) {
[_signInWithAppleView signInWithApple];
}
return 0;
}
static RechargeVC * _rechargeVC;
static int pay(lua_State *L )
{
const char *jsonstring = lua_tostring(L, 1);
NSString * _jsonstring = [NSString stringWithUTF8String:jsonstring];
// NSData *jsonData = [_jsonstring dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary * dic = YCSDKModule::dictionaryWithJsonString(_jsonstring);
if (_rechargeVC) {
[_rechargeVC doPay : [dic valueForKey:@"productId"]];
}
return 0;
}
static lua_State * mL = NULL;
int YCSDKModule::Open(lua_State * L)
{
id<CoronaRuntime> runtime = (id<CoronaRuntime>)CoronaLuaGetContext( L );
_signInWithAppleView = [[SignInWithAppleView alloc] init];
[runtime.appViewController.view addSubview:_signInWithAppleView.view];
_rechargeVC = [[RechargeVC alloc] init];
[runtime.appViewController.view addSubview:_rechargeVC.view];
mL = L;
NSLog(@"----YCSDKModule::Open-----");
const luaL_Reg kVTable[] =
{
// {"showAppleButton",showAppleButton},
// {"hideAppleButton",hideAppleButton},
{"signInWithApple",signInWithApple},
{"pay",pay},
{NULL, NULL}
};
luaL_openlib(L, Name(), kVTable, 1);//leave "YCSDK" on top of stack
return 1;
}
NSDictionary * YCSDKModule::dictionaryWithJsonString(NSString * jsonString)
{
if (jsonString == nil) {
return nil;
}
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *parseError = nil;
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingMutableContainers
error:&parseError];
if(parseError)
{
NSLog(@"json解析失败:%@",parseError);
return nil;
}
return dic;
}
NSString * YCSDKModule::convertToJsonData(NSDictionary * dict) {
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict
options:NSJSONWritingSortedKeys
error:&error];
NSString *jsonString= [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
return jsonString;
}
void YCSDKModule::onAppleLoginSuccess(NSString * userID,NSString * nickName,NSString * identityToken)
{
lua_State *L = mL;
const char kvalueKey[] = "appstoreDelegate";
const char kNameKey[] = "name";
const char kNameKey2[] = "message";
NSDictionary *dict2 = @{@"userID" : userID, @"nickName" : nickName, @"identityToken" : identityToken};
NSDictionary *dict = @{@"code" : @"100", @"eventName" : @"login", @"eventData" : dict2};
NSString *jsonString = YCSDKModule::convertToJsonData(dict);
char* str = (char*) [jsonString UTF8String];
NSLog(@"str: %@",jsonString);
lua_newtable( L );
lua_pushstring(L, kvalueKey );
lua_setfield( L, -2, kNameKey );
lua_pushstring(L, str );
lua_setfield( L, -2, kNameKey2 );
CoronaLuaDispatchRuntimeEvent( L, -1 );
}
void YCSDKModule::onAppleRecharge(NSString * code,NSString * transactionReceipt,NSString * transactionIdentifier)
{
lua_State *L = mL;
const char kvalueKey[] = "appstoreDelegate";
const char kNameKey[] = "name";
const char kNameKey2[] = "message";
NSDictionary *dict = @{@"code" : code, @"eventName" : @"pay",@"transactionReceipt" : transactionReceipt,@"transactionIdentifier" : transactionIdentifier};
NSString *jsonString = YCSDKModule::convertToJsonData(dict);
char* str = (char*) [jsonString UTF8String];
// NSLog(@"str: %@",jsonString);
lua_newtable( L );
lua_pushstring(L, kvalueKey );
lua_setfield( L, -2, kNameKey );
lua_pushstring(L, str );
lua_setfield( L, -2, kNameKey2 );
CoronaLuaDispatchRuntimeEvent( L, -1 );
}