Flutter iOS 蘋果IAP(內(nèi)購(gòu))實(shí)現(xiàn)步驟及問(wèn)題總結(jié)(全網(wǎng)最全)

IAP內(nèi)購(gòu)支付流程

效果圖
  • Client向Server發(fā)送請(qǐng)求侨赡,獲得一份產(chǎn)品列表。
  • Server返回包含產(chǎn)品標(biāo)識(shí)符的列表锚烦。
  • Client向App Store發(fā)送請(qǐng)求扩然,得到產(chǎn)品的信息。
  • App Store返回產(chǎn)品信息聋伦。
  • Client把返回的產(chǎn)品信息顯示給用戶(App的store界面)
  • 用戶選擇某個(gè)產(chǎn)品
  • Client向App Store發(fā)送支付請(qǐng)求
  • App Store處理支付請(qǐng)求并返回交易完成信息
  • Client從信息中獲得數(shù)據(jù)夫偶,并發(fā)送至Server
  • Server紀(jì)錄數(shù)據(jù)界睁,并進(jìn)行審(我們的)查
  • Server將數(shù)據(jù)發(fā)給App Store來(lái)驗(yàn)證該交易的有效性
  • App Store對(duì)收到的數(shù)據(jù)進(jìn)行解析,返回該數(shù)據(jù)和說(shuō)明其是否有效的標(biāo)識(shí)
  • Server讀取返回的數(shù)據(jù)兵拢,確定用戶購(gòu)買的內(nèi)容
  • Server將購(gòu)買的內(nèi)容傳遞給Client

配置內(nèi)購(gòu)環(huán)境

  • 按要求錄入該賬戶銀行卡信息和相關(guān)用戶信息
  • 根據(jù)項(xiàng)目需求選擇適合的內(nèi)購(gòu)類型:消耗項(xiàng)目翻斟、非消耗項(xiàng)目、自動(dòng)續(xù)費(fèi)说铃、非自動(dòng) 續(xù)費(fèi)访惜;
  • 錄入相應(yīng)的產(chǎn)品內(nèi)購(gòu)信息如:名稱、ID腻扇、價(jià)格债热;
  • 創(chuàng)建 沙盒測(cè)試賬號(hào)
  • Capabilities里面打開(kāi)Purchase功能幼苛;

* 錄入該賬戶銀行卡信息和相關(guān)用戶信息

點(diǎn)擊 “協(xié)議窒篱、稅務(wù)和銀行業(yè)務(wù)”


15755521108887.jpg

內(nèi)購(gòu)用的是付費(fèi)應(yīng)用程序,先簽署《付費(fèi)應(yīng)用程序協(xié)議》舶沿,同意后狀態(tài)變更為“用戶信息待處理”墙杯,等待審核。


15755521303042.jpg

狀態(tài)更改完畢后括荡,點(diǎn)擊“開(kāi)始設(shè)置稅務(wù)高镐、銀行業(yè)務(wù)和聯(lián)系信息”。
(1)添加銀行賬戶,按照要求填寫相關(guān)內(nèi)容即可畸冲。


15755521500978.jpg

(2)選擇報(bào)稅表嫉髓,并填寫。所有與 Apple 有商業(yè)合作者必選都是美國(guó)召夹,若有其他需求岩喷,可以多選。

15755521681828.jpg

15755521821480.jpg

繼續(xù)填寫监憎,首先認(rèn)證公司基本信息纱意,選擇所有人類型,確認(rèn)無(wú)誤后認(rèn)證條款處打?qū)?/p>

15755521934163.jpg
15755522006604.jpg

Part I 部分鲸阔,繼續(xù)核對(duì)公司相關(guān)信息逼纸,選填內(nèi)容可不填。

15755522475582.jpg

Part III 部分汰翠,簽署稅務(wù)條約十拣,設(shè)置利益限制條款的種類,選填內(nèi)容可不填渔扎。此部分如果需要可勾選上下圖勾選框硫狞,不需要可不勾選,我們這個(gè)項(xiàng)目沒(méi)有用到part III 部分,所以沒(méi)有勾選。


15755522609491.jpg

Part XXX 部分残吩,確認(rèn)之前填寫的信息财忽,勾選完畢后,提交

15755522722467.jpg

