日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

Cocos2d-x使用iOS游戏内付费IAP(C++篇)

發布時間:2025/6/15 c/c++ 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Cocos2d-x使用iOS游戏内付费IAP(C++篇) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

source file url: http://www.tairan.com/archives/5515


Cocos2d-x使用iOS游戲內付費IAP(C++篇)

前期準備

設備與賬號

在開始編碼之前我們需要準備測試環境。

  • IAP只能真機測試,準備一臺iOS設備是必須的。

  • 真機調試與IAP沙盒(SandBox)測試需要IDP(IOS Developer Program)賬號。

  • MAC開發機一臺.

本文不涉及IDP申請流程和真機調試設置,重點解析IAP相關的設置。

新建IAP付費條目

新建app ID

登錄iOS Dev Center, 點擊“Certificates, Identifiers & Profiles->Identifiers->App IDs”,切換到App IDs界面,再點擊“+”新建用于測試的AppID,默認設置”In-App-Purchase”已開啟,如下圖所示:

創建發布程序

無IAP的iOS App的真機測試是不需要下面的步驟的,而有IAP的則不同,需要先建立發布程序,設置好IAP信息才能測試相關的功能。

登錄iTunes Connect, 切換到“Manage Your Apps ”,點擊“Add New App”新建一個待發布程序, Bundle ID選擇剛才創建的App ID。

接下來的程序信息界面可隨意填寫,截圖可使用符合大小要求的假圖,先保證能創建成功、可測試,等到需要正式提交審核的時候再修改成最終截圖。

為發布程序新建IAP付費項目

點擊剛才創建完成的App進入“App Information”界面,再點擊“Manager In-App Purchases”進入IAP管理界面。

我們點擊左上角的“Create New”來新建一個IAP付費項目,接下來的Select Type界面會有5中IAP類型可供選擇。如圖:

前兩種是主類型:

游戲中使用得最多的就是“購買游戲幣”了,我們這里只關注Consumable類型,可多次購買。

更多其他類型的信息可查詢StoreKitGuide.pdf。

選擇“Consumable”,進入詳細信息設置界面。

Product ID全服唯一,起個自己覺得舒服的名稱, 一般建議:Bundle ID + IAP description.

Language需要至少一種,選擇“English”,方便測試。

當完成IAP付費項目的新建后,回到“Manager In-App Purchases”界面,可以看到下面的信息。

你可以隨時修改已存在的項目,即使在游戲上線后也能修改(Product ID除外),這樣可以在不發布新程序的情況下,做一些促銷活動。

新建IAP付費測試賬號

IAP的測試至關重要,你肯定不想給錢測試,被蘋果扣掉30%。蘋果的SandBox提供了一整套測試相關的服務。依然在iTunes Connect中設置。

點擊“Manage Users->Test User”進入測試賬號添加界面,點擊左上交的“Add New User”,填入Email等信息。

Note:Email地址必須是未注冊過Apple ID的email,注冊過的無法使用。
Select iTunes Store必須選“United States”,錯選為中國區不能測試不要怪我沒提醒。

到此,前期準備工作都已完成,你也許需要等待幾個小時讓iTunes Connect設置生效,以便代碼能獲取到IAP信息,接下來我們正式進入代碼階段。

IAP的C++封裝

新建項目

使用tool下的create_project.py創建項目,注意project ID 必須填寫為上面我們申請的APP ID,這樣真機調試才能取到我們設置的IAP信息。

C++開發的游戲,付費點直接使用Object-c的IAP接口會有諸多不便,在StoreKit基礎上再封裝一層C++接口會方便很多。新建 IOSiAP.h和IOSiAP.mm兩個文件,加入到Xcode工程。mm文件為C++和Object-c混編文件,可在里面實現兩種語言的互相調用。

IAP付費流程與接口抽象

如下圖所示:

首先,IAP付費首先需要客戶端發起請求,獲取服務器上的IAP條目信息。之所用需要這個步驟,是因為iTunes Connect后臺可以修改付費條目的價格、說明等信息。

