iOS 應(yīng)用內(nèi)支付

參考鏈接
iOS開發(fā)之內(nèi)購-AppStore
iOS App提交指南(二)-協(xié)議、稅務(wù)和銀行業(yè)務(wù)
iOS應(yīng)用內(nèi)付費(fèi)(IAP)開發(fā)步驟列表

一、創(chuàng)建App

首先你需要登錄 App的ItunesConnection,你會(huì)看到如下界面


ItunesConnection

簡單的介紹一下這幾個(gè)選項(xiàng)

  1. 我的App主要用于管理自己的App應(yīng)用,例如編輯資料,上架,下架等。
  2. 銷售和趨勢主要是來查看App在各個(gè)平臺(tái)的下載量,收入等方面數(shù)據(jù),里面有曲線圖等圖文結(jié)合的方式給我們參考。
  3. 付款和財(cái)務(wù)報(bào)告顯示的是你的收入以及付款等相關(guān)信息。
  4. iAd主要是跟廣告有關(guān),開發(fā)者可以登錄到Workbench,通過iAd對應(yīng)用的廣告進(jìn)行控制。
  5. 用戶和職能用于生成相應(yīng)賬號(hào),例如蘋果沙河測試賬號(hào)。
  6. 協(xié)議,稅務(wù)和銀行業(yè)務(wù)則是你銀行相關(guān)賬戶的信息設(shè)置。

在這里我們選擇第一個(gè)選項(xiàng),我的App,然后點(diǎn)擊左上角的加號(hào),新建一個(gè)用來測試用的App。

新建App

點(diǎn)新建 App,會(huì)出現(xiàn)新建窗口;


新建窗口

在這里有幾個(gè)需要填寫的地方,名稱自己取,平臺(tái)IOS,語言選擇了簡體中文,套裝ID也就是你的Bundle Identifier,需要你在Certificates頁面 申請BundleID,SKU可以理解為用戶看一看到的唯一標(biāo)示,會(huì)體現(xiàn)在你的app的App Store的鏈接中。

申請BundleID

打開Certificates頁面,在左側(cè)選擇Identifiers,并點(diǎn)擊加號(hào),申請一個(gè)新的Identifiers。


申請一個(gè)新的Identifiers

在這里Name可以隨意填寫,我填寫的是TestAppStroeTestDemo,而用來使用的BundleID,我們在這里必須選擇第一個(gè)選項(xiàng)唯一的,不用選擇通配。在下面的選項(xiàng)中, 我們只需要勾選一個(gè) Apple Pay即可,其他選項(xiàng)看自己需求,我在這里只選擇了它。


選項(xiàng)

之后我們回到創(chuàng)建App,選擇好自己剛創(chuàng)建的 BundleID ,填寫SKU, SKU是你App的專用ID,我在這里隨意填寫,直接復(fù)制了App名。點(diǎn)擊創(chuàng)建,我們的測試App則創(chuàng)建成功。

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

進(jìn)入?yún)f(xié)議、稅務(wù)和銀行業(yè)務(wù)頁面


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

進(jìn)入?yún)f(xié)議、稅務(wù)和銀行業(yè)務(wù)頁面后,會(huì)有3種合同類型,如果你之前沒有主動(dòng)申請過去合同,那么一般你現(xiàn)在激活的合同只有iOS Free Application一種。

頁面內(nèi)容分為兩塊:

  • Request Contracts(申請合同)
  • Contracts In Effect(已生效合同)。

合同類型分為3種:

  • iOS Free Application(免費(fèi)應(yīng)用合同)
  • iOS Paid Application(付費(fèi)應(yīng)用合同)
  • iAd App NetNetwork(廣告合同)

筆者暫時(shí)只申請過付費(fèi)應(yīng)用合同,所以下面主要講一下付費(fèi)應(yīng)用合同的申請流程。


付費(fèi)應(yīng)用合同

當(dāng)我們點(diǎn)擊申請iOS Paid Application合同后,該合同的狀態(tài)會(huì)變成如下的樣子,我們可以看到其中Status為Pending Tax, Bank, Contact。意思是聯(lián)系方式、銀行和稅務(wù)信息沒有填寫。


缺少信息

1、填寫聯(lián)系方式

我們點(diǎn)擊Contact Info下方的Set Up按鈕可以進(jìn)入聯(lián)系方式填寫頁面,如下圖:


填寫聯(lián)系方式