(3)填寫聯(lián)系信息泣侮,共5個(gè)即彪。高級(jí)管理、財(cái)務(wù)活尊、技術(shù)隶校、法務(wù)、營(yíng)銷蛹锰。只需要提供5個(gè)人的基本信息即可深胳。

15755522842121.jpg

添加內(nèi)購(gòu)商品信息

https://appstoreconnect.apple.com/apps/1604297713/appstore/addons?m=

image.png

消耗型項(xiàng)目

只可使用一次的產(chǎn)品,使用之后即失效宁仔,必須再次購(gòu)買稠屠。

示例:釣魚(yú) App 中的魚(yú)食。

非消耗型項(xiàng)目

只需購(gòu)買一次翎苫,不會(huì)過(guò)期或隨著使用而減少的產(chǎn)品权埠。

示例:游戲 App 的賽道。

自動(dòng)續(xù)期訂閱

允許用戶在固定時(shí)間段內(nèi)購(gòu)買動(dòng)態(tài)內(nèi)容的產(chǎn)品煎谍。除非用戶選擇取消攘蔽,否則此類訂閱會(huì)自動(dòng)續(xù)期。

示例:每月訂閱提供流媒體服務(wù)的 App呐粘。

非續(xù)期訂閱

允許用戶購(gòu)買有時(shí)限性服務(wù)的產(chǎn)品满俗。此 App 內(nèi)購(gòu)買項(xiàng)目的內(nèi)容可以是靜態(tài)的。此類訂閱不會(huì)自動(dòng)續(xù)期作岖。

示例:為期一年的已歸檔文章目錄訂閱唆垃。

用于 App 審核的商品截屏

App 內(nèi)購(gòu)買項(xiàng)目的截屏,即所售項(xiàng)目的示意圖痘儡。例如辕万,如果 App 內(nèi)購(gòu)買項(xiàng)目是一本圖書,您可以提交圖書的截屏沉删。您也可以提交購(gòu)買頁(yè)的截屏渐尿。該截屏僅用于 Apple 審核,不會(huì)在 App Store 中顯示矾瑰。
截屏要求如下:

iOS 至少需要 640 x 920 像素

Apple tvOS 需要 1920 x 1080 像素

macOS 需要 1280 x 800 像素

App 審核圖像上傳后砖茸,可以替換,但無(wú)法移除殴穴。當(dāng)您的 App 內(nèi)購(gòu)買項(xiàng)目處于審核中時(shí)凉夯,您無(wú)法更新截屏货葬。

  • 在首頁(yè)上,點(diǎn)按“我的 App”劲够,然后選擇與該 App 內(nèi)購(gòu)買項(xiàng)目相關(guān)聯(lián)的 App宝惰。
  • 在工具欄中,點(diǎn)按“功能”再沧,然后在左列中點(diǎn)按“App 內(nèi)購(gòu)買項(xiàng)目”。
  • 若要添加 App 內(nèi)購(gòu)買項(xiàng)目尊残,請(qǐng)前往“App 內(nèi)購(gòu)買項(xiàng)目”炒瘸,并點(diǎn)按“添加”按鈕(+)。
  • 選擇“消耗型項(xiàng)目”寝衫、“非消耗型項(xiàng)目”或“非續(xù)訂訂閱”顷扩,并點(diǎn)按“創(chuàng)建”。有關(guān)自動(dòng)續(xù)訂訂閱的信息慰毅,請(qǐng)參見(jiàn)創(chuàng)建自動(dòng)續(xù)期訂閱隘截。
  • 添加參考名稱、產(chǎn)品 ID 和本地化顯示名稱汹胃。
  • 點(diǎn)按“存儲(chǔ)”或“提交以供審核”婶芭。
  • 提交審核前需要上傳購(gòu)買界面截圖,供蘋果審核
  • 在項(xiàng)目中開(kāi)啟In-App Purchase
15755367143317.jpg
  • 提交新的版本
    我看的文章都是創(chuàng)建好內(nèi)購(gòu)項(xiàng)目之后就可能在項(xiàng)目中使用測(cè)試了着饥,當(dāng)時(shí)我的結(jié)果就是無(wú)效productID犀农。綠色框中寫的很明白要重新提交二進(jìn)制文件(.ipa文件),新的版本中添加在步驟3中添加的內(nèi)購(gòu)項(xiàng)目宰掉。
    15755368021179.jpg
  • 注意:最好選擇手動(dòng)發(fā)布呵哨,因?yàn)楸敬翁峤恢皇菫榱俗寗?chuàng)建的內(nèi)購(gòu)項(xiàng)目ID生效,項(xiàng)目中可以沒(méi)有關(guān)于內(nèi)購(gòu)的邏輯代碼