然后,客戶端根據獲取到的IAP條目信息展示UI,當用戶點擊支付后發起payment請求。

最后,等待payment的回調響應。如果成功,游戲幣增加;如果失敗,UI提示給用戶。

從付費流程,我們可以看出需要3個接口:

  • 發起products information請求,并等待數據回來。

  • 獲取每個product的information。

  • 請求購買product,并等待響應。

  • 具體在IOSiAP.h中的抽象如下:

    class?IOSiAP{public:IOSiAP();~IOSiAP();void?requestProducts(std::vector?<std::string>?&productIdentifiers);IOSProduct?*iOSProductByIdentifier(std::string?&identifier);void?paymentWithProduct(IOSProduct?*iosProduct,?int?quantity?=?1);IOSiAPDelegate?*delegate;//?===??internal?use?for?object-c?class?===void?*skProducts;//?object-c?SKProductvoid?*skTransactionObserver;//?object-c?TransactionObserverstd::vector<IOSProduct?*>?iOSProducts;};

    其中的identifier是IAP付費項目的“Product ID”。

    IOSProduct是一個簡單的數據類,存放Product information。

    class?IOSProduct{public:std::string?productIdentifier;std::string?localizedTitle;std::string?localizedDescription;std::string?localizedPrice;//?has?be?localed,?just?display?it?on?UI.bool?isValid;int?index;//internal?use?:?index?of?skProducts};

    IOSiAPDelegate是消息回調通知類,由具體的調用者來實現。

    typedef?enum?{IOSIAP_PAYMENT_PURCHASING,//?just?notify,?UI?do?nothingIOSIAP_PAYMENT_PURCHAED,//?need?unlock?App?FunctionalityIOSIAP_PAYMENT_FAILED,//?remove?waiting?on?UI,?tall?user?payment?was?failedIOSIAP_PAYMENT_RESTORED,//?need?unlock?App?Functionality,?consumble?payment?No?need?to?care?about?this.IOSIAP_PAYMENT_REMOVED,//?remove?waiting?on?UI}?IOSiAPPaymentEvent;class?IOSiAPDelegate{public:virtual?~IOSiAPDelegate()?{}//?for?requestProductvirtual?void?onRequestProductsFinish(void)?=?0;virtual?void?onRequestProductsError(int?code)?=?0;//?for?paymentvirtual?void?onPaymentEvent(std::string?&identifier,?IOSiAPPaymentEvent?event)?=?0;};

    其中的前兩個消息是requestProducts()的消息回調,最后一個是payment的回調。而payment又分5種狀態。

    requestProducts的實現

    首先我們要包含StoreKit的頭文件

    #import?<StoreKit/StoreKit.h>

    然后,需要把StoreKit.framework加入到工程里面,如下圖:

    requestProducts的具體實現如下:

    void?IOSiAP::requestProducts(std::vector?<std::string>?&productIdentifiers){//?1.NSMutableSet?*set?=?[NSMutableSet?setWithCapacity:productIdentifiers.size()];std::vector?<std::string>::iterator?iterator;for?(iterator?=?productIdentifiers.begin();?iterator?!=?productIdentifiers.end();?iterator++)?{[set?addObject:[NSString?stringWithUTF8String:(*iterator).c_str()]];}//?2.SKProductsRequest?*productsRequest?=?[[SKProductsRequest?alloc]?initWithProductIdentifiers:set];//?3.iAPProductsRequestDelegate?*delegate?=?[[iAPProductsRequestDelegate?alloc]?init];delegate.iosiap?=?this;productsRequest.delegate?=?delegate;//?4.[productsRequest?start];}

    要點如下:

  • 轉換C++的數組為Object-c的數組。

  • 新建一個SKProductsRequest,用product identifiers來初始化。

  • iAPProductsRequestDelegate是內部抽象的一個橋接Object-c類,用來接受StoreKit的回調,并轉換到C++的回調。

  • 一切準備就緒,啟動request。

  • 下面我們看下iAPProductsRequestDelegate是如何橋接的。
    聲明protocol:SKProductsRequestDelegate,
    在interface里面定義了一個iosiap,引用到C++對象實例。

    @interface?iAPProductsRequestDelegate?:?NSObject<SKProductsRequestDelegate>@property?(nonatomic,?assign)?IOSiAP?*iosiap;@end

    實現SKProductsRequestDelegate的協議接口。

    @implementation?iAPProductsRequestDelegate//?1.-?(void)productsRequest:(SKProductsRequest?*)requestdidReceiveResponse:(SKProductsResponse?*)response{//?release?oldif?(_iosiap->skProducts)?{[(NSArray?*)(_iosiap->skProducts)?release];}//?record?new?product_iosiap->skProducts?=?[response.products?retain];for?(int?index?=?0;?index?<?[response.products?count];?index++)?{SKProduct?*skProduct?=?[response.products?objectAtIndex:index];//?check?is?validbool?isValid?=?true;for?(NSString?*invalidIdentifier?in?response.invalidProductIdentifiers)?{NSLog(@"invalidIdentifier:%@",?invalidIdentifier);if?([skProduct.productIdentifier?isEqualToString:invalidIdentifier])?{isValid?=?false;break;}}IOSProduct?*iosProduct?=?new?IOSProduct;iosProduct->productIdentifier?=?std::string([skProduct.productIdentifier?UTF8String]);iosProduct->localizedTitle?=?std::string([skProduct.localizedTitle?UTF8String]);iosProduct->localizedDescription?=?std::string([skProduct.localizedDescription?UTF8String]);//?locale?price?to?stringNSNumberFormatter?*formatter?=?[[NSNumberFormatter?alloc]?init];[formatter?setFormatterBehavior:NSNumberFormatterBehavior10_4];[formatter?setNumberStyle:NSNumberFormatterCurrencyStyle];[formatter?setLocale:skProduct.priceLocale];NSString?*priceStr?=?[formatter?stringFromNumber:skProduct.price];[formatter?release];iosProduct->localizedPrice?=?std::string([priceStr?UTF8String]);iosProduct->index?=?index;iosProduct->isValid?=?isValid;_iosiap->iOSProducts.push_back(iosProduct);}}//?2.-?(void)requestDidFinish:(SKRequest?*)request{_iosiap->delegate->onRequestProductsFinish();[request.delegate?release];[request?release];}//?3.-?(void)request:(SKRequest?*)request?didFailWithError:(NSError?*)error{NSLog(@"%@",?error);_iosiap->delegate->onRequestProductsError([error?code]);}@end

    解析如下:

  • 收到響應,解析出每個product information,再轉換為C++數據存儲起來。

  • 請求結束通知。

  • 請求失敗通知,2和3不會同時出現。

  • iOSProductByIdentifier的實現

    iOSProductByIdentifier的實現簡單很多,在上一個步驟中我們已存儲了請求回來的數據,現在只需要查找出對應的數據返回即可。

    IOSProduct?*IOSiAP::iOSProductByIdentifier(std::string?&identifier){std::vector?<IOSProduct?*>::iterator?iterator;for?(iterator?=?iOSProducts.begin();?iterator?!=?iOSProducts.end();?iterator++)?{IOSProduct?*iosProduct?=?*iterator;if?(iosProduct->productIdentifier?==?identifier)?{return?iosProduct;}}return?nullptr;}

    paymentWithProduct的實現

    paymentWithProduct有兩個參數,第一個參數是由iOSProductByIdentifier獲取的IOSProduct實例,第二個參數是購買數量,本文只涉及Consumable類型的IAP,所以需要這個參數。

    void?IOSiAP::paymentWithProduct(IOSProduct?*iosProduct,?int?quantity){SKProduct?*skProduct?=?[(NSArray?*)(skProducts)?objectAtIndex:iosProduct->index];SKMutablePayment?*payment?=?[SKMutablePayment?paymentWithProduct:skProduct];payment.quantity?=?quantity;[[SKPaymentQueue?defaultQueue]?addPayment:payment];}

    SKMutablePayment是異步請求,和requestProducts一樣自定義了一個叫iAPTransactionObserver的Object-c類來實現橋接。

    @implementation?iAPTransactionObserver//?1.-?(void)paymentQueue:(SKPaymentQueue?*)queue?updatedTransactions:(NSArray?*)transactions{for?(SKPaymentTransaction?*transaction?in?transactions)?{std::string?identifier([transaction.payment.productIdentifier?UTF8String]);IOSiAPPaymentEvent?event;switch?(transaction.transactionState)?{case?SKPaymentTransactionStatePurchasing:event?=?IOSIAP_PAYMENT_PURCHASING;return;case?SKPaymentTransactionStatePurchased:event?=?IOSIAP_PAYMENT_PURCHAED;break;case?SKPaymentTransactionStateFailed:event?=?IOSIAP_PAYMENT_FAILED;NSLog(@"==ios?payment?error:%@",?transaction.error);break;case?SKPaymentTransactionStateRestored://?NOTE:?consumble?payment?is?NOT?restorableevent?=?IOSIAP_PAYMENT_RESTORED;break;}_iosiap->delegate->onPaymentEvent(identifier,?event,?transaction.payment.quantity);//?2.if?(event?!=?IOSIAP_PAYMENT_PURCHASING)?{[[SKPaymentQueue?defaultQueue]?finishTransaction:?transaction];}}}//?3.-?(void)paymentQueue:(SKPaymentQueue?*)queue?removedTransactions:(NSArray?*)transactions{for?(SKPaymentTransaction?*transaction?in?transactions)?{std::string?identifier([transaction.payment.productIdentifier?UTF8String]);_iosiap->delegate->onPaymentEvent(identifier,?IOSIAP_PAYMENT_REMOVED,?transaction.payment.quantity);}}@end

    要點如下:

  • payment的狀態更新,這里有四個狀態,我們一一做了映射。

    • IOSIAP_PAYMENT_PURCHASING不需要做任何處理。

    • IOSIAP_PAYMENT_PURCHAED這個消息里面,游戲需要把金幣交付給玩家。

    • IOSIAP_PAYMENT_FAILED則可能需要UI提示錯誤信息。

    • IOSIAP_PAYMENT_RESTORED,consumble類型的IAP是沒有這個消息的。

    除了IOSIAP_PAYMENT_PURCHASING消息,其他消息在通知完上層游戲邏輯后,都需要finishTransaction處理。removedTransactions實則是由finishTransaction觸發的回調,我們依然要把這個消息映射到上層。

    測試

    不少只使用C++的用戶反饋不知道如何使用接口,這里給一個偽代碼供參考

    首先要讓調用的類繼承IOSiAPDelegate,重寫三個消息函數。
    IOSiAP的初始化很簡單,記得把delegate設置為調用IOSiAP_Bridge。其他邏輯參考偽代碼注釋。

    class?IOSiAP_Bridge?:?public?IOSiAPDelegate{public:IOSiAP_Bridge();~IOSiAP_Bridge();IOSiAP?*iap;virtual?void?onRequestProductsFinish(void);virtual?void?onRequestProductsError(int?code);virtual?void?onPaymentEvent(std::string?&identifier,?IOSiAPPaymentEvent?event,?int?quantity);};IOSiAP_Bridge::IOSiAP_Bridge(){iap?=?new?IOSiAP();iap->delegate?=?this;}IOSiAP_Bridge::~IOSiAP_Bridge(){delete?iap;}IOSiAP_Bridge::?requestProducts(){iap->requestProducts(identifiers);}void?IOSiAP_Bridge::onRequestProductsFinish(void){//必須在onRequestProductsFinish后才能去請求iAP產品數據。IOSProduct?*product?=?iap->iOSProductByIdentifier(identifier);//?然后可以發起付款請求。iap->paymentWithProduct(product,?quantity);}void?IOSiAP_Bridge::onRequestProductsError(int?code){//這里requestProducts出錯了,不能進行后面的所有操作。}void?IOSiAP_Bridge::onPaymentEvent(std::string?&identifier,?IOSiAPPaymentEvent?event,?int?quantity){if?(event?==?IOSIAP_PAYMENT_PURCHAED)?{//付款成功了,可以吧金幣發給玩家了。}//其他狀態依情況處理掉。}

    Where to Go

    你可以在這里獲取到本文的源碼,把工程放到Cocos2d-x 3.0 beta下的projects目錄下即可運行使用。

    這里沒有提及接口測試,我們將在下一章JSB篇中講解。


    總結

    以上是生活随笔為你收集整理的Cocos2d-x使用iOS游戏内付费IAP(C++篇)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 日韩精品极品视频免费观看 | 亚洲免费二区 | 中文字幕精品三区 | 午夜黄色 | 在线观看日本网站 | 亚洲美女啪啪 | 日韩视频在线观看一区二区三区 | 黄色大片免费观看视频 | 成人小视频在线观看 | 1000部多毛熟女毛茸茸 | 成人娱乐网 | 中文在线a在线 | 美女搡bbb又爽又猛又黄www | 日韩婷婷 | 在线欧美成人 | 91秘密入口 | 国产精品自偷自拍 | 在哪里可以看黄色片 | 国产视频久久久久久久 | 琪琪色av | 成人三级黄色 | 综合久久久久久久久久久 | 一区二区三区啪啪啪 | 免费在线视频你懂的 | 国产91九色 | 亚洲美女av在线 | 国色天香一区二区 | 色美av | 国产二页 | 四虎影视永久 | 成年人免费网站在线观看 | 欧美黄色大片免费观看 | 久久久久久亚洲中文字幕无码 | 免费看一区二区三区 | 成人做爰66片免费看网站 | 国产精品1000| 西西久久| 国产www精品 | 亚洲熟妇无码一区二区三区导航 | 人人草在线 | av射进来| 午夜8888| 五月婷中文字幕 | 亚洲va久久久噜噜噜无码久久 | 91精品系列 | 撸大师av| 欧美一区二区在线观看 | 日本黄色大片网站 | 香蕉视频91 | 毛片毛片毛片毛片毛片毛片 | 日韩av综合网 | 久久久久久久网 | 91污在线观看 | 国产亚洲精品久久久久动 | 国产精品久久久久久久久夜色 | 欧美成人精品一区二区男人看 | 国产福利视频一区二区 | 午夜啪啪网站 | 韩国三级与黑人 | 明里柚番号 | 涩涩涩av| 国产欧美日韩在线 | 亚洲男人天堂2018 | 国产尤物av尤物在线看 | 中国美女囗交视频 | 一区三区视频在线观看 | 尹人成人网 | 孕期1ⅴ1高h | 一区精品在线 | www天堂网 | 欧美在线播放一区二区 | 五月婷婷av| 日本在线一级片 | 国产精品色婷婷99久久精品 | 女女互磨互喷水高潮les呻吟 | 日韩欧美亚洲在线 | 蜜臀久久99精品久久久久久 | 在线黄色免费网站 | 一级片在线观看视频 | 欧美国产二区 | 欧美人与性动交α欧美精品 | 亚洲在线天堂 | 久久久精品美女 | 日本一区二区三区免费在线观看 | 九九少妇 | xx99小雪 | 超碰个人在线 | 一二三四国产精品 | 国产精品成人午夜视频 | 四虎成人免费视频 | 丁香久久久 | 无码无套少妇毛多18pxxxx | 麻豆一区二区三区精品视频 | 久久亚洲网 | 97人妻人人澡人人爽人人精品 | 精品国产一区二区在线观看 | 四虎最新网址在线观看 | 中文字幕一区二区三区在线不卡 | 亚洲色图在线观看 |