Unityios平台IAP内购和沙箱测试流程详解(开发中遇到的坑)

Posted 天生爱赞美

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unityios平台IAP内购和沙箱测试流程详解(开发中遇到的坑)相关的知识,希望对你有一定的参考价值。

Unity ios内购

内购流程

  • 1、在 AppStore 中创建相应的物品,创建内购沙盒测试账号
  • 2、客户端从后台获取相应的物品 ID (当然也可以再客户端写死,但后期扩展性就受限制了)
  • 3、依据相应的物品 ID 请求商品的相关信息
  • 4、依据商品信息创建订单请求交易
  • 5、依据返回的订单状态处理交易结果
  • 6、请求后台再次验证订单状态
  • 7、依据后台返回结果处理相关逻辑

2、创建内购物品以及沙盒测试账号


思路:

Unity调用iOS内购代码实现

效果图:


重要提示:

测试一定要用沙盒账号,否则无效!

流程

这里就不重复写了,直接上截图 

OC代码:

IAPInterface(主要是实现Unity跟OC的IAP代码的一个交互作用,等于是一个中间桥梁)

#import <Foundation/Foundation.h>

@interface IAPInterface : NSObject

@end
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
#import "IAPInterface.h"
#import "IAPManager.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)
    NSString *list = [NSString stringWithUTF8String:p];
    NSLog(@"productKey:%@",list);
    [iapManager requestProductData:list];


void BuyProduct(void *p)
    [iapManager buyRequest:[NSString stringWithUTF8String:p]];


@end
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

IAPManager(真真的iOS的购买功能)

#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
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
#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

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128

Unity中调用的C#代码

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")]
    内购(IAP)详解

ios IAP 内购验证

IOS内购(IAP)的那些事

苹果内购和 Apple Pay

Apple开发如何在设备中切换IAP(内购)沙盒测试账户?

Apple开发如何在设备中切换IAP(内购)沙盒测试账户?