* 沙盒賬號(hào)創(chuàng)建及使用注意事項(xiàng)

① 沙盒賬號(hào)創(chuàng)建

https://appstoreconnect.apple.com/access/testers

image.png

  • 登錄蘋果開(kāi)發(fā)者后臺(tái)--iTunes Connect--用戶和職能--沙箱測(cè)試技術(shù)員轨奄,在這個(gè)界面你可以看到當(dāng)前賬號(hào)已經(jīng)創(chuàng)建好的沙盒賬號(hào)孟害。
    Snip20191205_2.png
  • 點(diǎn)擊“+”進(jìn)行創(chuàng)建
WeChat6429578a0beffd1414cc33a45386f875.png

②注意事項(xiàng)

  • 電子郵件不能是別人已經(jīng)注冊(cè)過(guò)AppleID的郵箱
  • App Store 地區(qū)不要亂選。雖然隨便哪個(gè)地區(qū)都可以用來(lái)測(cè)試(還沒(méi)上線之前app并沒(méi)有地區(qū)之分)挪拟,但是在沙盒測(cè)試的時(shí)候挨务,彈出的購(gòu)買提示框會(huì)根據(jù)當(dāng)前AppleID(沙盒賬號(hào))的地區(qū)顯示語(yǔ)言的。

沙箱賬號(hào)怎么登錄不成功舞丛?

沙箱賬號(hào)是不能直接在App Store進(jìn)行登錄的耘子,只能在點(diǎn)擊了購(gòu)買商品之后,在彈出的登錄框進(jìn)行登錄球切。

驗(yàn)證是否已登錄沙箱測(cè)試賬號(hào):

設(shè)置--iTunes Store與App Store谷誓,頁(yè)面拉到最底部,會(huì)看到沙箱賬戶項(xiàng)會(huì)列出你已登錄的沙箱測(cè)試賬號(hào)吨凑!

③沙盒賬號(hào)使用的前提

  • bundleID別搞錯(cuò)了捍歪,開(kāi)發(fā)者賬號(hào)户辱、證書、bundleID要一致
  • 內(nèi)購(gòu)的商品ID糙臼,價(jià)格等相關(guān)信息已經(jīng)錄入到開(kāi)發(fā)者后臺(tái)了(不然那你買什么)
  • 開(kāi)發(fā)者后臺(tái)已經(jīng)創(chuàng)建好沙盒測(cè)試賬號(hào)了(下面我們會(huì)講如何創(chuàng)建)
  • 你要有一部真機(jī)(iPhone或iPad都行庐镐,別用模擬器就好。而且不能是越獄機(jī))
  • 如果你是第一次在這個(gè)開(kāi)發(fā)者賬號(hào)上集成內(nèi)購(gòu)功能变逃,請(qǐng)先將iTune Connect上的稅務(wù)協(xié)議都填寫好必逆,否則內(nèi)購(gòu)時(shí)會(huì)發(fā)現(xiàn)商品ID無(wú)效。

④沙盒賬號(hào)使用流程

  • 1.在iPhone上安裝測(cè)試包(必須是adhoc簽名證書或者develop簽名證書打的包揽乱,不能是從App Store上下載的)
  • 2.退出iPhone的App Store賬號(hào)(因?yàn)槲覀冃枰褂蒙澈匈~號(hào)登錄)名眉。

操作方法一:打開(kāi)App Store應(yīng)用首頁(yè)滑到最下方--選中AppleID--注銷
操作方法二:設(shè)置--iTunes Store與App Store--選中AppleID--注銷

  • 3.在測(cè)試包里面購(gòu)買商品,系統(tǒng)會(huì)讓你進(jìn)行登錄凰棉,這里我們點(diǎn)擊“使用現(xiàn)有的AppleID”就可以輸入剛才創(chuàng)建好的沙盒測(cè)試賬號(hào)進(jìn)行登錄了
  • 4.點(diǎn)擊購(gòu)買商品之后损拢,成功的話會(huì)出現(xiàn)相應(yīng)提示
  • 5.我們?cè)趇Tunes Connect上創(chuàng)建商品了之后,除了需要填商品ID撒犀,商品名稱福压,商品描述,價(jià)格等之外或舞,還要上傳一張圖片荆姆,圖片就是下面這個(gè)界面。
