Unity IOS内购

参考:http://blog.sina.com.cn/s/blog_4a2183a60101lc8a.html
http://blog.csdn.net/shenjie12345678/article/details/40978977
http://blog.csdn.net/xiaominghimi/article/details/6937097
http://blog.csdn.net/shenjie12345678/article/details/41120637


Unity的assets下新建Plugins/IOS 添加TestAlertView.h TestAlertView.m IAPInterface.h IAPInterface.m IAPManager.h IAPManager.m文件

购买确认弹出框:

#import <UIKit/UIKit.h>

static NSString *productId = nil;

@interface TestAlertView : UIViewController<UIAlertViewDelegate>

-(void)setProductId:(NSString *)proId;
-(NSString*)getProductId;
@end

//
//  TestAlertView.m
//  Unity-iPhone
//
//  Created by macmini3 on 16/1/27.
//
//




#import "TestAlertView.h"
//#import "TestSingleton.h"
#import "IAPInterface.h"

@interface TestAlertView ()

@end

@implementation TestAlertView

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(void)setProductId:(NSString *)id
{
    productId = id;
    NSLog(@">>>>>>>>>>ID %@",productId);
}

-(NSString *)getProductId
{
    return productId;
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/
//判断点击的是哪一个按钮事件
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{

    switch (buttonIndex) {
        case 1:
            NSLog(@">>确认购买");
            IAPInterface *test = [IAPInterface alloc];
            [test Confirm];
            [test release];
            break;
        case 0:
             NSLog(@">>取消");
             IAPInterface *test1 = [IAPInterface alloc];
            [test1 Cancel];
            [test1 release];
            break;
        default:
            break;
    }
}

@end

购买接口:

//
//  UJSInterface.h
//  Unity-iPhone
//
//  Created by MacMini on 14-5-15.
//
//

#import <Foundation/Foundation.h>

@interface IAPInterface : NSObject
{
    IAPInterface *mySelf;
}
-(void)Confirm;
-(void)Cancel;
@end

//
//  UJSInterface.m
//  Unity-iPhone
//
//  Created by MacMini on 14-5-15.
//
//

#import "IAPInterface.h"
#import "IAPManager.h"
#import "TestAlertView.h"
//#import "TestSingleton.h"

@implementation IAPInterface

void TestMsg(){
    NSLog(@"Msg received");

}

void TestSendString(void *p){
    NSString *list = [NSString stringWithUTF8String:p];
    NSArray *listItems = [list componentsSeparatedByString:@"\t"];

    for (int i =0; i<listItems.count; i++) {
        NSLog(@"msg %d : %@",i,listItems[i]);
    }

}

void TestGetString(){
    NSArray *test = [NSArray arrayWithObjects:@"t1",@"t2",@"t3", nil];
    NSString *join = [test componentsJoinedByString:@"\n"];


    UnitySendMessage("Main", "IOSToU", [join UTF8String]);
}

IAPManager *iapManager = nil;

void InitIAPManager(){
    iapManager = [[IAPManager alloc] init];
    [iapManager attachObserver];

}

bool IsProductAvailable(){
    return [iapManager CanMakePayment];
}

void RequstProductInfo(void *p){
    UnitySendMessage("Main", "PopBuyingMask", "");
       NSString *list = [NSString stringWithUTF8String:p];
       NSLog(@"productKey:%@",list);
       [iapManager requestProductData:list];

}

-(void)Confirm
{
    TestAlertView *productId = [TestAlertView alloc];

     NSLog(@"============购买 %@",[productId getProductId]);
//    NSString *name = [NSString stringWithFormat:@"com.test.TestIAP_20"];
    NSString *name = [NSString alloc];
    name = [productId getProductId];
    [productId release];
    [iapManager buyRequest:name];
}

-(void)Cancel
{
    //通知Unity用户取消了购买支付
    NSLog(@"============取消");
    UnitySendMessage("Main", "PayFailure", "");
}

//调用IOS的弹出框不需要从Unity发送购买产品消息
void BuyProduct(void *p){
    [iapManager buyRequest:[NSString stringWithUTF8String:p]];
}

@end

购买管理:

//
//  IAPManager.h
//  Unity-iPhone
//
//  Created by MacMini on 14-5-16.
//
//

#import <Foundation/Foundation.h>
#import <StoreKit/StoreKit.h>

@interface IAPManager : NSObject<SKProductsRequestDelegate, SKPaymentTransactionObserver>{
    SKProduct *proUpgradeProduct;
    SKProductsRequest *productsRequest;
}

-(void)attachObserver;
-(BOOL)CanMakePayment;
-(void)requestProductData:(NSString *)productIdentifiers;
-(void)buyRequest:(NSString *)productIdentifier;

@end


//
//  IAPManager.m
//  Unity-iPhone
//
//  Created by MacMini on 14-5-16.
//
//

#import "IAPManager.h"
#import "TestAlertView.h"

@implementation IAPManager

-(void) attachObserver{
    NSLog(@"AttachObserver");
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}

-(BOOL) CanMakePayment{
    return [SKPaymentQueue canMakePayments];
}

-(void) requestProductData:(NSString *)productIdentifiers{

    NSArray *idArray = [productIdentifiers componentsSeparatedByString:@"\t"];
    NSSet *idSet = [NSSet setWithArray:idArray];
    [self sendRequest:idSet];
}

-(void)sendRequest:(NSSet *)idSet{
    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:idSet];
    request.delegate = self;
    [request start];
}
TestAlertView *mySelf = nil;
NSArray *products;
-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
    products = response.products;
    [products retain];
     for (SKProduct *p in products) {
         //在此由Store kit返回当前要购买的产品的详细信息,通过TestAlertView警告框弹出来,显示确认或者取消
         //1、当点击确认的时候,在TestAlertView中调用IAPInterface中的confirm方法,然后调用buyProduct方法。
         //2、当点击取消时,在TestAlertView中调用IAPInterface中的cancel方法,不做任何处理。
         mySelf = [TestAlertView alloc];
         UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[p localizedTitle]
                                                         message:[p localizedDescription]
                                                        delegate:mySelf
                                               cancelButtonTitle:@"取消"
                                               otherButtonTitles:@"确定", nil];
         [alert show];
         [alert release];
         [mySelf setProductId:[p productIdentifier]];
     }


    for(NSString *invalidProductId in response.invalidProductIdentifiers){
        NSLog(@"Invalid product id:%@",invalidProductId);
    }

    [request autorelease];
}