如果你沒有添加過聯(lián)系人,你需要通過Add New Contact按鈕來添加一個(gè)新的聯(lián)系人。然后指定聯(lián)系人的職務(wù),職務(wù)如下:

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

如果你是獨(dú)立開發(fā)者,可以全部填你自己一個(gè)人。

2、填寫銀行卡信息

我們點(diǎn)擊Bank Info下方的Set Up按鈕可以進(jìn)入聯(lián)系方式填寫頁面,如下圖:


添加銀行卡信息

選擇你的銀行賬戶,如果你沒有,點(diǎn)擊旁邊的Add Bank Account添加一個(gè)賬戶。
下面是添加一個(gè)賬戶的流程。

2-1、選擇銀行所在的國家
選擇銀行所在的國家
2-2、填寫銀行CNAPS Code

如果你不知道CNAPS Code是多少,可以點(diǎn)擊Look up Transit Number來查詢,查詢時(shí)會(huì)根據(jù)3個(gè)關(guān)鍵信息來查詢,如下:

  • Bank Name:銀行的英文名稱(不能是拼音)
  • City:銀行所在的城市英文名稱(中國的城市用拼音)
  • Postal Code:郵編
  • 然后在下面就會(huì)出來備選的銀行,選擇正確的銀行后,點(diǎn)擊next,進(jìn)入下一步。


    填寫銀行CNAPS Code

    銀行信息
2-3、確認(rèn)銀行信息
確認(rèn)銀行信息
2-4、填寫銀行賬號(hào)信息
  • Bank Account Number:銀行賬號(hào)
  • Confirm Bank Account Number:再次輸入銀行賬號(hào)
  • Account Holder Name:持卡人姓名,中文名用拼寫,名在前,姓在后
  • Bank Account Currency:貨幣類型,一般國內(nèi)的開發(fā)者選擇CNY


    填寫銀行賬號(hào)信息
2-5、確認(rèn)所有信息
確認(rèn)所有信息

3、填寫稅務(wù)信息

稅務(wù)信息這一塊了解不是很多,不過因?yàn)槭菄鴥?nèi)開發(fā)者,可以不用太費(fèi)心,稅務(wù)信息分3種:

  • U.S Tax Forms: 美國稅務(wù)
  • Australia Tax Forms:澳大利亞稅務(wù)
  • Canada Tax Forms: 加拿大稅務(wù)


    填寫稅務(wù)信息

    筆者選擇的是U.S Tax Forms,選擇后會(huì)問你兩個(gè)問題,第一個(gè)問題如下:詢問你是否是美國居民,有沒有美國伙伴關(guān)系或者美國公司,如果沒有直接選擇No。


    是否美國居民

    接下來第二個(gè)問題如下:詢問你有沒有在美國的商業(yè)性活動(dòng),沒有也直接選No。
    是否在美國的商業(yè)性活動(dòng)

然后填寫你的稅務(wù)信息,包括以下幾點(diǎn):

  • Individual or Organization Name:個(gè)人或者組織名稱
  • Country of incorporation: 所在國家
  • Type of Beneficial Owner:受益方式,獨(dú)立開發(fā)者選個(gè)人
  • Permanent Residence:居住地址
  • Mailing address:郵寄地址
  • Name of Person Making this Declaration:聲明人
  • Title:頭銜

填寫完這些信息后就可以提交了


提交審核

4、等待審核

當(dāng)你填寫完所有資料后,合同狀態(tài)就會(huì)變成Processing,筆者凌晨1點(diǎn)左右提交,下午就通過了。


等待審核

三、添加內(nèi)購買項(xiàng)目

App創(chuàng)建好之后,我們打開創(chuàng)建的App,在左上角選擇功能,會(huì)看到左側(cè)的App 內(nèi)購買項(xiàng)目。我們點(diǎn)擊右下角的加號(hào),為App添加內(nèi)購項(xiàng)目。


內(nèi)購買項(xiàng)目