15755358556541.jpg

flutter_inapp_purchase 支付插件使用

1.下載依賴

# iOS 內(nèi)購(gòu)
flutter_inapp_purchase: ^2.0.5

2.常見(jiàn)用法

2.1初始化配置(initState)

checks if the client can make payments(檢測(cè)App是否能支付)

StreamSubscription _purchaseUpdatedSubscription;
StreamSubscription _purchaseErrorSubscription;
List<IAPItem> _items = [];
List<PurchasedItem> _purchases = [];
Future<void> initPlatformState() async {
   
    // prepare
    var result = await FlutterInappPurchase.instance.initConnection;
    print('result: $result');
    
    // 判斷容器是否加載
    if (!mounted) return;

    // 更新購(gòu)買訂閱消息
    _purchaseUpdatedSubscription =
        FlutterInappPurchase.purchaseUpdated.listen((productItem) {
      print('purchase-updated: $productItem');
    });
    // 購(gòu)買報(bào)錯(cuò)訂閱消息
    _purchaseErrorSubscription =
        FlutterInappPurchase.purchaseError.listen((purchaseError) {
      print('purchase-error: $purchaseError');
    });
  }

2.2結(jié)束支付

await FlutterInappPurchase.instance.endConnection;
  _purchaseUpdatedSubscription.cancel();
  _purchaseUpdatedSubscription = null;
  _purchaseErrorSubscription.cancel();
  _purchaseErrorSubscription = null;
  setState(() {
    this._items = [];
    this._purchases = [];
  });

2.3獲取商品(_getProduct)

final List<String> _productLists = Platform.isAndroid
  ? [
      'android.test.purchased',
      'point_1000',
      '5000_point',
      'android.test.canceled',
    ]
  : ['com.cooni.point1000', 'com.cooni.point5000'];
List<IAPItem> _items = [];
////////////////////////////////////
Future _getProduct() async {
    List<IAPItem> items =
        await FlutterInappPurchase.instance.getProducts(_productLists);
    for (var item in items) {
      print('item==============>${item.toString()}');
      this._items.add(item);
    }

    setState(() {
      this._items = items;
      this._purchases = [];
    });
  }

2.4獲取已購(gòu)買商品(_getPurchases)

getAvailablePurchases
Get all non-consumed purchases 獲取未消費(fèi)的商品

Future _getPurchases() async {
    List<PurchasedItem> items =
        await FlutterInappPurchase.instance.getAvailablePurchases();
    print('_getPurchases${items}');
    for (var item in items) {
      print('getAvailablePurchases======>${item.toString()}');
      this._purchases.add(item);
    }

    setState(() {
      this._items = [];
      this._purchases = items;
    });
  }

2.5.獲取購(gòu)買歷史(getPurchaseHistory)

Future _getPurchaseHistory() async {
    List<PurchasedItem> items =
        await FlutterInappPurchase.instance.getPurchaseHistory();
    print('_getPurchaseHistory${items}');
    for (var item in items) {
      print('${item.toString()}');
      this._purchases.add(item);
    }

    setState(() {
      this._items = [];
      this._purchases = items;
    });
  }

2.6購(gòu)買商品(requestPurchase)

print("---------- Buy Item Button Pressed");
Map<String, dynamic> json = {
'price': '0.01',
'productId': 'com.games.ztyxs.product_point.1'
};
IAPItem item = IAPItem.fromJSON(json);
this._requestPurchase(item);

---------------------------
void _requestPurchase(IAPItem item) {
    FlutterInappPurchase.instance
        .requestPurchase(item.productId ?? 'com.games.ztyxs.product_point.1');
  }

打印信息查詢映凳;

purchase-error: responseCode: null, debugMessage: Invalid product ID., code: E_DEVELOPER_ERROR, message: Invalid product ID.

原因:
沒(méi)有先執(zhí)行g(shù)etProducts胞枕,直接執(zhí)行requestPurchase方法,要先拉取商品列表,再執(zhí)行購(gòu)買操作.