-(void)buyRequest:(NSString *)productIdentifier{
    NSLog(@"发送购买产品请求!");
     for (SKProduct *p in products) {
         SKPayment *payment = [SKPayment paymentWithProduct:p];
         [[SKPaymentQueue defaultQueue] addPayment:payment];
     }
    [products release];
}



-(NSString *)productInfo:(SKProduct *)product{
    NSArray *info = [NSArray arrayWithObjects:product.localizedTitle,product.localizedDescription,product.price,product.productIdentifier, nil];

    return [info componentsJoinedByString:@"\t"];
}

-(NSString *)transactionInfo:(SKPaymentTransaction *)transaction{

    return [self encode:(uint8_t *)transaction.transactionReceipt.bytes length:transaction.transactionReceipt.length];
}

-(NSString *)encode:(const uint8_t *)input length:(NSInteger) length{
    static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    NSMutableData *data = [NSMutableData dataWithLength:((length+2)/3)*4];
    uint8_t *output = (uint8_t *)data.mutableBytes;

    for(NSInteger i=0; i<length; i+=3){
        NSInteger value = 0;
        for (NSInteger j= i; j<(i+3); j++) {
            value<<=8;

            if(j<length){
                value |=(0xff & input[j]);
            }
        }

        NSInteger index = (i/3)*4;
        output[index + 0] = table[(value>>18) & 0x3f];
        output[index + 1] = table[(value>>12) & 0x3f];
        output[index + 2] = (i+1)<length ? table[(value>>6) & 0x3f] : '=';
        output[index + 3] = (i+2)<length ? table[(value>>0) & 0x3f] : '=';
    }

    return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
}

