1. 程式人生 > >Adobe Gaming SDK 內建ProductStore詳解

Adobe Gaming SDK 內建ProductStore詳解

Adobe在去年歲末釋出了Gaming Develop Tool,其中一個內容是蘋果內支付的原生擴充套件ProductStore。我在自己的專案裡反覆試驗了這個ANE,所以等了很久才寫這篇教程,旨在幫助初學者理解蘋果應用內支付的一些流程,以及學會使用這個ANE的幾個關鍵API。

本文適合的人群:
使用Adobe AIR進行iOS遊戲和應用開發的ActionScript 3開發者。
有應用內支付需求的開發者
會使用ADT打包iPA

閱讀本文不需要具備的知識:
Objective C

—————————————————-
下載安裝ProductStore
—————————————————-

用你的Adobe帳號登陸Adobe創意雲(Creative Cloud),然後在下面的頁面下載Adobe Gaming SDK:



下載安裝後,開啟安裝路徑下的Native Extensions(ANEs)資料夾,可以看到Adobe官方提供的免費ANE。其中Product Store.ane是內支付擴充套件,把它拷貝到你的專案下的一個合理路徑,然後用開發工具引用它,就可以進行開發了。



小貼士:如果你的開發工具不支援直接引用ANE檔案,如Flash Builder 4.6以前的版本。可以把ANE副檔名修改成SWC後再引用。

——————————————————–
應用內支付的工作原理
——————————————————–

如果要使用ProductStore,就必須要先了解蘋果內支付流程是怎樣的。下面摘自蘋果開發者文件的兩個流程圖,很好解釋了這個問題:

本地應用內支付流程圖


上圖適用於非消費型商品,也就是隻需使用者一次購買終身享用的那種;下圖是消費型商品,一般情況下需要開發者自己架設伺服器來儲存使用者的購買記錄。

有第三方伺服器介入的支付流程圖



但無論是哪種架構,內支付的基本流程如下:
請求商品資訊 -> 購買商品 -> 驗證收據 -> 購買成功

由此可見,應用程式需要做以下5件事情:

1, 請求商品列表和詳細資訊(提交商品ID,處理結果)
2, 展示商品列表和詳細資訊(使用者介面,提供購買按鈕)
3, 處理使用者購買請求 ( 提交商品ID,處理結果)
4, 驗證收據(提交收據,處理結果)
5, 使用者反饋

針對這些工作,ProductStore給開發者提供了完整的API
——————————————————–
ProductStore的API


——————————————————–
在寫內支付第一行程式碼之前,一定要到上建立應用內支付商品,否則商品ID無效,應用也就無法測試。

準備妥當後,再開啟安裝目錄下的Doc資料夾,可以看到API文件,可惜這份文件內容還十分初淺,連英文描述都很少,更別提中文了。好在內支付的API並不多,所以我們只要關注這幾個類:

ProductStore
ProductEvent
Product
Transaction
TransactionEvent

朋友們只要注意以下幾點,就能保證你的內支付程式運作無誤。
————————————————————–
(一)在應用程式執行後,儘早建立一個ProductStore的Singleton例項,並保持它存在於整個應用的生命週期內。
————————————————————–

1

productStore = new ProductStore();

給productStore新增以下的事件偵聽:
ProductEvent.PRODUCT_DETAILS_SUCCESS :商品列表獲取成功ProductEvent.PRODUCT_DETAILS_FAIL:商品列表獲取失敗
TransactionEvent.PURCHASE_TRANSACTION_SUCCESS:交易成功 TransactionEvent.PURCHASE_TRANSACTION_CANCEL:交易取消
TransactionEvent.PURCHASE_TRANSACTION_FAIL:交易失敗 TransactionEvent.FINISH_TRANSACTION_SUCCESS:結束交易成功
TransactionEvent.RESTORE_TRANSACTION_SUCCESS:恢復交易成功
TransactionEvent.RESTORE_TRANSACTION_FAIL:恢復交易失敗
TransactionEvent.RESTORE_TRANSACTION_COMPLETE:恢復交易完成

具體含義在下面講解。
————————————————————–
(二)儘早請求商品資訊,並儲存在記憶體中
————————————————————–

使用下面的API可以使用商品ID來請求商品的詳細資訊:

1

2

var productsArray:Array = ["package1","package2","package3"]
            productStore.requestProductsDetails(productsArray);

如果productsArray裡定義的每一個商品ID都在成功設定,並且給productStrore添加了ProductEvent.PRODUCT_DETAILS_SUCCESS偵聽,那麼就可以在偵聽器裡成功獲取這些商品的詳細資訊。

private function onProductsReceived(e:ProductEvent):void{
      products = e.products
      for each(var p:Product in products){
              //這裡獲取每一個商品的資訊
      }
}

商品資訊被ANE封裝在一個Product類中,屬性如下:
identifier: 商品ID
title:商品名稱
description:描述文字
price:商品價格(已經摺合為使用者商店的本地貨幣單位)
priceLocale:商品價格本地化資訊(用來獲取貨幣單位的顯示),如果你的應用需要在中國玩家裝置上顯示”CNY 6″ , 但是在美國玩家那兒顯示”USD 0.99″,那麼你就需要用到這個屬性。(別忘了有些國家的貨幣數值可能比較大,比如島國,所以要給你的文字框留足位置)