2.7.補(bǔ)充

  • 如果用戶退款魏宽,在recipt字段中會(huì)接收到cancel_data字段取消日期對(duì)于由Apple客戶支持取消的交易腐泻,取消的時(shí)間和日期

iOS 內(nèi)購(gòu)返回商品列表ID為空

問(wèn)題描述;

response.products商品返回列表為空
response.invalidProductIdentifiers無(wú)效產(chǎn)品id有數(shù)據(jù)
解決方法
  • 1.創(chuàng)建的App ID是否啟用了IAP功能队询。
//允許內(nèi)購(gòu)允許iap
if([SKPaymentQueue canMakePayments]){
    [self requestProductData:product];
}else{
    NSLog(@"不允許程序內(nèi)付費(fèi)");
}
  • 2.商品信息是否配置到iTurn Connect派桩,并到達(dá)“準(zhǔn)備提交”狀態(tài).
image.png
  • 3.在iTurn Connect中創(chuàng)建沙盒測(cè)試員,并收取郵件激活蚌斩。之后登錄到測(cè)試用手機(jī)的設(shè)置頁(yè)面中(Store選項(xiàng))铆惑。

  • 4.是否創(chuàng)建相應(yīng)的provisioning profile,并用此簽名App送膳。

  • 5.iTurn Connect后臺(tái)配置完商品信息后员魏,是否等待若干小時(shí)生效。

  • 6.SKProductsRequest請(qǐng)求的商品Id必須和iTurn Connect中配置的一致叠聋。(如:com.test.product.xxx)

  • 7.iTunes Connect中配置的銀行撕阎、稅務(wù)信息是否正確。

  • 8.是否先刪除舊App碌补,再重新編譯生成新的虏束。

漏單等情況預(yù)防與處理方案

1.漏單必須要處理棉饶,玩家花RMB購(gòu)買的東西卻丟失了,是絕對(duì)不能容忍的镇匀。所謂的漏單就是玩家已經(jīng)正常付費(fèi)照藻,卻沒(méi)有拿到該拿的道具。

解決:只要購(gòu)買成功汗侵,便將購(gòu)買記錄(receipt等賬單信息)保存下來(lái)幸缕,然后將賬單信息傳送給我們游戲服務(wù)器,游戲服務(wù)器獲得賬單后晰韵,和蘋果服務(wù)器驗(yàn)證冀值,賬單有效的話,回饋給游戲服務(wù)器處理宫屠,游戲服務(wù)器處理后,返回給游戲客戶端處理滑蚯,處理完畢浪蹂,將本地保存的購(gòu)買記錄刪除。

receipt-data 支付憑證校驗(yàn)

https://developer.apple.com/library/content/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html 官方文檔:向蘋果校驗(yàn)支付憑證

蘋果反饋的狀態(tài)碼

21000 App Store無(wú)法讀取你提供的JSON數(shù)據(jù)
21002 收據(jù)數(shù)據(jù)不符合格式
21003 收據(jù)無(wú)法被驗(yàn)證
21004 你提供的共享密鑰和賬戶的共享密鑰不一致
21005 收據(jù)服務(wù)器當(dāng)前不可用
21006 收據(jù)是有效的告材,但訂閱服務(wù)已經(jīng)過(guò)期坤次。當(dāng)收到這個(gè)信息時(shí),解碼后的收據(jù)信息也包含在返回內(nèi)容中
21007 收據(jù)信息是測(cè)試用(sandbox)斥赋,但卻被發(fā)送到產(chǎn)品環(huán)境中驗(yàn)證 【請(qǐng)求sandbox校驗(yàn)支付憑證】
21008 收據(jù)信息是產(chǎn)品環(huán)境中使用缰猴,但卻被發(fā)送到測(cè)試環(huán)境中驗(yàn)證

被蘋果拒絕:內(nèi)購(gòu)類型問(wèn)題

消耗類型: 例如:金幣、道具等疤剑。
非續(xù)訂訂閱: non-renewable subscription 例如:VIP

注意

您的首個(gè) App 內(nèi)購(gòu)買項(xiàng)目必須以新的 App 版本提交滑绒。請(qǐng)創(chuàng)建您的 App 內(nèi)購(gòu)買項(xiàng)目,然后前往 App 的“App Store”頁(yè)隘膘,從“App 內(nèi)購(gòu)買項(xiàng)目”中進(jìn)行選擇疑故,點(diǎn)按“提交”。 了解更多