虛擬物品添加分為如下幾種:

  1. 消耗品(Consumable products):比如游戲內(nèi)金幣等。
  2. 不可消耗品(Non-consumable products):簡單來說就是一次購買,終身可用(用戶可隨時(shí)從App Store restore)。
  3. 自動(dòng)更新訂閱品(Auto-renewablesubscriptions):和不可消耗品的不同點(diǎn)是有失效時(shí)間。比如一整年的付費(fèi)周刊。在這種模式下,開發(fā)者定期投遞內(nèi)容,用戶在訂閱期內(nèi)隨時(shí)可以訪問這些內(nèi)容。訂閱快要過期時(shí),系統(tǒng)將自動(dòng)更新訂閱(如果用戶同意)。
  4. 非自動(dòng)更新訂閱品(Non-renewablesubscriptions):一般使用場景是從用戶從IAP購買后,購買信息存放在自己的開發(fā)者服務(wù)器上。失效日期/可用是由開發(fā)者服務(wù)器自行控制的,而非由AppStore控制,這一點(diǎn)與自動(dòng)更新訂閱品有差異。
  5. 免費(fèi)訂閱品(Free subscriptions):在Newsstand中放置免費(fèi)訂閱的一種方式。免費(fèi)訂閱永不過期。只能用于Newsstand-enabled apps。

類型2、3、5都是以Apple ID為粒度的。比如小張有三個(gè)iPad,有一個(gè)Apple ID購買了不可消耗品,則三個(gè)iPad上都可以使用。

類型1、4一般來說則是現(xiàn)買現(xiàn)用。如果開發(fā)者自己想做更多控制,一般選4

之后我們會(huì)看到類型的選項(xiàng),如下圖


選擇類型

官方的注釋寫的很清楚了,只在這里簡單的說下前兩種:

  • 消耗型項(xiàng)目 就像你玩游戲需要買金幣,買鉆石等,只要花錢就可以無限次的購買
  • 非消耗型項(xiàng)目 就像你在App Store購買App,買了一次之后就不用再買第二次,你擁有永久使用權(quán)。
    在我們的app中,是充值會(huì)員,所以選擇的是第一種,可以無限次購買。


    填寫信息

    這里有幾個(gè)選項(xiàng),需要填寫商品名稱,產(chǎn)品ID以及價(jià)格等級(jí),簡單說明一下

  1. 商品名稱根據(jù)你的消費(fèi)道具的實(shí)際意義來說明,比如“100顆寶石”,“100金幣”等。
  2. 產(chǎn)品ID是比較重要的,由項(xiàng)目自定義,只要唯一即可,因?yàn)闇y試,我在這里隨便填寫的123,在實(shí)際應(yīng)用中,一定要認(rèn)真填寫。
  3. 價(jià)格等級(jí)的話“查看價(jià)格表”中有對應(yīng)的說明,可以對照著表中每個(gè)國家的貨幣價(jià)格與等級(jí)來選擇
    接下來是語言選擇,和上傳快照如下圖


    內(nèi)置購買詳細(xì)信息

    點(diǎn)擊添加語言,填寫名稱和描述,這里我們依然選擇簡體中文,如下


    添加語言

    審核備注,根據(jù)實(shí)際情況填寫,可以不填。而下面的屏幕快照,則是商品圖片,以像素為單位,最低尺寸為321,390,尺寸需求如下圖,上傳即可。
    審核備注

    到這里為止, 我們的內(nèi)購項(xiàng)目則添加完成。接下來則是測試階段了。

四、申請沙盒測試賬號(hào)(用來測試購買項(xiàng)目)

這個(gè)賬號(hào),是利用蘋果的沙盒測試環(huán)境來模擬AppStore的購買流程,你肯定不會(huì)想要用真實(shí)RMB去購買測試吧?
首先我們回到iTunes Connect中,在這里我們選擇用戶和職能。


用戶與職能

然后在上面的第三個(gè)選項(xiàng)沙箱技術(shù)測試員中點(diǎn)擊加號(hào),添加測試員。


添加測試員

在信息填寫頁面只簡單說兩句。
所有信息都可以隨意填寫,不用管是否真實(shí)。
App Store地區(qū)選擇,一定要選對,它對應(yīng)的是你創(chuàng)建的App的地區(qū), 你App是中國的話, 在這里我們依然選擇中國。

此賬號(hào)只能用來測試,不要在正式的appstore上使用
填寫完畢,點(diǎn)擊保存后,我們則生成一個(gè)測試賬號(hào),當(dāng)然這個(gè)賬號(hào)是可以隨時(shí)刪除和添加的。


生成測試賬號(hào)

五、大致流程

IAP流程分為兩種,一種是直接使用Apple的服務(wù)器進(jìn)行購買和驗(yàn)證,另一種就是自己假設(shè)服務(wù)器進(jìn)行驗(yàn)證。由于國內(nèi)網(wǎng)絡(luò)連接Apple服務(wù)器驗(yàn)證非常慢,而且也為了防止黑客偽造購買憑證,通用做法是自己架設(shè)服務(wù)器進(jìn)行驗(yàn)證。

