【7】iOS開(kāi)發(fā)·內(nèi)購(gòu)流程

說(shuō)明:
涉及到金額交易,蘋(píng)果審核的一般嚴(yán)格許多。蘋(píng)果在涉及需要支付中間幣的購(gòu)買(mǎi)必須走蘋(píng)果內(nèi)購(gòu)(例:點(diǎn)券、鉆石、K幣等等),若是涉及實(shí)物的交易,則可以走第三方(支付寶、微信等)支付購(gòu)買(mǎi)。

iOS內(nèi)購(gòu)流程:

一、設(shè)置協(xié)議

1、登錄蘋(píng)果開(kāi)發(fā)者后臺(tái),點(diǎn)擊itunes Connect -> 協(xié)議、稅務(wù)和銀行業(yè)務(wù)

協(xié)議、稅務(wù)和銀行業(yè)務(wù)

2、點(diǎn)擊Request Contracts(申請(qǐng)合同)下面的request,點(diǎn)擊一直確定下去。

申請(qǐng)合同-1

Contact info:聯(lián)系人信息
Bank info:銀行信息
Tax info:稅務(wù)信息

申請(qǐng)合同-2

3、首先設(shè)置聯(lián)系人信息,點(diǎn)擊Contact info下面的 Set up(設(shè)置),點(diǎn)擊Add New Contract(增加先的聯(lián)系方式)

申請(qǐng)合同-3

4、填寫(xiě)詳情(填寫(xiě)完成后點(diǎn)擊save)

填寫(xiě)詳情

5、在下面的所有項(xiàng)目中選擇剛剛填寫(xiě)的信息,選擇后點(diǎn)擊右下角的Done(完成),你可以創(chuàng)建聯(lián)系人,在不同的職務(wù)選擇不同的聯(lián)系人。

Senior Management:高管
Financial:財(cái)務(wù)
Technical:技術(shù)支持
Legal:法務(wù)
Marketing:市場(chǎng)推廣

填寫(xiě)信息

6、設(shè)置銀行信息,點(diǎn)擊Back info下面的Set up,彈出頁(yè)面

點(diǎn)擊Add Bank Account(添加銀行賬號(hào))

image

選擇china,后點(diǎn)擊next。

image

填寫(xiě)了CNAPS Code后點(diǎn)擊Next

image

會(huì)彈出你的銀行卡開(kāi)戶(hù)地的信息,確認(rèn)一下點(diǎn)擊next

image

填寫(xiě)銀行卡信息,注意:戶(hù)主名只能寫(xiě)拼音,比如:李三(Li San)。填完后點(diǎn)擊Next

image

彈出確定信息頁(yè)面,在下面打鉤后點(diǎn)擊Save

image

點(diǎn)擊了save后就可以在彈出的頁(yè)面中選擇剛剛填寫(xiě)的卡了。選擇后點(diǎn)擊Save

image

7、設(shè)置稅務(wù)信息,點(diǎn)擊Tax info下面的Set up,此時(shí)聯(lián)系人信息已經(jīng)變成可以編輯狀態(tài),銀行信息為瀏覽狀態(tài)。

image

彈出的界面中,稅務(wù)分為三種
U.S Tax Forms: 美國(guó)稅務(wù)
Australia Tax Forms:澳大利亞稅務(wù)
Canada Tax Forms: 加拿大稅務(wù)
這里我選擇的美國(guó)稅務(wù),就是第一個(gè)

image

彈出第一個(gè)選擇,點(diǎn)擊submit(提交)后,彈出第二個(gè)選擇

image

彈出第二個(gè)選擇,選擇后點(diǎn)擊submit

image

彈出第三個(gè)頁(yè)面,填寫(xiě)的資料后點(diǎn)擊提交,記得勾選頁(yè)面上的幾個(gè)復(fù)選框

image

在提交成功后,狀態(tài)就變成processing成功

image

到這里設(shè)置的協(xié)議就已經(jīng)設(shè)置完畢。

二、創(chuàng)建項(xiàng)目的內(nèi)購(gòu)

1、進(jìn)入到APP信息頁(yè)面,點(diǎn)擊功能,在彈出的頁(yè)面點(diǎn)擊App內(nèi)購(gòu)買(mǎi)項(xiàng)目后面的?

image

2、在彈出的新對(duì)話(huà)框中選擇你需要哪一種服務(wù),由于我的項(xiàng)目需要兌換成消耗的金幣,所以我選擇第一個(gè)。選擇后點(diǎn)擊創(chuàng)建。

image

3、開(kāi)始填寫(xiě)內(nèi)購(gòu)項(xiàng)目信息。填完后點(diǎn)擊右上角的存儲(chǔ)(所有信息必須填寫(xiě)完整)。

image

4、點(diǎn)擊存儲(chǔ)后,內(nèi)購(gòu)列表就會(huì)有剛剛創(chuàng)建的內(nèi)購(gòu)條目。

image

你app有幾個(gè)內(nèi)購(gòu)級(jí)別就需要依次創(chuàng)建幾個(gè)條目。

添加測(cè)試賬號(hào),用來(lái)測(cè)試支付功能