在上傳二進(jìn)制文件并提交首個(gè) App 內(nèi)購(gòu)買項(xiàng)目以供審核后弯菊,您可以使用下表提交其他 App 內(nèi)購(gòu)買項(xiàng)目纵势。

參考

唐巧-iOS應(yīng)用內(nèi)付費(fèi)(IAP)開(kāi)發(fā)步驟列表

未完~待續(xù)

iOS內(nèi)購(gòu)問(wèn)題總結(jié)

1.沙盒測(cè)試賬號(hào)在支付成功后,再次購(gòu)買相同的商品,會(huì)提示“您已購(gòu)買此App內(nèi)購(gòu)買項(xiàng)目。此項(xiàng)目將免費(fèi)恢復(fù)管钳∏仗”

image.png

問(wèn)題分析

當(dāng)使用內(nèi)購(gòu)購(gòu)買過(guò)商品之后沒(méi)有把這個(gè)交易關(guān)閉,所以再次去購(gòu)買商品后就會(huì)調(diào)用以前已經(jīng)購(gòu)買成功的交易去購(gòu)買因?yàn)橐呀?jīng)購(gòu)買過(guò)才漆,才會(huì)有這個(gè)提示

解決方法

  • 使用[[SKPaymentQueue defaultQueue] addPayment:payment];這個(gè)方法進(jìn)行支付請(qǐng)求后牛曹,因?yàn)槲覀円呀?jīng)把支付所需要的信息都添加到蘋果的支付隊(duì)列,蘋果會(huì)自動(dòng)完成后續(xù)的購(gòu)買請(qǐng)求
  • 用戶購(gòu)買成功或者點(diǎn)擊取消購(gòu)買的后會(huì)回調(diào)
// 該方法返回響應(yīng)的結(jié)果信息
- (void)paymentQueue:(SKPaymentQueue )queue updatedTransactions:(NSArray )transaction;
  • 在該方法內(nèi)除了得到響應(yīng)的支付信息編寫自身的業(yè)務(wù)的代碼外還要記得調(diào)用[[SKPaymentQueue defaultQueue] finishTransaction:transaction];方法通知蘋果的支付隊(duì)列該交易已經(jīng)完成醇滥,否者就會(huì)調(diào)用已經(jīng)購(gòu)買成功的支付隊(duì)列躏仇,就會(huì)出現(xiàn)您以購(gòu)買過(guò)此APP內(nèi)購(gòu)項(xiàng)目恋脚,此項(xiàng)目將免費(fèi)恢復(fù)這句提示。
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions{
    NSLog(@"調(diào)用了幾次這個(gè)方法焰手?");
    SKPaymentTransaction *transaction = transactions.lastObject;
    switch (transaction.transactionState) {
        case SKPaymentTransactionStatePurchased: {
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];//記得關(guān)閉交易事件

            NSLog(@"購(gòu)買完成,向自己的服務(wù)器驗(yàn)證 ---- %@", transaction.payment.applicationUsername);
            NSData *data = [NSData dataWithContentsOfFile:[[[NSBundle mainBundle] appStoreReceiptURL] path]];
            NSString *receipt = [data base64EncodedStringWithOptions:0];
//            [self buySuccessWithReceipt:receipt transaction:transaction];
        }
            break;
        case SKPaymentTransactionStateFailed: {
            NSLog(@"交易失敗");
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
        }
            break;
        case SKPaymentTransactionStateRestored: {
            NSLog(@"已經(jīng)購(gòu)買過(guò)該商品");
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
        }
            break;
        case SKPaymentTransactionStatePurchasing: {
            NSLog(@"商品添加進(jìn)列表");
        }
            break;
        default: {
        }
            break;
    }
}
  • 在買次購(gòu)買之前檢測(cè)是否有未完成的交易如果有就關(guān)閉糟描。