下面我們通過圖來看看兩種方式的差別:

5.1、使用Apple服務(wù)器

使用Apple服務(wù)器

5.2、自己架設(shè)服務(wù)器

自己架設(shè)服務(wù)器

簡單說下第二中情況的流程:

  1. 用戶進(jìn)入購買虛擬物品頁面,App從后臺(tái)服務(wù)器獲取產(chǎn)品列表然后顯示給用戶
  2. 用戶點(diǎn)擊購買購買某一個(gè)虛擬物品,APP就發(fā)送該虛擬物品的productionIdentifier到Apple服務(wù)器
  3. Apple服務(wù)器根據(jù)APP發(fā)送過來的productionIdentifier返回相應(yīng)的物品的信息(描述,價(jià)格等)
  4. 用戶點(diǎn)擊確認(rèn)鍵購買該物品,購買請求發(fā)送到Apple服務(wù)器
  5. Apple服務(wù)器完成購買后,返回用戶一個(gè)完成購買的憑證
  6. APP發(fā)送這個(gè)憑證到后臺(tái)服務(wù)器驗(yàn)證
  7. 后臺(tái)服務(wù)器把這個(gè)憑證發(fā)送到Apple驗(yàn)證,Apple返回一個(gè)字段給后臺(tái)服務(wù)器表明該憑證是否有效
  8. 后臺(tái)服務(wù)器把驗(yàn)證結(jié)果在發(fā)送到APP,APP根據(jù)驗(yàn)證結(jié)果做相應(yīng)的處理

六、大致代碼

#import "ViewController.h"
#import <StoreKit/StoreKit.h>

@interface ViewController () <SKPaymentTransactionObserver, SKProductsRequestDelegate>

@property (nonatomic, strong) NSString * receipt;

@end

@implementation ViewController

/**
 *  開發(fā)流程:
 *  1、引入頭文件 #import <StoreKit/StoreKit.h>
 *  2、檢查用戶是否允許使用 內(nèi)置購買 [SKPaymentQueue canMakePayments]
 *  3、如果允許:獲取所有付費(fèi)Product ID(productionIdentifier)列表??梢杂贸A勘4嬖诒镜?,也可以自己服務(wù)器返回(原因:連接蘋果服務(wù)器比較慢)
 *  4、先查詢是否有該productionIdentifier的商品信息,獲取SKPayment實(shí)例,然后通過SKPaymentQueue的 addPayment方法發(fā)起一個(gè)購買的操作。
 *  5、監(jiān)聽購買結(jié)果 [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
 *  6、購買完成回調(diào)- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
 *  7、服務(wù)器驗(yàn)證憑證(Optional)。如果購買成功,我們需要將憑證發(fā)送到服務(wù)器上進(jìn)行驗(yàn)證。
 *      服務(wù)器工作:
 *      7.1 接收ios端發(fā)過來的購買憑證。
 *      7.2 判斷憑證是否已經(jīng)存在或驗(yàn)證過,然后存儲(chǔ)該憑證。
 *      7.3 將該憑證發(fā)送到蘋果的服務(wù)器驗(yàn)證,并將驗(yàn)證結(jié)果返回給客戶端。
 *      7.4 如果需要,修改用戶相應(yīng)的會(huì)員權(quán)限。
 *  8、網(wǎng)絡(luò)異常、崩潰等導(dǎo)致無法驗(yàn)證,將購買憑證持久化。用戶下次啟動(dòng)的時(shí)候,再發(fā)一次驗(yàn)證
 *      8.1 保存數(shù)據(jù)(日期、用戶、憑證receipt)
 *      8.2 重新啟動(dòng),讀取數(shù)據(jù),發(fā)送網(wǎng)絡(luò)請求
 *      8.3 如果成功,刪除文件
 */

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 監(jiān)聽購買結(jié)果
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}

- (void)buyProdutin:(UIButton *)sender
{
    // 確認(rèn)用戶是否允許使用 內(nèi)置購買
    if([SKPaymentQueue canMakePayments]){
        // 獲取商品的productionIdentifier
        NSString * productIdentifier = @"";     //用戶選擇
        [self getProductInfo:productIdentifier];
    }else{
        
    }
}