————————————————————–
(三)有關交易的觸發和維護
————————————————————–

呼叫下面的API可以觸發購買的交易請求:

1

productStore.makePurchaseTransaction("package1", 1);

上面程式碼向Store傳送了一個購買請求,商品ID是package1,數量為1。與此同時,ANE向裝置中的應用商店傳送了一個購買行為,由裝置系統內的應用商店來負責交易的安全。它會先彈出一個原生對話方塊,讓玩家作購買確認;然後負責玩家的安全登陸和密碼輸入;再去連線蘋果的伺服器進行交易;最後將得到的結果返回給應用程式。

從程式角度來看,每一個交易是一個Transaction。它包含了下面的屬性:
identifier:交易ID,每次交易都有一個unique的ID,由應用商店生成。
date:交易時間
error:交易錯誤資訊
originalTransaction:原始交易(針對恢復非消費型商品的交易)
productIdentifier:交易所涉及的商品ID
productQuantity:交易所涉及的商品數量
receipt:交易成功後的收據

(由ANE封裝的Product和Transaction類,儲存了iOS SDK中StoreKit的原生類屬性,連命名都一樣)。

關於交易的幾個FAQ

(1)如果使用者在交易過程中退出應用了怎麼辦?
裝置中的應用商店,維護著一個Transaction佇列。每個交易的生命週期不受應用程式的生命週期限制,即使在交易過程中退出,交易依然存在。下次登陸應用並且初始化ProductStore時,應用商店會在第一時間派發事件告知交易結果。這就是為什麼我提到要儘早初始化ProductStore。

(2)如何防止使用者重複扣款?
對於非消費型商品不存在這個問題,商店不會因為這類商品給使用者重複扣款。但是對消費型商品,開發者也不必擔心重複扣款的問題。開發者只要在判斷了交易成功(包含驗證收據)之後結束該交易,則使用者就可以再次購買該商品。否則每次購買同樣的商品都會產生一個相同的交易ID,應用商店會提示“您已經購買該商品,但是並沒有下載”這樣的資訊。至於如何結束交易會在接下來的內容中說明。

TransactionEvent.PURCHASE_TRANSACTION_SUCCESS
下面是一段處理成功交易的程式碼範例,開發者在得到了交易成功的結果之後不要急於給玩家提供相應的服務。為了保證該交易是合法的而非來自於第三方軟體的造假行為,需要拿著收據去蘋果網站上驗證。驗證收據會在稍後說明。

private function purchaseTransactionSucceeded(e:TransactionEvent):void{
        var i:uint=0;
        var t:Transaction;
        while(e.transactions && i < e.transactions.length){
                t = e.transactions[i];
                i++;
                verifyReceipt(t.identifier, t.productIdentifier, t.productQuantity, t.receipt);
        }
}



TransactionEvent.PURCHASE_TRANSACTION_CANCEL
TransactionEvent.PURCHASE_TRANSACTION_FAIL       

當用戶取消交易或者交易失敗的時候,或者一個新的交易請求屬於重複購買行為。應用商店會派發Cancel或者Fail這兩個事件。它們都可以用下面的程式碼來處理,使用ProductStore.finishTransaction這個API來結束這筆交易。呼叫這個API會將該交易從系統維護的交易佇列中移除。

private function purchaseTransactionCanceled(e:TransactionEvent):void{
        var i:uint = 0;
        while(e.transactions && i < e.transactions.length){
                var t:Transaction = e.transactions[i];
                i++;
                productStore.finishTransaction(t.identifier);
        }
}

—————————————————————-
(四)驗證收據
—————————————————————-
交易收據以字串的形式儲存在Transaction類的receipt屬性裡,開發者可以選擇在客戶端提交驗證,也可以選擇讓自己的伺服器來發送驗證。

驗證收據的目的是檢查該交易的合法性,防止無效的購買。驗證的方式是將收據以JSON物件的方式傳送到蘋果官方的驗證地址,然後判斷返回的結果。

強烈推薦先用Base64把收據編碼然後再發送。

var encodedReceipt:String = Base64.encode(receipt);
var req:URLRequest = new URLRequest("https://sandbox.itunes.apple.com/verifyReceipt");
req.method = URLRequestMethod.POST;
req.data = "{\"receipt-data\" : \""+ encodedReceipt +"\"}";
var loader:URLLoader = new URLLoader(req);
loader.addEventListener(Event.COMPLETE,onReceiptComplete);
loader.addEventListener(IOErrorEvent.IO_ERROR, onReceiptError);

響應的結果也是一個JSON格式的物件:

{
    "status" : 0,
    "receipt" : { (receipt here) }
}

注意:應用正式提審之前要把驗證收據的地址改為https://buy.itunes.apple.com/verifyReceipt

status只要是0就說明該收據有效,否則無效。蘋果對收據的驗證沒有時效性,它不負責該收據的生命週期,所以傳送相同的收據永遠會得到同樣的結果。作為第三方伺服器,需要使用交易ID對交易作記錄,這樣可以避免同一個收據的兩次成功驗證導致的兩次購買成功的問題。

Gaming SDK包含了一個ProductStore的案例,各位可以在安裝路徑下找到。這個案例在驗證收據的時候有一個bug,它使用了一個第三方的Base64類,卻沒有提供該類包,所以會出現編譯錯誤。大家要注意這點,自己找一個Base64類來代替就可以了。