NSArray* transactions = [SKPaymentQueue defaultQueue].transactions;
   if (transactions.count > 0) {
       //檢測(cè)是否有未完成的交易
       SKPaymentTransaction* transaction = [transactions firstObject];
       if (transaction.transactionState == SKPaymentTransactionStatePurchased) {
           [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
           return;
       }  
   }

2.iOS后臺(tái)添加內(nèi)購(gòu)項(xiàng)目,提交顯示元數(shù)據(jù)丟失

原因:添加內(nèi)購(gòu)項(xiàng)目時(shí)书妻,信息填寫不完整船响,app審核圖像未上傳

處理方法:上傳app審核圖片(合適的尺寸),點(diǎn)擊提交躲履,狀態(tài)改為正在準(zhǔn)備審核中见间。

3.您已經(jīng)購(gòu)買了此項(xiàng)目,您想免費(fèi)再獲取一次嗎

這個(gè)是內(nèi)購(gòu)選擇類型不匹配原因?qū)е隆?/p>

  • 非消耗型就是消耗一次后在該appid下都能使用工猜。
  • 消耗型比如一些直播平臺(tái)的貨幣 使用完以后可以在充值米诉。

4.Purchase二次驗(yàn)證

購(gòu)買成功之后,Apple會(huì)返回以下四個(gè)數(shù)據(jù)給應(yīng)用

  • 產(chǎn)品標(biāo)識(shí)符:
  • 交易狀態(tài): state
  • Receipt:很長(zhǎng)的一段字符串篷帅,大概49行史侣,作為二次驗(yàn)證的重要依據(jù)
  • 交易標(biāo)識(shí)符: transaction Identifier 我們需要把Receipt發(fā)送給蘋果的蘋果的服務(wù)器驗(yàn)證,用戶的購(gòu)買信息是否真實(shí)

交易狀態(tài)

  • Purchased 購(gòu)買成功
  • Restored 恢復(fù)購(gòu)買
  • Failed 失敗
  • Deferred 等待確認(rèn)魏身,兒童模式需要詢問(wèn)家長(zhǎng)同意

蘋果返回狀態(tài)碼

Reference

  • 21000 App Store不能讀取你提供的JSON對(duì)象
  • 21002 receipt-data域的數(shù)據(jù)有問(wèn)題
  • 21003 receipt無(wú)法通過(guò)驗(yàn)證
  • 21004 提供的shared secret不匹配你賬號(hào)中的shared secret
  • 21005 receipt服務(wù)器當(dāng)前不可用
  • 21006 receipt合法惊橱,但是訂閱已過(guò)期。服務(wù)器接收到這個(gè)狀態(tài)碼時(shí)箭昵,receipt數(shù)據(jù)仍然會(huì)解碼并一起發(fā)送
  • 21007 receipt是Sandbox receipt税朴,但卻發(fā)送至生產(chǎn)系統(tǒng)的驗(yàn)證服務(wù)
  • 21008 receipt是生產(chǎn)receipt,但卻發(fā)送至Sandbox環(huán)境的驗(yàn)證服務(wù)

5.蘋果后臺(tái)添加內(nèi)購(gòu)商品報(bào)問(wèn)題

Review the updated Paid Applications Schedule.

image.png

解決辦法

  • 先打開(kāi) https://itunesconnect.apple.com 首頁(yè)

  • 然后找到這個(gè)協(xié)議的位置


    image.png
  • 點(diǎn)進(jìn)去之后家制,如下所示


    image.png
  • 右上角有個(gè)Request按鈕正林,好了,點(diǎn)擊這個(gè)按鈕颤殴,然后點(diǎn)擊Submit提交


    image.png
  • 同意之后就OK了卓囚,然后到首頁(yè)重新添加商品可以看到提醒消息已經(jīng)消失了

5.iOS內(nèi)購(gòu)匿名購(gòu)買-內(nèi)購(gòu)游客模式解決方案

游客身份解決方案:即不登錄也要能購(gòu)買

1)服務(wù)器端做一個(gè)蘋果審核機(jī)制,審核期間游客身份可以進(jìn)行一切行為诅病,一旦審核通過(guò)哪亿,修改服務(wù)端即可達(dá)到強(qiáng)制用戶登錄進(jìn)行內(nèi)購(gòu)買的目的(這個(gè)有點(diǎn)。贤笆。蝇棉。)

