京城游戏人-Day11: Unity 中实现 IAP 内购(内付费)

来源:互联网 发布:黑社会2 知乎 编辑:程序博客网 时间:2024/05/28 03:02

京城游戏人-Day11: Unity 中实现 IAP 内购(内付费)

-

  • 作者:大锐哥
  • 地址:http://blog.csdn.net/prevention

-

一、先说基本流程

  • 在 iTunes Connect 中创建 IAP(In-App Purchase)
  • 编写 Objective-C 的代码
  • 编写 Unity C# 的代码
  • 生成 iOS 工程,并在 Xcode 中调试

其中在 iTunes Connect 中的操作,与研发关系不大,这里省略。

二、编写 Objective-C 代码

创建两个类,分别是 IAPInterface,主要用于两种语言之间的交互调用。另一个是 IAPManager。注意这两个类的名字叫什么并不重要。

2.1 IAPInterface.h
#import <Foundation/Foundation.h>@interface IAPInterface : NSObject@end
2.2 IAPInterface.m
#import "IAPInterface.h"#import "IAPManager.h"@implementation IAPInterface...@end

其中...包括如下方法。

// Unity to iOSvoid TestMsg() {    NSLog(@"Msg recved");        }// Unity to iOSvoid TestSendString(void *p) {    NSString *list = [NSString stringWithUTF8String:p];    NSArray *listItems = [list componentsSeparateByString:@"\t"];    for (int i = 0; i < listItems.count; ++i) {        NSLog(@"msg %d: %@", i, listItems[i]);    }}// iOS to Unityvoid 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){    NSString *list = [NSString stringWithUTF8String:p];    NSLog(@"productKey:%@",list);    [iapManager requestProductData:list];}// 购买商品void BuyProduct(void *p){    [iapManager buyRequest:[NSString stringWithUTF8String:p]];}
2.3 IAPManager.h
#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
2.4 IAPManager.m
#import "IAPManager.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];}-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{    NSArray *products = response.products;    for (SKProduct *p in products) {        UnitySendMessage("Main", "ShowProductList", [[self productInfo:p] UTF8String]);    }    for(NSString *invalidProductId in response.invalidProductIdentifiers){        NSLog(@"Invalid product id:%@",invalidProductId);    }    [request autorelease];}-(void)buyRequest:(NSString *)productIdentifier{    SKPayment *payment = [SKPayment paymentWithProductIdentifier:productIdentifier];    [[SKPaymentQueue defaultQueue] addPayment:payment];}-(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];    //return [[NSString alloc] initWithData:transaction.transactionReceipt encoding:NSASCIIStringEncoding];}-(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];}-(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);    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 的 C# 代码

先在 Unity 中创建一个名为MainEmpty Object。并创建如下脚本,添加为Main的组件。该脚本名称随意。

using UnityEngine;using System.Collections;using System.Collections.Generic;using System.Runtime.InteropServices;public class IAPExample : MonoBehaviour {    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);    }    //获取商品回执    void ProvideContent(string s){        Debug.Log ("[MsgFrom ios]proivideContent : "+s);    }    // Use this for initialization    void Start () {        InitIAPManager();    }    // Update is called once per frame    void Update () {    }    void OnGUI(){        /*if(GUILayout.Button("Test 1",GUILayout.Width(200), GUILayout.Height(100)))            TestMsg();        GUILayout.Space (200);        if(GUILayout.Button("Test 1",GUILayout.Width(200), GUILayout.Height(100)))            TestSendString("This is a msg form unity3d\tt1\tt2\tt3\tt4");        GUILayout.Space (200);        if(GUILayout.Button("Test 1",GUILayout.Width(200), GUILayout.Height(100)))            TestGetString();        /********通信测试***********/        if(Btn ("GetProducts")){            if(!IsProductAvailable())                throw new System.Exception("IAP not enabled");            productInfo = new List<string>();                        RequstProductInfo("test"); // 获取商品信息!InApp 的 ID,可以用 \n 搞 n 个        }        GUILayout.Space(40);        for(int i=0; i<productInfo.Count; i++){            if(GUILayout.Button (productInfo[i],GUILayout.Height (100), GUILayout.MinWidth (200))){                string[] cell = productInfo[i].Split('\t');                Debug.Log ("[Buy]"+cell[cell.Length-1]);                BuyProduct(cell[cell.Length-1]); // 购买!            }        }    }    bool Btn(string msg){        GUILayout.Space (100);        return  GUILayout.Button (msg,GUILayout.Width (200),GUILayout.Height(100));    }}

-

  • 作者:大锐哥
  • 地址:http://blog.csdn.net/prevention

-

0 0
原创粉丝点击