Android三方支付:Google Play支付毛仪、MyCard支付、ONE store支付

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*)不搞混亂就好裂垦,后面拼接字段需要注意

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末顺囊,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蕉拢,更是在濱河造成了極大的恐慌特碳,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件企量,死亡現(xiàn)場(chǎng)離奇詭異测萎,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)届巩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門硅瞧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人恕汇,你說(shuō)我怎么就攤上這事腕唧。” “怎么了瘾英?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵枣接,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我缺谴,道長(zhǎng)但惶,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任湿蛔,我火速辦了婚禮膀曾,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘阳啥。我一直安慰自己添谊,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布察迟。 她就那樣靜靜地躺著斩狱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪扎瓶。 梳的紋絲不亂的頭發(fā)上所踊,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音概荷,去河邊找鬼污筷。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的瓣蛀。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼雷厂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼惋增!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起改鲫,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤诈皿,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后像棘,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體稽亏,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年缕题,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了截歉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡烟零,死狀恐怖瘪松,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情锨阿,我是刑警寧澤宵睦,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站墅诡,受9級(jí)特大地震影響壳嚎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜末早,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一烟馅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧荐吉,春花似錦焙糟、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至痪欲,卻和暖如春悦穿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背业踢。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工栗柒, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓瞬沦,卻偏偏與公主長(zhǎng)得像太伊,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子逛钻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353