2)游客可以進(jìn)行內(nèi)購(gòu)買,購(gòu)買時(shí)以設(shè)備UUID為準(zhǔn)芥永,生成一個(gè)游客賬號(hào)篡殷,將購(gòu)買信息保存在服務(wù)器和本地,當(dāng)用戶登錄正式賬戶后判斷此設(shè)備是否進(jìn)行過(guò)內(nèi)購(gòu)埋涧,有的話提示用戶將游客身份購(gòu)買的權(quán)益與現(xiàn)有賬號(hào)綁定板辽,如果綁定奇瘦,游客權(quán)益則遷移到正式賬戶,如果不遷移劲弦,則游客身份和正是賬戶是兩個(gè)獨(dú)立賬戶耳标,正式賬戶不享有游客身份的權(quán)益(我用的這個(gè))

內(nèi)購(gòu)游客模式解決方案
iOS內(nèi)購(gòu)規(guī)則

6.審核注意事項(xiàng)

  • 1.沙盒/正式環(huán)境:后臺(tái)提供開(kāi)關(guān)控制
  • 2.內(nèi)購(gòu)支付建議添加開(kāi)關(guān),因?yàn)榻刂辽暇€前審核模式只能通過(guò)沙盒測(cè)試邑跪,上線后才能看到正式功能的支付次坡。所以建議手動(dòng)發(fā)布,發(fā)布前先關(guān)閉開(kāi)關(guān)画畅,待測(cè)試完成后再打開(kāi)顯示支付開(kāi)關(guān)砸琅。
  • 3.支付流程
    • ①.先下單獲取訂單號(hào)
    • ②.獲取支付參數(shù)(商品ID)
    • ③.發(fā)起支付,到支付回調(diào)
    • ④.通知上報(bào)transactionReceiptServer【此處Server驗(yàn)證較慢】
    • ⑤調(diào)用訂單狀態(tài)查詢(輪詢)轴踱,添加友好提示
      問(wèn)題描述:
  • 4.支付收據(jù)驗(yàn)證比較慢
  • 先快速通知症脂,不做業(yè)務(wù)處理只上報(bào):之后調(diào)取查詢訂單狀態(tài)接口
  • 添加重試機(jī)制(比如5次或者5秒)
  • 5.漏單處理(斷網(wǎng),Server未收到支付憑證淫僻,Server無(wú)返回)

支付成功回調(diào)后诱篷,存儲(chǔ)訂單號(hào)和支付憑證,Server驗(yàn)證成功后remove嘁傀,其他情況(例如:Server5秒無(wú)返回)發(fā)送事件通知(上報(bào)給Server),然后直接走訂單查詢视粮,并且下次啟動(dòng)App時(shí)上報(bào)給Server细办。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蕾殴,隨后出現(xiàn)的幾起案子笑撞,更是在濱河造成了極大的恐慌,老刑警劉巖钓觉,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茴肥,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡荡灾,警方通過(guò)查閱死者的電腦和手機(jī)瓤狐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)批幌,“玉大人础锐,你說(shuō)我怎么就攤上這事∮担” “怎么了皆警?”我有些...
    開(kāi)封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)截粗。 經(jīng)常有香客問(wèn)我信姓,道長(zhǎng)鸵隧,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任意推,我火速辦了婚禮豆瘫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘左痢。我一直安慰自己靡羡,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布俊性。 她就那樣靜靜地躺著略步,像睡著了一般。 火紅的嫁衣襯著肌膚如雪定页。 梳的紋絲不亂的頭發(fā)上趟薄,一...
    開(kāi)封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天,我揣著相機(jī)與錄音典徊,去河邊找鬼杭煎。 笑死,一個(gè)胖子當(dāng)著我的面吹牛卒落,可吹牛的內(nèi)容都是我干的羡铲。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼儡毕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼也切!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起腰湾,我...
    開(kāi)封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤雷恃,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后费坊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體倒槐,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年附井,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了讨越。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡永毅,死狀恐怖谎痢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情卷雕,我是刑警寧澤节猿,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響滨嘱,放射性物質(zhì)發(fā)生泄漏峰鄙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一太雨、第九天 我趴在偏房一處隱蔽的房頂上張望吟榴。 院中可真熱鬧,春花似錦囊扳、人聲如沸吩翻。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)狭瞎。三九已至,卻和暖如春搏予,著一層夾襖步出監(jiān)牢的瞬間熊锭,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工雪侥, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留碗殷,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓速缨,卻偏偏與公主長(zhǎng)得像锌妻,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子旬牲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容