//给Unity发送成功的交易订单
-(void) provideContent:(SKPaymentTransaction *)transaction{
    UnitySendMessage("Main", "ProvideContent", [[self transactionInfo:transaction] UTF8String]);
}

-(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];
                break;
            default:
                break;
        }
    }
}

-(void) completeTransaction:(SKPaymentTransaction *)transaction{
    NSLog(@"Comblete transaction : %@",transaction.transactionIdentifier);
    [self provideContent:transaction];
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

-(void) failedTransaction:(SKPaymentTransaction *)transaction{
    NSLog(@"Failed transaction : %@",transaction.transactionIdentifier);
    //交易失败取消Unity中的购买遮罩
    UnitySendMessage("Main", "HideBuyingMask", "");
    if (transaction.error.code != SKErrorPaymentCancelled) {
        NSLog(@"!Cancelled");
    }
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

-(void) restoreTransaction:(SKPaymentTransaction *)transaction{
    NSLog(@"Restore transaction : %@",transaction.transactionIdentifier);
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}


@end

Unity脚本:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;

public class ClickBtn : MonoBehaviour {
    //遮罩动画
    public GameObject mask;

    public List<string> productInfo = new List<string>();

    [DllImport("__Internal")]
    private static extern void TestMsg();//测试信息发送

    [DllImport("__Internal")]
    private static extern void TestSendString(string s);//测试发送字符串

    [DllImport("__Internal")]
    private static extern void TestGetString();//测试接收字符串

    [DllImport("__Internal")]
    private static extern void InitIAPManager();//初始化

    [DllImport("__Internal")]
    private static extern bool IsProductAvailable();//判断是否可以购买

    [DllImport("__Internal")]
    private static extern void RequstProductInfo(string s);//获取商品信息

    [DllImport("__Internal")]
    private static extern void BuyProduct(string s);//购买商品

    //测试从xcode接收到的字符串
    void IOSToU(string s){
        Debug.Log ("[MsgFrom ios]"+s);
    }

    //获取product列表
    void ShowProductList(string s){
//      productInfo.Add (s);
//      BuyProduct("com.test.TestIAP_20");
    }


    /// <summary>
    /// 获取商品回执,将商品回执传送给服务器,服务器和App Store验证之后,向客户端推送道具或者钻石
    /// </summary>

    void ProvideContent(string s){
        Debug.Log ("[MsgFrom ios]proivideContent : "+s);
        Debug.Log (">>>>>>>>>>>>>>>>>>>>>>>>>支付成功,向服务器请求发货!!!");
        //可以在获得app Store返回交易号时,不隐藏购买遮罩,直到服务器和app Store确认之后再取消遮罩
        HideBuyingMask ();
    }

    void Start () {
        mask.SetActive (false);
        InitIAPManager();
    }

    /// <summary>
    /// 支付失败后,隐藏遮罩
    /// </summary>
    void PayFailure(){
        HideBuyingMask ();
        Debug.Log (">>>>>>>>>>>>>>>>>>>>>>>>支付失败!!!");
    }
    /// <summary>
    /// 在购买过程中显示遮罩,防止玩家再次点击购买按钮
    /// </summary>
    void PopBuyingMask(){
        mask.SetActive (true);
        Debug.Log (">>>>>>>>>>>>>>>>>>>>>>>>>弹出购买遮罩!!!!");
    }
    /// <summary>
    /// 购买成功后 或者 支付失败时隐藏购买遮罩
    /// </summary>
    void HideBuyingMask(){
        mask.SetActive (false);
        Debug.Log (">>>>>>>>>>>>>>>>隐藏购买遮罩!!!!");
    }
    /// <summary>
    /// 点击购买按钮时,通过调用Store kit框架给app Store发送购买消息
    /// </summary>
    public void OnClick(){
        Debug.Log (">>>>>>click>>>>>>");

        if (IsProductAvailable ()) {
            productInfo = new List<string> ();
            RequstProductInfo ("com.test.TestIAP_20");
        } else {
            Debug.Log (">>>>>>>>>>>>>>>>>>>>>>>>>余额不足,不能支付!!!");
        }

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值