Google Play支付:
詳情可通過(guò)VPN:https://developer.android.com/google/play/billing/billing_library_overview#java
下面記錄為個(gè)人摘錄
1对粪、更新應(yīng)用程序的依賴關(guān)系
將以下行添加到build.gradle您應(yīng)用的文件的“依賴項(xiàng)”部分:
dependencies {
????...
????implementation 'com.android.billingclient:billing:2.1.0'
}
2右冻、連接到Google Play
在發(fā)出Google Play結(jié)算請(qǐng)求之前,您必須先通過(guò)以下步驟建立與Google Play的連接:
調(diào)用newBuilder() 以創(chuàng)建的實(shí)例著拭。 BillingClient 您還必須調(diào)用 setListener()纱扭,將傳遞給引用, PurchasesUpdatedListener 以接收有關(guān)您的應(yīng)用發(fā)起的購(gòu)買以及Google Play商店發(fā)起的購(gòu)買的更新儡遮。
建立與Google Play的連接乳蛾。設(shè)置過(guò)程是異步的,BillingClientStateListener 一旦客戶端的設(shè)置完成并且可以發(fā)出進(jìn)一步的請(qǐng)求鄙币,您就必須實(shí)現(xiàn)A 來(lái)接收回調(diào)肃叶。
覆蓋 onBillingServiceDisconnected() 回調(diào)方法,并實(shí)施您自己的重試策略十嘿,以在客戶端斷開(kāi)連接的情況下處理與Google Play的連接丟失因惭。例如,BillingClient如果Google Play商店服務(wù)在后臺(tái)更新绩衷,則可能會(huì)失去其連接蹦魔。 在發(fā)出進(jìn)一步的請(qǐng)求之前,BillingClient必須調(diào)用 startConnection()方法重新啟動(dòng)連接咳燕。
private BillingClient billingClient;
...
billingClient = BillingClient.newBuilder(activity).setListener(this).build();
billingClient.startConnection(new BillingClientStateListener() {
????@Override
????public void onBillingSetupFinished(BillingResult billingResult) {
????????if (billingResult.getResponseCode() == ?BillingResponseCode.OK) {
????????????// The BillingClient is ready. You can query purchases here.
????????}
????}
????@Override
????public void onBillingServiceDisconnected() {
????????// Try to restart the connection on the next request to
????????// Google Play by calling the startConnection() method.
????}
});
注意:強(qiáng)烈建議您實(shí)施自己的連接重試策略并覆蓋該 onBillingServiceDisconnected() 方法勿决。BillingClient執(zhí)行任何方法時(shí),請(qǐng)確保維護(hù)連接招盲。
3低缩、查詢應(yīng)用內(nèi)商品詳細(xì)信息
您在配置應(yīng)用內(nèi)商品時(shí)創(chuàng)建的唯一商品ID用于異步查詢Google Play的應(yīng)用內(nèi)商品詳細(xì)信息。要在Google Play中查詢應(yīng)用內(nèi)商品詳情宪肖,請(qǐng)致電 querySkuDetailsAsync()表制。調(diào)用此方法時(shí)健爬,傳遞一個(gè)實(shí)例,SkuDetailsParams 該實(shí)例 指定產(chǎn)品ID字符串列表和一個(gè)SkuType么介。該SkuType可以是SkuType.INAPP一次性產(chǎn)品或SkuType.SUBS訂閱費(fèi)娜遵。
注意:要查詢產(chǎn)品詳細(xì)信息,您的應(yīng)用將使用您在Google Play控制臺(tái)中配置產(chǎn)品時(shí)定義的產(chǎn)品ID壤短。有關(guān)更多信息设拟,請(qǐng)參閱 添加一次性產(chǎn)品特定功能 或添加訂閱特定功能。
要處理異步操作的結(jié)果久脯,還必須指定一個(gè)實(shí)現(xiàn)該SkuDetailsResponseListener 接口的偵聽(tīng) 器纳胧。然后onSkuDetailsResponse() ,您可以重寫 以在查詢結(jié)束時(shí)通知偵聽(tīng)器帘撰,如以下示例代碼所示:
List<String> skuList = new ArrayList<> ();
skuList.add("premium_upgrade");
skuList.add("gas");
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(SkuType.INAPP);
billingClient.querySkuDetailsAsync(params.build(),
? ? new SkuDetailsResponseListener() {
? ? ? ? @Override
? ? ? ? public void onSkuDetailsResponse(BillingResult billingResult,
? ? ? ? ? ? ? ? List<SkuDetails> skuDetailsList) {
? ? ? ? ? ? // Process the result.
? ? ? ? }
? ? });
注意:premium_upgrade產(chǎn)品ID代表用戶可以購(gòu)買一次但無(wú)限期使用的新游戲車跑慕。可以無(wú)限期使用的一次性產(chǎn)品稱為非消耗品摧找。氣體產(chǎn)品ID代表氣體核行,用戶可以多次購(gòu)買該氣體。非無(wú)限使用的一次性產(chǎn)品稱為消耗品蹬耘。要處理臨時(shí)資源的消耗芝雪,請(qǐng)參閱指示一次性產(chǎn)品已消耗。
您的應(yīng)用應(yīng)通過(guò)將其與APK捆綁在一起或從您自己的安全后端服務(wù)器中查詢來(lái)維護(hù)自己的產(chǎn)品ID列表综苔。
調(diào)用 getResponseCode() 以檢索響應(yīng)代碼惩系。如果請(qǐng)求成功,則響應(yīng)代碼為BillingResponse.OK如筛。有關(guān)Google Play其他可能的響應(yīng)代碼的列表堡牡,請(qǐng)參見(jiàn) BillingClient.BillingResponse。
如果發(fā)生錯(cuò)誤妙黍,您可以 getDebugMessage() 用來(lái)查看相關(guān)的錯(cuò)誤消息悴侵。
該谷歌Play結(jié)算庫(kù)存儲(chǔ)查詢結(jié)果中List的 SkuDetails 對(duì)象。然后拭嫁,您可以SkuDetails 在列表中的每個(gè)對(duì)象上調(diào)用各種方法可免,以查看有關(guān)應(yīng)用內(nèi)商品的相關(guān)信息,例如其價(jià)格或說(shuō)明做粤。要查看可用的產(chǎn)品詳細(xì)信息浇借,請(qǐng)參閱SkuDetails類中的方法列表。
以下示例顯示了如何使用SkuDetails上一個(gè)代碼段返回的對(duì)象來(lái)檢索應(yīng)用內(nèi)商品的價(jià)格:
if (result.getResponseCode() == BillingResponse.OK && skuDetailsList != null) {
? ?for (SkuDetails skuDetails : skuDetailsList) {
? ? ? ?String sku = skuDetails.getSku();
? ? ? ?String price = skuDetails.getPrice();
? ? ? ?if ("premium_upgrade".equals(sku)) {
? ? ? ? ? ?premiumUpgradePrice = price;
? ? ? ?} else if ("gas".equals(sku)) {
? ? ? ? ? ?gasPrice = price;
? ? ? ?}
? ?}
}
4怕品、允許購(gòu)買應(yīng)用內(nèi)商品
某些Android手機(jī)可能具有較舊版本的Google Play商店應(yīng)用妇垢,該版本不支持某些產(chǎn)品類型,例如訂閱。因此闯估,在您的應(yīng)用進(jìn)入計(jì)費(fèi)流程之前灼舍,請(qǐng)致電 isFeatureSupported() 以檢查設(shè)備是否支持您要銷售的產(chǎn)品。有關(guān)產(chǎn)品類型的列表涨薪,請(qǐng)參見(jiàn) BillingClient.FeatureType骑素。
要從您的應(yīng)用發(fā)出購(gòu)買請(qǐng)求,請(qǐng)launchBillingFlow()從UI線程調(diào)用 方法刚夺。將引用傳遞給BillingFlowParams 包含相關(guān)數(shù)據(jù)的 對(duì)象以完成購(gòu)買献丑,例如商品的商品ID(skuId)和商品類型(SkuType.INAPP針對(duì)一次性商品或SkuType.SUBS訂閱商品)。要獲取的實(shí)例 BillingFlowParams 侠姑,請(qǐng)使用 BillingFlowParams.Builder 類:
// Retrieve a value for "skuDetails" by calling querySkuDetailsAsync().
BillingFlowParams flowParams = BillingFlowParams.newBuilder()
? ? ? ? .setSkuDetails(skuDetails)
? ? ? ? .build();
int responseCode = billingClient.launchBillingFlow(flowParams);
當(dāng)您調(diào)用該 launchBillingFlow() 方法時(shí)创橄,系統(tǒng)會(huì)顯示Google Play購(gòu)買屏幕。
該 launchBillingFlow() 方法返回中列出的幾個(gè)響應(yīng)代碼之一 BillingClient.BillingResponse莽红。Google Play調(diào)用將 onPurchasesUpdated() 購(gòu)買操作的結(jié)果傳遞給實(shí)現(xiàn)該P(yáng)urchasesUpdatedListener接口的偵聽(tīng) 器的方法妥畏。使用setListener()前面在“ 連接到Google Play”部分中演示的方法指定了偵聽(tīng)器 。
您必須實(shí)現(xiàn)該 onPurchasesUpdated() 方法以處理可能的響應(yīng)代碼船老。以下代碼段顯示了如何覆蓋該 onPurchasesUpdated() 方法:
@Override
void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
? ? if (billingResult.getResponseCode() == BillingResponse.OK
? ? ? ? ? ? && purchases != null) {
? ? ? ? for (Purchase purchase : purchases) {
? ? ? ? ? ? handlePurchase(purchase);
? ? ? ? }
? ? } else if (billingResult.getResponseCode() == BillingResponse.USER_CANCELED) {
? ? ? ? // Handle an error caused by a user cancelling the purchase flow.
? ? } else {
? ? ? ? // Handle any other error codes.
? ? }
}
成功購(gòu)買會(huì)產(chǎn)生一個(gè)Google Play成功屏幕咖熟。
成功的購(gòu)買還會(huì)生成購(gòu)買令牌,該令牌是代表用戶及其所購(gòu)買的應(yīng)用內(nèi)商品的產(chǎn)品ID的唯一標(biāo)識(shí)符柳畔。您的應(yīng)用程序可以將購(gòu)買令牌存儲(chǔ)在本地,或者理想情況下郭赐,可以將其傳遞到安全的后端服務(wù)器薪韩,該服務(wù)器可以用來(lái)驗(yàn)證購(gòu)買并防止欺詐。購(gòu)買令牌對(duì)于每次一次性產(chǎn)品購(gòu)買都是唯一的捌锭。但是俘陷,由于訂閱是一次性購(gòu)買的,并且會(huì)在常規(guī)結(jié)算周期自動(dòng)更新观谦,因此訂閱的購(gòu)買令牌在每個(gè)結(jié)算周期都保持不變拉盾。
還通過(guò)電子郵件向用戶發(fā)送包含訂單ID或交易唯一ID的交易收據(jù)。用戶會(huì)收到一封電子郵件豁状,其中包含每次一次性產(chǎn)品購(gòu)買以及首次訂閱購(gòu)買和隨后定期自動(dòng)續(xù)訂的唯一訂單ID捉偏。您可以使用訂單ID在Google Play控制臺(tái)中管理退款。有關(guān)更多詳細(xì)信息泻红,請(qǐng)參閱 查看和退款您的應(yīng)用程序的訂單和訂閱夭禽。
注意:代表訂購(gòu)重復(fù)性的訂單號(hào)有一個(gè)附加整數(shù),代表該訂購(gòu)的特定重復(fù)性谊路。例如讹躯,初始訂閱訂單ID可能 GPA.1234-5678-9012-34567與后續(xù)訂購(gòu)ID分別為GPA.1234-5678-9012-34567..0(第一次重復(fù)orderID), GPA.1234-5678-9012-34567..1(第二次重復(fù)orderID)等等。
注意:如果用戶在購(gòu)買應(yīng)用內(nèi)商品時(shí)(例如在免費(fèi)試用訂閱期間)沒(méi)有欠款潮梯,則訂單ID為$ 0骗灶。例如,當(dāng)用戶取消訂閱時(shí)秉馏,訂閱將保持有效耙旦,直到計(jì)費(fèi)期結(jié)束。如果用戶決定重新注冊(cè)沃饶,則其帳戶中會(huì)保留一些貸方母廷。在這種情況下,將創(chuàng)建一個(gè)新的購(gòu)買令牌糊肤,為$ 0創(chuàng)建一個(gè)訂單ID琴昆,并在信用用完后續(xù)訂。
5馆揉、確認(rèn)購(gòu)買(消費(fèi)掉才算真正的完結(jié)該訂單)
如果您使用的是Google Play結(jié)算庫(kù)2.0版或更高版本业舍,則必須在三天內(nèi)確認(rèn)所有購(gòu)買。未正確確認(rèn)購(gòu)買會(huì)導(dǎo)致這些購(gòu)買被退款升酣。
Google Play支持從應(yīng)用內(nèi)(應(yīng)用內(nèi))或應(yīng)用外(應(yīng)用外)購(gòu)買產(chǎn)品舷暮。為了使Google Play無(wú)論用戶在哪里購(gòu)買產(chǎn)品,都能夠確保一致的購(gòu)買體驗(yàn)噩茄,您必須SUCCESS在授予用戶權(quán)利后盡快確認(rèn)所有通過(guò)Google Play計(jì)費(fèi)庫(kù)收到狀態(tài)的購(gòu)買下面。如果您在三天內(nèi)不確認(rèn)購(gòu)買,則用戶會(huì)自動(dòng)收到退款绩聘,Google Play會(huì)撤消購(gòu)買沥割。對(duì)于待處理的交易,購(gòu)買PENDING狀態(tài)為3天的窗口不適用凿菩。相反机杜,它在購(gòu)買移至該SUCCESS狀態(tài)時(shí)開(kāi)始。
您可以使用以下方法之一確認(rèn)購(gòu)買:
對(duì)于易耗品衅谷,請(qǐng)使用 consumeAsync()客戶端API中的椒拗。
對(duì)于未消費(fèi)的產(chǎn)品,請(qǐng)使用 acknowledgePurchase()客戶端API中的获黔。
acknowledge()服務(wù)器API中也提供了一種新方法蚀苛。
對(duì)于訂閱,您必須確認(rèn)任何包含新購(gòu)買令牌的購(gòu)買肢执。這意味著需要確認(rèn)所有初始購(gòu)買枉阵,計(jì)劃變更和重新注冊(cè),但您無(wú)需確認(rèn)后續(xù)續(xù)訂预茄。要確定采購(gòu)是否需要確認(rèn)兴溜,您可以檢查采購(gòu)中的確認(rèn)字段侦厚。
該P(yáng)urchase對(duì)象包括isAcknowledged() 指示是否已經(jīng)確認(rèn)購(gòu)買的 方法。此外拙徽,服務(wù)器端API包括用于確認(rèn)布爾值 Product.purchases.get()和Product.subscriptions.get()刨沦。在確認(rèn)購(gòu)買之前,請(qǐng)使用以下方法確定是否已確認(rèn)購(gòu)買膘怕。
此示例顯示如何確認(rèn)訂閱購(gòu)買:
BillingClient client = ...
AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = ...
void handlePurchase(Purchase purchase) {
? ? if (purchase.getPurchaseState() == PurchaseState.PURCHASED) {
? ? ? ? // Grant entitlement to the user.
? ? ? ? ...
? ? ? ? // Acknowledge the purchase if it hasn't already been acknowledged.
? ? ? ? if (!purchase.isAcknowledged()) {
? ? ? ? ? ? AcknowledgePurchaseParams acknowledgePurchaseParams =
? ? ? ? ? ? ? ? AcknowledgePurchaseParams.newBuilder()
? ? ? ? ? ? ? ? ? ? .setPurchaseToken(purchase.getPurchaseToken())
? ? ? ? ? ? ? ? ? ? .build();
? ? ? ? ? ? client.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
? ? ? ? }
? ? }
}
ONE store支付:
詳情可通過(guò)VPN:https://dev.onestore.co.kr/devpoc/reference/view/IAP_v17_cn
1想诅、什么是ONE store應(yīng)用內(nèi)支付(IAP)
一家商店應(yīng)用內(nèi)部支付(下稱IAP)是一家商店使用的,支付服務(wù)岛心,開(kāi)發(fā)者銷售手機(jī)應(yīng)用程序的應(yīng)用內(nèi)部商品時(shí)来破,利用一個(gè)商店的驗(yàn)證和支付系統(tǒng)完成向用戶支付費(fèi)用,解決等價(jià)流程忘古。一店服務(wù)(一店服務(wù)徘禁,OSS)替代開(kāi)發(fā)的應(yīng)用商品,OSS與一店總服務(wù)器連接執(zhí)行支付工作髓堪,用于響應(yīng)用戶的應(yīng)用內(nèi)部商品購(gòu)買請(qǐng)求送朱。
2、開(kāi)發(fā)環(huán)境配置建議安卓應(yīng)用程序程序適用的IAP SDK所需的開(kāi)發(fā)環(huán)境如下:
Android 4.0及以上版本(API版本14以上)
Java SDK 1.6版本
Android studio 2.0及以上版本
3干旁、事先準(zhǔn)備
詳情可通過(guò)VPN:https://dev.onestore.co.kr/devpoc/reference/view/IAP_v17_04_preparation_cn
3-1驶沼、配置應(yīng)用ID
3-2、填寫銀行信息
3-3争群、應(yīng)用內(nèi)商品注冊(cè)
3-3.1應(yīng)用內(nèi)商品個(gè)別注冊(cè)
3-3.2應(yīng)用內(nèi)商品批量注冊(cè)
3-4回怜、配置認(rèn)證密鑰
3-5、下載示例應(yīng)用
3-6换薄、新增應(yīng)用內(nèi)支付庫(kù)(Library)
3-7鹉戚、設(shè)置 Android Manifest文檔
3-8、安裝ONE store應(yīng)用
4缠局、實(shí)現(xiàn)應(yīng)用內(nèi)支付
詳情可通過(guò)VPN:https://dev.onestore.co.kr/devpoc/reference/view/IAP_v17_05_implementation_cn
使用SDK實(shí)現(xiàn)應(yīng)用內(nèi)支付
4-1溉卓、發(fā)起ONE store登錄的請(qǐng)求
調(diào)用 launchLoginFlowAsync,請(qǐng)求登錄于ONE store。
以參數(shù)傳遞的requestCode用于以后確認(rèn)返回至onActivityResult的數(shù)據(jù)怀泊。
/*
?* PurchaseClient的 launchLoginFlowAsync API(登錄)回調(diào)監(jiān)聽(tīng)器
?*/
PurchaseClient.LoginFlowListener mLoginFlowListener = new PurchaseClient.LoginFlowListener() {
? ? @Override
? ? public void onSuccess() {
? ? ? ? Log.d(TAG, "launchLoginFlowAsync onSuccess");
? ? ? ? // 開(kāi)發(fā)者應(yīng)自行編寫登錄成功后的方案。
? ? }
? ? @Override
? ? public void onError(IapResult result) {
? ? ? ? Log.e(TAG, "launchLoginFlowAsync onError, " + result.toString());
? ? }
? ? @Override
? ? public void onErrorRemoteException() {
? ? ? ? Log.e(TAG, "launchLoginFlowAsync onError, 無(wú)法連接ONE store服務(wù)");
? ? }
? ? @Override
? ? public void onErrorSecurityException() {
? ? ? ? Log.e(TAG, "launchLoginFlowAsync onError, 應(yīng)用狀態(tài)異常下請(qǐng)求支付");
? ? }
? ? @Override
? ? public void onErrorNeedUpdateException() {
? ? ? ? Log.e(TAG, "launchLoginFlowAsync onError, 需要更新ONE store客戶端 ");
? ? }
};
int IAP_API_VERSION = 5;
int LOGIN_REQUEST_CODE = 2000; // 向onActivityResult 返回的 request code
mPurchaseClient.launchLoginFlowAsync(IAP_API_VERSION, "調(diào)用Activity".this, LOGIN_REQUEST_CODE, mLoginFlowListener)
4-2立润、應(yīng)用內(nèi)支付初始化與連接
使用應(yīng)用內(nèi)支付SDK時(shí)庙曙,應(yīng)進(jìn)行初始化,創(chuàng)建PurchaseClient對(duì)象并執(zhí)行購(gòu)買方法粹庞。首先在創(chuàng)建PurchaseClient對(duì)象時(shí)咳焚,輸入當(dāng)前Activity的Context信息和簽名密鑰值。創(chuàng)建對(duì)象后庞溜,執(zhí)行connect連接革半。在此過(guò)程中碑定,SDK中與應(yīng)用內(nèi)支付服務(wù)連接,啟動(dòng)為購(gòu)買的各種參數(shù)設(shè)定的操作又官。
/*
?* PurchaseClient的 connect API 回調(diào)監(jiān)聽(tīng)器
?* 返回綁定成功或失敗以及是否要更新ONE store服務(wù)的結(jié)果延刘。
?*/
PurchaseClient.ServiceConnectionListener mServiceConnectionListener = new PurchaseClient.ServiceConnectionListener() {
? ? @Override
? ? public void onConnected() {
? ? ? ? Log.d(TAG, "Service connected");
? ? }
? ? @Override
? ? public void onDisconnected() {
? ? ? ? Log.d(TAG, "Service disconnected");
? ? }
? ? @Override
? ? public void onErrorNeedUpdateException() {
? ? ? ? Log.e(TAG, "connect onError, 需要更新ONE store客戶端 ");
? PurchaseClient.launchUpdateOrInstallFlow(this);
? ? }
};
@Override
public void onCreate(Bundle savedInstanceState) {
?super.onCreate(savedInstanceState);
? ? // PurchaseClient 初始化——將公鑰作為參數(shù)傳遞,以驗(yàn)證context和Signature六敬。
? ? mPurchaseClient = new PurchaseClient(this, AppSecurity.getPublicKey());
? ? // 請(qǐng)求綁定ONE store服務(wù)碘赖,以啟動(dòng)應(yīng)用內(nèi)支付。
? ? mPurchaseClient.connect(mServiceConnectionListener);
}
請(qǐng)注意連接時(shí)未安裝ONE store客戶端或ONE store客戶端版本不支持應(yīng)用內(nèi)支付 V17版本的情況外构,會(huì)調(diào)用 ServiceConnectionListener之onErrorNeedUpdateException()普泡。出現(xiàn)該錯(cuò)誤時(shí),調(diào)用安裝或更新ONE store客戶端的方法审编,即PurchaseClient.launchUpdateOrInstallFlow撼班。
退出Activity時(shí),在 onDestroy方法中輸入解除PurchaseClient的代碼割笙。
@Override
protected void onDestroy() {
? ? super.onDestroy();
? ? if (mPurchaseClient == null) {
? ? ? ? Log.d(TAG, "PurchaseClient is not initialized");
? ? ? ? return;
? ? }
? ? // 關(guān)閉應(yīng)用時(shí)权烧,使用PurchaseClient中斷服務(wù)。
? ? mPurchaseClient.terminate();
}
4-3伤溉、查詢是否支持
開(kāi)發(fā)者在正式使用應(yīng)用內(nèi)支付方法之前般码,應(yīng)先調(diào)用相應(yīng)方法,確認(rèn)能否啟動(dòng)應(yīng)用內(nèi)支付乱顾。
如果SDK方法是使用AIDL提供的API板祝,以回調(diào)形式返回成功及失敗的結(jié)果。
對(duì)失敗的返回會(huì)提供使用SDK的開(kāi)發(fā)者必須處理的三大錯(cuò)誤(onErrorRemoteException走净、onErrorSecurityException券时、onErrorNeedUpdateException)和普通錯(cuò)誤(onError)。向onError監(jiān)聽(tīng)器返回的IapResult有返回碼和對(duì)返回碼進(jìn)行說(shuō)明的Enum伏伯,開(kāi)發(fā)者應(yīng)根據(jù)開(kāi)發(fā)方案橘洞,處理相應(yīng)錯(cuò)誤。
/*
?* PurchaseClient的isBillingSupportedAsync (查詢是否支持)回調(diào)監(jiān)聽(tīng)器
?*/
PurchaseClient.BillingSupportedListener mBillingSupportedListener = new PurchaseClient.BillingSupportedListener() {
? ? @Override
? ? public void onSuccess() {
? ? ? ? Log.d(TAG, "isBillingSupportedAsync onSuccess");
? ? }
? ? @Override
? ? public void onError(IapResult result) {
? ? ? ? Log.e(TAG, "isBillingSupportedAsync onError, " + result.toString());
? ? }
? ? @Override
? ? public void onErrorRemoteException() {
? ? ? ? Log.e(TAG, "isBillingSupportedAsync onError, 無(wú)法連接ONE store服務(wù)");
? ? }
? ? @Override
? ? public void onErrorSecurityException() {
? ? ? ? Log.e(TAG, "isBillingSupportedAsync onError, 應(yīng)用狀態(tài)異常下請(qǐng)求支付");
? ? }
? ? @Override
? ? public void onErrorNeedUpdateException() {
? ? ? ? Log.e(TAG, "isBillingSupportedAsync onError, 需要更新ONE store客戶端");
? ? }
};
// ONE store應(yīng)用內(nèi)支付API版本
int IAP_API_VERSION = 5;
mPurchaseClient.isBillingSupportedAsync(IAP_API_VERSION, mBillingSupportedListener);
4-4说搅、查詢商品信息
開(kāi)發(fā)者在 ArrayList輸入采用queryProductAsync方法的參數(shù)中放入想要獲取信息的應(yīng)用內(nèi)商品ID并調(diào)用炸枣,返回結(jié)果至已注冊(cè)的監(jiān)聽(tīng)器。
商品ID指開(kāi)發(fā)者在開(kāi)發(fā)者中心注冊(cè)商品時(shí)自定義的商品ID弄唧。商品信息會(huì)以 ProductDetail形式返回至 onSuccess監(jiān)聽(tīng)器适肠。
/*
?* PurchaseClient的 queryProductsAsync API (商品信息查詢)回調(diào)監(jiān)聽(tīng)器
?*/
PurchaseClient.QueryProductsListener mQueryProductsListener = new PurchaseClient.QueryProductsListener() {
? ? @Override
? ? public void onSuccess(List<ProductDetail> productDetails) {
? ? ? ? Log.d(TAG, "queryProductsAsync onSuccess, " + productDetails.toString());
? ? }
? ? @Override
? ? public void onErrorRemoteException() {
? ? ? ? Log.e(TAG, "queryProductsAsync onError, 無(wú)法連接ONE store服務(wù) ");
? ? }
? ? @Override
? ? public void onErrorSecurityException() {
? ? ? ? Log.e(TAG, "queryProductsAsync onError, 應(yīng)用狀態(tài)異常下請(qǐng)求支付 ");
? ? }
? ? @Override
? ? public void onErrorNeedUpdateException() {
? ? ? ? Log.e(TAG, "queryProductsAsync onError, 需要更新ONE store客戶端");
? ? }
? ? @Override
? ? public void onError(IapResult result) {
? ? ? ? Log.e(TAG, "queryProductsAsync onError, " + result.toString());
? ? }
};
int IAP_API_VERSION = 5;
String productType = IapEnum.ProductType.IN_APP.getType(); // "inapp"
ArrayList<String> productCodes = new ArrayList<>();
productCodes.add("p5000");
productCodes.add("p10000");
mPurchaseClient.queryProductsAsync(IAP_API_VERSION, productCodes, productType, mQueryProductsListener);
4-5、發(fā)起購(gòu)買請(qǐng)求
調(diào)用launchPurchaseFlowAsync方法執(zhí)行購(gòu)買候引。調(diào)用方法時(shí)侯养,輸入想要購(gòu)買的應(yīng)用內(nèi)商品ID、商品名稱澄干、商品類別和開(kāi)發(fā)者任意決定的launchPurchaseFlowAsync(不超過(guò)100byte)逛揩,該值用于支付成功后確認(rèn)數(shù)據(jù)的正確性和附加數(shù)據(jù)柠傍,并以參數(shù)傳遞的requestCode用于確認(rèn)返回至onActivityResult的數(shù)據(jù)。
購(gòu)買成功時(shí)結(jié)果返回至onSuccess監(jiān)聽(tīng)器息尺,以SDK的 PurchaseData規(guī)格返回携兵。開(kāi)發(fā)者基于收到的結(jié)果,再通過(guò) developerPayload確認(rèn)數(shù)據(jù)的正確性和附加數(shù)據(jù)搂誉,以簽名信息來(lái)驗(yàn)證徐紧。
管理型商品,通過(guò)設(shè)置商品消耗處理為用戶提供商品炭懊。
ONE store面向用戶開(kāi)展發(fā)送優(yōu)惠券并级、 購(gòu)物返現(xiàn)(cashback)等各種優(yōu)惠推廣活動(dòng)。開(kāi)發(fā)者發(fā)起購(gòu)買請(qǐng)求時(shí)侮腹,可通過(guò)gameUserId嘲碧、promotionApplicable參數(shù),允許或控制用戶參加推廣活動(dòng)父阻。開(kāi)發(fā)者選擇應(yīng)用的唯一標(biāo)識(shí)符及是否參與活動(dòng)并傳遞給ONE store愈涩,ONE store基于該值處理用戶的活動(dòng)優(yōu)惠。
注意:gameUserId加矛,protectionApplicable參數(shù)必須事先應(yīng)用于ONE store經(jīng)理的促銷工作履婉。一般說(shuō)來(lái),該值不應(yīng)發(fā)送。
此外斟览,gameUserId參數(shù)應(yīng)當(dāng)送到散列單一值毁腿,以便在事先發(fā)送價(jià)值信息時(shí),沒(méi)有隱私信息保護(hù)問(wèn)題苛茂。
/*
* PurchaseClient的 launchPurchaseFlowAsync API (購(gòu)買)回調(diào)監(jiān)聽(tīng)器
?*/
PurchaseClient.PurchaseFlowListener mPurchaseFlowListener = new PurchaseClient.PurchaseFlowListener() {
? ? @Override
? ? public void onSuccess(PurchaseData purchaseData) {
? Log.d(TAG, "launchPurchaseFlowAsync onSuccess, " + purchaseData.toString());
? ? ? ? // 購(gòu)買成功后檢查開(kāi)發(fā)者payload已烤。
? ? ? ? if (!isValidPayload(purchaseData.getDeveloperPayload())) {
? ? ? ? ? ? Log.d(TAG, "launchPurchaseFlowAsync onSuccess, Payload is not valid.");
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? // 購(gòu)買成功后檢查簽名。
? ? ? ? boolean validPurchase = AppSecurity.isValidPurchase(purchaseData.getPurchaseData(), purchaseData.getSignature());
? ? ? ? if (validPurchase) {
? ? ? ? ? ? if (product5000.equals(purchaseData.getProductId())) {{
? ? ? ? ? ? ? ? // 管理型商品(inapp)購(gòu)買成功后消耗妓羊。
? ? ? ? ? ? ? ? consumeItem(purchaseData);
? ? ? ? ? ? }
? ? ? ? } else {
? ? ? ? ? ? Log.d(TAG, "launchPurchaseFlowAsync onSuccess, Signature is not valid.");
? ? ? ? ? ? return;
? ? ? ? }
? ? }
? ? @Override
? ? public void onError(IapResult result) {
? ? ? ? Log.e(TAG, "launchPurchaseFlowAsync onError, " + result.toString());
? ? }
? ? @Override
? ? public void onErrorRemoteException() {
? ? ? ? Log.e(TAG, "launchPurchaseFlowAsync onError, 無(wú)法連接ONE store服務(wù) ");
? ? }
? ? @Override
? ? public void onErrorSecurityException() {
? ? ? ? Log.e(TAG, "launchPurchaseFlowAsync onError, 應(yīng)用狀態(tài)異常下請(qǐng)求支付 ");
? ? }
? ? @Override
? ? public void onErrorNeedUpdateException() {
? ? ? ? Log.e(TAG, "launchPurchaseFlowAsync onError, 需要更新ONE store客戶端 ");
? ? }
};
int IAP_API_VERSION = 5;
int PURCHASE_REQUEST_CODE = 1000; // 返回至onActivityResult的request code
String product5000 = "p5000"; // 請(qǐng)求購(gòu)買的商品ID
String productName = ""; // ""時(shí)顯示開(kāi)發(fā)者中心注冊(cè)的商品名稱
String productType = IapEnum.ProductType.IN_APP.getType(); // "inapp"
String devPayload = AppSecurity.generatePayload();
String gameUserId = ""; // 默認(rèn) ""
boolean promotionApplicable = false;
mPurchaseClient.launchPurchaseFlowAsync(IAP_API_VERSION, "調(diào)用Activity".this, PURCHASE_REQUEST_CODE, product5000, productName, productType, devPayload, gameUserId, promotionApplicable, mPurchaseFlowListener);
支付成功時(shí)返回至監(jiān)聽(tīng)器的Purchase信息參考“應(yīng)用內(nèi)支付參考 - getPurchaseIntent() 發(fā)起購(gòu)買請(qǐng)求”胯究。
支付結(jié)果會(huì)返回至調(diào)用launchPurchaseFlowAsync的Activity的onActivityResult,在這里須添加handlePurchaseData方法躁绸,以SDK處理購(gòu)買結(jié)果唐片。啟動(dòng)handlePurchaseData方法時(shí),如果作為請(qǐng)求購(gòu)買的參數(shù)輸入的 PurchaseFlowListener為null的話涨颜,會(huì)返回false(失敗)茧球。成功或錯(cuò)誤的處理結(jié)果會(huì)通過(guò) PurchaseFlowListener來(lái)返回庭瑰。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
? ? Log.e(TAG, "onActivityResult resultCode " + resultCode);
? ? switch (requestCode) {
? ? ? ? case PURCHASE_REQUEST_CODE:
? ? ? ? ? ? /*
? ? ? ? ? ? ?* 調(diào)用 launchPurchaseFlowAsync API 時(shí)收到的intent數(shù)據(jù)通過(guò)handlePurchaseData解析返回值。
? ? ? ? ? ? ?* 解析后返回結(jié)果通過(guò)調(diào)用 launchPurchaseFlowAsync 時(shí)的 PurchaseFlowListener 返回抢埋。
? ? ? ? ? ? ?*/
? ? ? ? ? ? if (resultCode == Activity.RESULT_OK) {
? ? ? ? ? ? ? ? if (mPurchaseClient.handlePurchaseData(data) == false) {
? ? ? ? ? ? ? ? ? ? Log.e(TAG, "onActivityResult handlePurchaseData false ");
? ? ? ? ? ? ? ? ? ? // listener is null
? ? ? ? ? ? ? ? }
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? Log.e(TAG, "onActivityResult user canceled");
? ? ? ? ? ? ? ? // user canceled , do nothing..
? ? ? ? ? ? }
? ? ? ? ? ? break;
? ? ? ? default:
? ? }
}
4-6弹灭、商品消耗
如為管理型商品(inapp)督暂,未消耗已購(gòu)商品時(shí)無(wú)法再次購(gòu)買。用戶購(gòu)買商品后穷吮,其購(gòu)買信息托管給ONE store逻翁,商品被消耗,ONE store立刻收回用戶購(gòu)買商品的權(quán)限捡鱼。也就是說(shuō)八回,如過(guò)購(gòu)買了管理型商品而未消耗,可作為永久性商品驾诈,如購(gòu)買后立刻消耗商品缠诅,可作為消耗型商品,如超過(guò)一定期限消耗已購(gòu)商品乍迄,可作為限期型商品管引。要發(fā)起商品消耗請(qǐng)求時(shí),將返回至launchPurchaseFlowAsync或queryPurchasesAsync的購(gòu)買信息闯两,作為 consumeAsync 方法的參數(shù)傳遞并調(diào)用褥伴。
/*
?* PurchaseClient的 consumeAsync API (商品消耗)回調(diào)監(jiān)聽(tīng)器
?*/
PurchaseClient.ConsumeListener mConsumeListener = new PurchaseClient.ConsumeListener() {
? ? @Override
? ? public void onSuccess(PurchaseData purchaseData) {
? Log.d(TAG, "consumeAsync onSuccess, " + purchaseData.toString());
? // 商品消耗成功后,按各開(kāi)發(fā)者編寫的購(gòu)買成功方案進(jìn)行漾狼。
? ? }
? ? @Override
? ? public void onErrorRemoteException() {
? ? ? ? Log.e(TAG, "consumeAsync onError, 無(wú)法連接ONE store服務(wù)");
? ? }
? ? @Override
? ? public void onErrorSecurityException() {
? ? ? ? Log.e(TAG, "consumeAsync onError, 應(yīng)用狀態(tài)異常下請(qǐng)求支付");
? ? }
? ? @Override
? ? public void onErrorNeedUpdateException() {
? ? ? ? Log.e(TAG, "consumeAsync onError, 需要更新ONE store客戶端 ");
? ? }
? ? @Override
? ? public void onError(IapResult result) {
? ? ? ? Log.e(TAG, "consumeAsync onError, " + result.toString());
? ? }
};
int IAP_API_VERSION = 5;
PurchaseData purchaseData; // 查詢購(gòu)買記錄及請(qǐng)求購(gòu)買后接到的PurchaseData
mPurchaseClient.consumeAsync(IAP_API_VERSION, purchaseData, mConsumeListener);
4-7重慢、查詢購(gòu)買記錄
調(diào)用queryPurchasesAsync方法來(lái)獲取用戶已購(gòu)但未消耗的管理型商品(inapp)和用戶訂閱的包月自動(dòng)支付商品(auto)。SDK會(huì)驗(yàn)證簽名以確認(rèn)購(gòu)買信息數(shù)據(jù)偽造與否邦投,如簽名驗(yàn)證失敗伤锚,會(huì)將“IapResult”內(nèi)定義的 IapResult.IAP_ERROR_SIGNATURE_VERIFICATION值返回至onError監(jiān)聽(tīng)器。出現(xiàn)錯(cuò)誤表示購(gòu)買信息數(shù)據(jù)有偽造的可能志衣,有必要確認(rèn)是否有abusing襲擊屯援。
開(kāi)發(fā)者查詢購(gòu)買記錄獲得管理型商品(inapp),可通過(guò)設(shè)置商品消耗向用戶提供商品念脯。
/*
?* PurchaseClient的queryPurchasesAsync API (查詢購(gòu)買記錄)回調(diào)監(jiān)聽(tīng)器
?*/
PurchaseClient.QueryPurchaseListener mQueryPurchaseListener = new PurchaseClient.QueryPurchaseListener() {
? ? @Override
? ? public void onSuccess(List<PurchaseData> purchaseDataList, String productType) {
? Log.d(TAG, "queryPurchasesAsync onSuccess, " + purchaseDataList.toString());
? ? ? ? if (IapEnum.ProductType.IN_APP.getType().equalsIgnoreCase(productType)) {
? ? ? ? ? ? // 如為查詢購(gòu)買記錄后獲取的管理型商品( inapp)狞洋,先驗(yàn)證簽名,成功后消耗商品绿店。
? ? ? ? } else if (IapEnum.ProductType.AUTO.getType().equalsIgnoreCase(productType)) {
? ? ? ? ? ? // 如為查詢購(gòu)買記錄后獲取的包月自動(dòng)支付商品( auto)吉懊,先驗(yàn)證簽名,成功后根據(jù)開(kāi)發(fā)者應(yīng)用處理需求編寫方案假勿。
? ? ? ? }
? ? }
? ? @Override
? ? public void onErrorRemoteException() {
? ? ? ? Log.e(TAG, "queryPurchasesAsync onError, 無(wú)法連接ONE store服務(wù)");
? ? }
? ? @Override
? ? public void onErrorSecurityException() {
? ? ? ? Log.e(TAG, "queryPurchasesAsync onError, 應(yīng)用狀態(tài)異常下請(qǐng)求支付");
? ? }
? ? @Override
? ? public void onErrorNeedUpdateException() {
? ? ? ? Log.e(TAG, "queryPurchasesAsync onError, 需要更新ONE store客戶端 ");
? ? }
? ? @Override
? ? public void onError(IapResult result) {
? ? ? ? Log.e(TAG, "queryPurchasesAsync onError, " + result.toString());
? ? }
};
int IAP_API_VERSION = 5;
String productType = IapEnum.ProductType.IN_APP.getType(); // "inapp"
mPurchaseClient.queryPurchasesAsync(IAP_API_VERSION, productType, mQueryPurchaseListener);
MyCard支付:
1借嗽、通過(guò)商務(wù)聯(lián)系MyCard進(jìn)行技術(shù)對(duì)接,獲得最新MyCardPaySDK.jar和接入文檔
2转培、導(dǎo)入MyCardPaySDK.jar
3恶导、根據(jù)MyCard提供文檔設(shè)置AndroidManifest.xml
4、根據(jù)自身需求確定是走SDK支付方式還是WebView支付方式
4-1浸须、SDK支付方式
???? ? ?MyCardSDK sdk = new MyCardSDK(activity);
???? ? ?//flag???true代表測(cè)試環(huán)境惨寿,false代表正式環(huán)境
???? ? ?sdk.StartPayActivityForResult(flag, bean.getAuthCode());
?? ? ? ?// 通過(guò)onActivityResult接收SDK結(jié)果
????????if (requestCode == Config.Payment_RequestCode) {
????????????if( resultCode == -1)
????????????{
????????????????JSONObject js = null;
????????????????try {
????????????????????js = new JSONObject(data.getStringExtra(Config.PaySDK_Result));
????????????????????MLog.e(data.getStringExtra(Config.PaySDK_Result));
????????????????????if (js.optInt("returnCode") == 1 && js.optInt("payResult") == 3) {
????????????????????????String orderNo = js.getString("facTradeSeq");
????????????????????????//進(jìn)行你的操作
????????????????????}
????????????????} catch (JSONException e) {
????????????????????e.printStackTrace();
????????????????} catch (Exception e){
????????????????}
????????????}else{
????????????}
????????}
4-2邦泄、WEB支付方式
測(cè)試環(huán)境鏈接(http://test.mycard*)、正式環(huán)境鏈接(https://www.mycard*)不搞混亂就好裂垦,后面拼接字段需要注意