1、點(diǎn)擊圖中用戶(hù)和職能

image

2、點(diǎn)擊沙盒測(cè)試員,然后點(diǎn)擊左邊的?

image

3、設(shè)置好信息點(diǎn)擊右上角存儲(chǔ)就可以,記住里面的郵箱和密碼用于支付的時(shí)候登陸Apple id

image
三、代碼集成

創(chuàng)建一個(gè)測(cè)試類(lèi):

#import "TestPayController.h"

// 1.首先導(dǎo)入支付包
#import <StoreKit/StoreKit.h>

// 2.設(shè)置代理服務(wù)
@interface TestPayController ()<SKPaymentTransactionObserver,SKProductsRequestDelegate>

@end

@implementation TestPayController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];

    //3.創(chuàng)建測(cè)試按鈕
    UIButton *testBtn = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    testBtn.backgroundColor = [UIColor redColor];
    [testBtn addTarget:self action:@selector(clickTestBtnAction) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:testBtn];

    // 4.設(shè)置支付服務(wù)
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];

}

//點(diǎn)擊測(cè)試按鈕
- (void)clickTestBtnAction
{

    // 5.點(diǎn)擊按鈕的時(shí)候判斷app是否允許apple支付

    //如果app允許applepay
    if ([SKPaymentQueue canMakePayments]) {
        NSLog(@"yes");

        // 6.請(qǐng)求蘋(píng)果后臺(tái)商品
        [self getRequestAppleProduct];
    }
    else
    {
        NSLog(@"not");
    }
}

//請(qǐng)求蘋(píng)果商品
- (void)getRequestAppleProduct
{
    // 7.這里的com.czchat.CZChat01就對(duì)應(yīng)著蘋(píng)果后臺(tái)的商品ID,他們是通過(guò)這個(gè)ID進(jìn)行聯(lián)系的。
    NSArray *product = [[NSArray alloc] initWithObjects:@"com.czchat.CZChat01",nil];

    NSSet *nsset = [NSSet setWithArray:product];

    // 8.初始化請(qǐng)求
    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset];
    request.delegate = self;

    // 9.開(kāi)始請(qǐng)求
    [request start];
}

// 10.接收到產(chǎn)品的返回信息,然后用返回的商品信息進(jìn)行發(fā)起購(gòu)買(mǎi)請(qǐng)求
- (void) productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    NSArray *product = response.products;

    //如果服務(wù)器沒(méi)有產(chǎn)品
    if([product count] == 0){
        NSLog(@"nothing");
        return;
    }

    SKProduct *requestProduct = nil;
    for (SKProduct *pro in product) {

        NSLog(@"%@", [pro description]);
        NSLog(@"%@", [pro localizedTitle]);
        NSLog(@"%@", [pro localizedDescription]);
        NSLog(@"%@", [pro price]);
        NSLog(@"%@", [pro productIdentifier]);

        // 11.如果后臺(tái)消費(fèi)條目的ID與我這里需要請(qǐng)求的一樣(用于確保訂單的正確性)
        if([pro.productIdentifier isEqualToString:@"com.czchat.CZChat01"]){
            requestProduct = pro;
        }
    }

    // 12.發(fā)送購(gòu)買(mǎi)請(qǐng)求
    SKPayment *payment = [SKPayment paymentWithProduct:requestProduct];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

//請(qǐng)求失敗
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
    NSLog(@"error:%@", error);
}

//反饋請(qǐng)求的產(chǎn)品信息結(jié)束后
- (void)requestDidFinish:(SKRequest *)request{
    NSLog(@"信息反饋結(jié)束");
}

// 13.監(jiān)聽(tīng)購(gòu)買(mǎi)結(jié)果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction{
    for(SKPaymentTransaction *tran in transaction){

        switch (tran.transactionState) {
            case SKPaymentTransactionStatePurchased:
                NSLog(@"交易完成");

                break;
            case SKPaymentTransactionStatePurchasing:
                NSLog(@"商品添加進(jìn)列表");

                break;
            case SKPaymentTransactionStateRestored:
                NSLog(@"已經(jīng)購(gòu)買(mǎi)過(guò)商品");
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];
                break;
            case SKPaymentTransactionStateFailed:
                NSLog(@"交易失敗");
                [[SKPaymentQueue defaultQueue] finishTransaction:tran];
                break;
            default:
                break;
        }
    }
}