#pragma mark - 查詢productIdentifier 的商品信息
- (void)getProductInfo:(NSString *)productIdentifier
{
    NSArray * product = [[NSArray alloc] initWithObjects:productIdentifier, nil];
    NSSet * set = [NSSet setWithArray:product];
 
    // 請求蘋果服務(wù)器,是否有該商品
    SKProductsRequest * request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
    request.delegate = self;
    [request start];
    
    // 這里可彈出提示信息 : 正在購買,請稍后
}

// 查詢該產(chǎn)品信息
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    NSArray * myProduct = response.products;
    if(myProduct.count == 0){
        // 說明沒有該商品,或查詢失敗
        
        return;
    }
    
    // 如果有,發(fā)起購買操作
    SKPayment * payment = [SKPayment paymentWithProduct:myProduct[0]];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

// 查詢失敗
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
    // 提示信息
}

#pragma mark - 購買回調(diào)
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions
{
    for(SKPaymentTransaction * transaction in transactions){
        switch (transaction.transactionState) {
            case SKPaymentTransactionStatePurchased:
                // 交易成功
                [self completeTransaction:transaction];
                break;
            case SKPaymentTransactionStateFailed:
                // 交易失敗
                [self failedTransaction:transaction];
                break;
                
            case SKPaymentTransactionStateRestored:
                // 已經(jīng)購買過該商品
                [self restoreTransaction:transaction];
                break;
                
            case SKPaymentTransactionStatePurchasing:
                // 商品添加進(jìn)列表
                
                break;
            default:
                break;
        }
    }
}

//沙盒測試環(huán)境驗(yàn)證
#define SANDBOX @"https://sandbox.itunes.apple.com/verifyReceipt"
//正式環(huán)境驗(yàn)證
#define AppStore @"https://buy.itunes.apple.com/verifyReceipt"
/**
 *  驗(yàn)證購買,避免越獄軟件模擬蘋果請求達(dá)到非法購買問題

// 交易結(jié)束后,驗(yàn)證票據(jù)信息是否正確,之后才可以給用戶商品
- (void)completeTransaction:(SKPaymentTransaction *)transaction {
    // 測試環(huán)境
    self.receipt = [[NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]] base64EncodedStringWithOptions:0];
    NSError *error;
    NSDictionary *requestContents = @{
                                      @"receipt-data": self.receipt
                                      };
    NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents
                                                          options:0
                                                            error:&error];
    // 設(shè)置URL
    NSURL *storeURL = [NSURL URLWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"];
    NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
    [storeRequest setHTTPMethod:@"POST"];
    [storeRequest setHTTPBody:requestData];
    
   // 網(wǎng)絡(luò)請求,驗(yàn)證
    
    
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

// 交易失敗后,回調(diào)
- (void)failedTransaction:(SKPaymentTransaction *)transaction {
    if(transaction.error.code != SKErrorPaymentCancelled) {
        // 購買失敗
        
    } else {
        // 用戶取消交易
        
    }
    
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

// 已購買過商品回調(diào)
- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

#pragma mark - 發(fā)送憑證失敗的處理
/**
 *  1 保存數(shù)據(jù)(日期、用戶、憑證receipt)
 *  2 重新啟動(dòng),讀取數(shù)據(jù),發(fā)送網(wǎng)絡(luò)請求
 *  3 如果成功,刪除文件
 */

- (void)dealloc
{
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}

@end

需要注意以下幾點(diǎn):

  • 代碼中的self.profuctIdArr所填寫的是你的購買項(xiàng)目的的ID,我這里是當(dāng)時(shí)填寫的ID 123。
  • 在監(jiān)聽購買結(jié)果后,一定要調(diào)用[[SKPaymentQueue defaultQueue] finishTransaction:tran];來允許你從支付隊(duì)列中移除交易。
  • 沙盒環(huán)境測試appStore內(nèi)購流程的時(shí)候,請使用沒越獄的設(shè)備。
  • 請務(wù)必使用真機(jī)來測試,一切以真機(jī)為準(zhǔn)。
  • 項(xiàng)目的Bundle identifier需要與您申請AppID時(shí)填寫的bundleID一致,不然會(huì)無法請求到商品信息。
  • 真機(jī)測試的時(shí)候,一定要退出原來的賬號(hào),才能用沙盒測試賬號(hào)
  • 二次驗(yàn)證,請注意區(qū)分宏, 測試用沙盒驗(yàn)證
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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