// 14.交易結(jié)束,當(dāng)交易結(jié)束后還要去appstore上驗(yàn)證支付信息是否都正確,只有所有都正確后,我們就可以給用戶(hù)方法我們的虛擬物品了。
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
    NSString * str=[[NSString alloc]initWithData:transaction.transactionReceipt encoding:NSUTF8StringEncoding];

    NSString *environment=[self environmentForReceipt:str];
    NSLog(@"----- 完成交易調(diào)用的方法completeTransaction 1--------%@",environment);

    // 驗(yàn)證憑據(jù),獲取到蘋(píng)果返回的交易憑據(jù)
    // appStoreReceiptURL iOS7.0增加的,購(gòu)買(mǎi)交易完成后,會(huì)將憑據(jù)存放在該地址
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    // 從沙盒中獲取到購(gòu)買(mǎi)憑據(jù)
    NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
    /**
     20      BASE64 常用的編碼方案,通常用于數(shù)據(jù)傳輸,以及加密算法的基礎(chǔ)算法,傳輸過(guò)程中能夠保證數(shù)據(jù)傳輸?shù)姆€(wěn)定性
     21      BASE64是可以編碼和解碼的
     22      */
    NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];

    NSString *sendString = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
    NSLog(@"_____%@",sendString);
    NSURL *StoreURL=nil;
    if ([environment isEqualToString:@"environment=Sandbox"]) {

        StoreURL= [[NSURL alloc] initWithString: @"https://sandbox.itunes.apple.com/verifyReceipt"];
    }
    else{

        StoreURL= [[NSURL alloc] initWithString: @"https://buy.itunes.apple.com/verifyReceipt"];
    }
    //這個(gè)二進(jìn)制數(shù)據(jù)由服務(wù)器進(jìn)行驗(yàn)證;zl
    NSData *postData = [NSData dataWithBytes:[sendString UTF8String] length:[sendString length]];

    NSLog(@"++++++%@",postData);
    NSMutableURLRequest *connectionRequest = [NSMutableURLRequest requestWithURL:StoreURL];

    [connectionRequest setHTTPMethod:@"POST"];
    [connectionRequest setTimeoutInterval:50.0];//120.0---50.0zl
    [connectionRequest setCachePolicy:NSURLRequestUseProtocolCachePolicy];
    [connectionRequest setHTTPBody:postData];

    //開(kāi)始請(qǐng)求
    NSError *error=nil;
    NSData *responseData=[NSURLConnection sendSynchronousRequest:connectionRequest returningResponse:nil error:&error];
    if (error) {
        NSLog(@"驗(yàn)證購(gòu)買(mǎi)過(guò)程中發(fā)生錯(cuò)誤,錯(cuò)誤信息:%@",error.localizedDescription);
        return;
    }
    NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:nil];
    NSLog(@"請(qǐng)求成功后的數(shù)據(jù):%@",dic);
//這里可以等待上面請(qǐng)求的數(shù)據(jù)完成后并且state = 0 驗(yàn)證憑據(jù)成功來(lái)判斷后進(jìn)入自己服務(wù)器邏輯的判斷,也可以直接進(jìn)行服務(wù)器邏輯的判斷,驗(yàn)證憑據(jù)也就是一個(gè)安全的問(wèn)題。樓主這里沒(méi)有用state = 0 來(lái)判斷。
    //  [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

    NSString *product = transaction.payment.productIdentifier;

    NSLog(@"transaction.payment.productIdentifier++++%@",product);

    if ([product length] > 0)
    {
        NSArray *tt = [product componentsSeparatedByString:@"."];

        NSString *bookid = [tt lastObject];

        if([bookid length] > 0)
        {

            NSLog(@"打印bookid%@",bookid);
//這里可以做操作吧用戶(hù)對(duì)應(yīng)的虛擬物品通過(guò)自己服務(wù)器進(jìn)行下發(fā)操作,或者在這里通過(guò)判斷得到用戶(hù)將會(huì)得到多少虛擬物品,在后面([self getApplePayDataToServerRequsetWith:transaction];的地方)上傳上面自己的服務(wù)器。
        }
    }
//此方法為將這一次操作上傳給我本地服務(wù)器,記得在上傳成功過(guò)后一定要記得銷(xiāo)毀本次操作。調(diào)用[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
    [self getApplePayDataToServerRequsetWith:transaction];
}

//結(jié)束后一定要銷(xiāo)毀
- (void)dealloc
{
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

-(NSString * )environmentForReceipt:(NSString * )str
{
    str= [str stringByReplacingOccurrencesOfString:@"\r\n" withString:@""];

    str = [str stringByReplacingOccurrencesOfString:@"\n" withString:@""];

    str = [str stringByReplacingOccurrencesOfString:@"\t" withString:@""];

    str=[str stringByReplacingOccurrencesOfString:@" " withString:@""];

    str=[str stringByReplacingOccurrencesOfString:@"\"" withString:@""];

    NSArray * arr=[str componentsSeparatedByString:@";"];

    //存儲(chǔ)收據(jù)環(huán)境的變量
    NSString * environment=arr[2];
    return environment;
}

@end

四、注意事項(xiàng)

1、必須用真機(jī)測(cè)試;
2、測(cè)試的時(shí)候必須退出自己的apple ID,彈出頁(yè)面后登陸沙盒的測(cè)試apple id;
3、在需要修改已經(jīng)上線(xiàn)的內(nèi)購(gòu)的時(shí)候需要重新創(chuàng)建新的內(nèi)購(gòu)條目,然后重新提交;
4、文章大部分內(nèi)容來(lái)自iOS內(nèi)購(gòu)流程,感謝該作者的分享;

五、參考文章:

iOS內(nèi)購(gòu)流程-http://www.itdecent.cn/p/f7bff61e0b31/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容