Google Play 區(qū)分
在接入Google Pay吹害,查閱 Api 的時(shí)候,發(fā)現(xiàn)集成方式有2種
- GooglePay:個(gè)人理解的是銷售實(shí)體商品之類的內(nèi)容(理解有誤歡迎拍磚)
- Google Pay Billing:應(yīng)用內(nèi)結(jié)算(進(jìn)行虛擬的商品交易)货葬,下面文字主要說明的是 Billing 接入過程
Google Play Billing 結(jié)算服務(wù)概覽 财搁, 可以用于銷售以下應(yīng)用內(nèi)商品:
- 一次性商品:需要一次性(非定期)向用戶收取相關(guān)費(fèi)用(通過用戶提供的付款方式)的應(yīng)用內(nèi)商品个束。額外游戲關(guān)卡慕购、高級(jí)戰(zhàn)利品盒和媒體文件都屬于一次性商品。Google Play 管理中心將一次性商品稱為“受管理的商品”茬底,Google Play 結(jié)算庫將其稱為“INAPP”沪悲。
- 獎(jiǎng)勵(lì)產(chǎn)品:需要用戶觀看視頻廣告才能獲得的應(yīng)用內(nèi)商品。額外的生命阱表、游戲代幣和定時(shí)任務(wù)快速通關(guān)等都屬于獎(jiǎng)勵(lì)產(chǎn)品殿如。Google Play 管理中心將獎(jiǎng)勵(lì)的產(chǎn)品稱為“獎(jiǎng)勵(lì)產(chǎn)品”,Google Play 結(jié)算庫則將其稱為“INAPP”最爬。
- 訂閱:需要定期向用戶收取相關(guān)費(fèi)用(通過用戶提供的付款方式)的應(yīng)用內(nèi)商品涉馁。在線雜志和音樂在線播放服務(wù)等都屬于訂閱。Google Play 結(jié)算庫將這些訂閱內(nèi)容稱為“SUBS”烂叔。
Google Play Billing 結(jié)算服務(wù)接入
過程大致分為 : 項(xiàng)目集成谨胞、創(chuàng)建商品固歪、應(yīng)用內(nèi)購買蒜鸡、商品消費(fèi)胯努、訂單確認(rèn)
一、項(xiàng)目集成步驟
先上官方demo地址:
集成到 Android Studio 步驟:
- 將以下行添加到應(yīng)用的
build.gradle
文件的依賴項(xiàng)部分:
dependencies {
...
implementation 'com.android.billingclient:billing:2.0.1'
}
- 在
AndroidManifest
中添加下面的權(quán)限
<!-- Google Play 內(nèi)購權(quán)限 -->
<uses-permission android:name="com.android.vending.BILLING" />
經(jīng)過上面的2個(gè)步驟逢防,其實(shí)已經(jīng)集成好了叶沛,后續(xù)就是書寫邏輯了(具體代碼可以參考 官方示例 TrivialDrive_v2,后續(xù)也會(huì)介紹到自己使用過程中遇到的坑忘朝。)
注:現(xiàn)在網(wǎng)上好多文章都是使用的AIDL步驟集成的灰署,不過現(xiàn)在Google好像不推薦了,AIDL使用GooglePay結(jié)算服務(wù)
Android studio 接入的過程比較簡單局嘁,到這里已經(jīng)基本ok了溉箕。
二、商品創(chuàng)建
這里默認(rèn)悦昵,你在Google Pay console 已經(jīng)創(chuàng)建好應(yīng)用了肴茄!商品創(chuàng)建步驟如下:
登錄Google Pay Console ----> 選擇自己的應(yīng)用---->商店發(fā)布---->應(yīng)用內(nèi)商品(如下圖)
比如,創(chuàng)建一個(gè) 受管理的商品
填寫相應(yīng)的信息即可但指,比較重要的有:
- 商品ID:不可重復(fù)寡痰,應(yīng)用使用最多的也就是這個(gè)id
- 狀態(tài):注意選成 有效
- 價(jià)格:這里注意國家地區(qū)的選擇
注:這里創(chuàng)建的商品,都可以根據(jù) Google Api - 查詢應(yīng)用內(nèi)商品接口 進(jìn)行查詢棋凳,后面的文章也會(huì)詳細(xì)介紹(測試階段,可以直接寫死一個(gè))拦坠。
三、應(yīng)用內(nèi)購買剩岳、商品消費(fèi)
這兩個(gè)步驟都是在App應(yīng)用內(nèi)贞滨,調(diào)用相應(yīng)Api來操作,對(duì)官方的Api進(jìn)行了簡單的封裝并且添加了相應(yīng)注釋(如果有誤歡迎拍磚)拍棕,附上代碼:
/**
* Date: 2019/8/13
* create by cuishuxiang
* description:
* <p>
* Google Pay 返回code:{@link com.android.billingclient.api.BillingClient.BillingResponseCode}
* <p>
* Google Pay 商品信息:{@link SkuDetails}
* 1,getPrice() 向用戶顯示折扣價(jià)疲迂,又使用 getOriginalPrice() 顯示商品的原價(jià)。
* 2,getOriginalPriceAmountMicros() - 返回未設(shè)置格式的折扣前 SKU 原價(jià)莫湘。
* 3,getOriginalPrice() - 返回采用其他貨幣格式設(shè)置的原價(jià)逛绵。
* <p>
* 商品類型 : {@link com.android.billingclient.api.BillingClient.FeatureType}
* <p>
* 購買注意事項(xiàng):如果商品購買成功,系統(tǒng)還會(huì)生成購買令牌芽偏,它是一個(gè)唯一標(biāo)識(shí)符隙疚,表示用戶及其所購應(yīng)用內(nèi)商品的商品 ID。
* 您的應(yīng)用可以在用戶設(shè)備上存儲(chǔ)購買令牌忙芒,理想情況下示弓,也可以將購買令牌傳遞到安全的后端服務(wù)器,
* 以便用于驗(yàn)證購買交易及防范欺詐行為呵萨。購買令牌對(duì)于一次性商品的每筆購買交易和每個(gè)獎(jiǎng)勵(lì)產(chǎn)品都是唯一的奏属。
* 不過,由于訂閱是一次性購買并按固定的結(jié)算周期自動(dòng)續(xù)訂潮峦,因此訂閱的購買令牌在各個(gè)結(jié)算周期內(nèi)保持不變囱皿。
* <p>
* 用戶還會(huì)收到包含交易收據(jù)的電子郵件勇婴,其中包含訂單 ID 或交易的唯一 ID。用戶每次購買一次性商品時(shí)嘱腥,
* 都會(huì)收到包含唯一訂單 ID 的電子郵件耕渴。此外,用戶最初購買訂閱時(shí)以及后續(xù)定期自動(dòng)續(xù)訂時(shí)齿兔,也會(huì)收到這樣的電子郵件橱脸。
* 您可以在 Google Play 管理中心內(nèi)使用訂單 ID 來管理退款。有關(guān)詳情分苇,請(qǐng)參閱查看應(yīng)用的訂單和訂閱及辦理退款添诉。
*/
public class BillingClientManager2 {
private static final String TAG = BillingClientManager2.class.getName();
private static BillingClient billingClient;
private static Activity mActivity;
//注意,每次請(qǐng)求前最好判斷是否已經(jīng)連接
private static boolean mIsServiceConnected = false;
/**
* @param activity
* @param listener 這里自己寫了一個(gè)回調(diào)医寿,處理常見的問題
* <p>
* 在調(diào)用購買方法后吻商,Google Play 會(huì)調(diào)用 {@link PurchasesUpdatedListener#onPurchasesUpdated(BillingResult, List)}方法,
* 將購買操作的結(jié)果傳遞給實(shí)現(xiàn) PurchasesUpdatedListener 接口的監(jiān)聽器
*/
public static void init(Activity activity, @NonNull final OnPurchaseCallBack listener) {
billingClient = BillingClient.newBuilder(activity).setListener(new PurchasesUpdatedListener() {
@Override
public void onPurchasesUpdated(BillingResult billingResult, @Nullable List<Purchase> purchases) {
Log.d(TAG, "onPurchasesUpdated: ");
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null) {
/**
* 購買成功
*/
listener.onPaySuccess(purchases);
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) {
// Handle an error caused by a user cancelling the purchase flow.
//處理由用戶取消購買流程引起的錯(cuò)誤
listener.onUserCancel();
} else {
// Handle any other error codes.
listener.responseCode(billingResult.getResponseCode());
}
}
}).enablePendingPurchases().build();
mActivity = activity;
//連接服務(wù)
connectionService();
}
/**
* 連接服務(wù)
*/
public static void connectionService() {
if (billingClient == null)
throw new IllegalArgumentException("Please call init(); first!");
billingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
// The BillingClient is ready. You can query purchases here.
mIsServiceConnected = true;
}
}
@Override
public void onBillingServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
mIsServiceConnected = false;
}
});
}
/**
* 要異步查詢商品詳情糟红,應(yīng)用會(huì)使用您在 Google Play 管理中心內(nèi)配置商品時(shí)定義的商品 ID艾帐。
*
* @param itemType 針對(duì)一次性商品或獎(jiǎng)勵(lì)產(chǎn)品:SkuType.INAPP ; 訂閱:SkuType.SUBS
* @param skuList 指定產(chǎn)品 ID 字符串列表
* @param listener
*/
public static void querySkuDetailsAsync(@BillingClient.SkuType String itemType,
SkuDetailsResponseListener listener, @NonNull String... skuList) {
if (billingClient == null)
throw new IllegalArgumentException("querySkuDetailsAsync(); error . Please call init(); first!");
//判斷是否連接
if (!mIsServiceConnected) connectionService();
SkuDetailsParams skuDetailsParams = SkuDetailsParams.newBuilder()
.setType(itemType)
.setSkusList(Arrays.asList(skuList))//轉(zhuǎn)換成數(shù)組
.build();
billingClient.querySkuDetailsAsync(skuDetailsParams, listener);
}
/**
* 啟動(dòng)應(yīng)用內(nèi)商品的購買
*
* @param skuDetails 這里商品詳情盆偿,從 querySkuDetailsAsync(); 查詢
* @return 方法會(huì)返回 BillingClient.BillingResponse 中列出的幾個(gè)響應(yīng)代碼之一
*/
public static BillingResult launchBillingFlow(@NonNull SkuDetails skuDetails) {
if (mActivity == null || billingClient == null)
throw new IllegalArgumentException("launchBillingFlow(); error . Please call init(); first!");
//判斷是否連接
if (!mIsServiceConnected) connectionService();
BillingFlowParams flowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
.build();
return billingClient.launchBillingFlow(mActivity, flowParams);
}
/**
* Android 手機(jī)安裝的 Google Play 商店應(yīng)用可能是舊版的柒爸,不支持訂閱等商品類型。
* 因此事扭,在應(yīng)用進(jìn)入結(jié)算流程之前捎稚,請(qǐng)調(diào)用 isFeatureSupported()
* 以檢查設(shè)備是否支持您要銷售的商品。如需查看商品類型的列表求橄,請(qǐng)參閱 BillingClient.FeatureType今野。
*
* @param feature
* @return
*/
public static boolean isFeatureSupported(@BillingClient.FeatureType String feature) {
if (billingClient == null)
throw new IllegalArgumentException("isFeatureSupported(); error . Please call init(); first!");
//判斷是否連接
if (!mIsServiceConnected) connectionService();
BillingResult result = billingClient.isFeatureSupported(feature);
if (result.getResponseCode() == BillingClient.BillingResponseCode.OK) {
return true;
} else {
Log.e(TAG, "isFeatureSupported: isFeatureSupported = false , errorMsg : " + result.getDebugMessage());
return false;
}
}
/**
* 確認(rèn)、消費(fèi)一次性商品交易
* <p>
* 警告罐农! 所有購買都需要確認(rèn)条霜。 未能確認(rèn)購買將導(dǎo)致購買退款。 對(duì)于一次性產(chǎn)品涵亏,請(qǐng)確保使用此方法作為隱式確認(rèn)宰睡,
* 或者您可以通過{@link BillingClient#acknowledgePurchase(AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)} 明確確認(rèn)購買。
* 對(duì)于訂閱气筋,請(qǐng)使用{@link #acknowledgePurchase)拆内。
* 有關(guān)詳細(xì)信息,請(qǐng)參閱https://developer.android.com/google/play/billing/billing_library_overview#acknowledge宠默。
*/
public static void consumeAsync(@NonNull Purchase purchase, ConsumeResponseListener listener) {
if (billingClient == null)
throw new IllegalArgumentException("consumeAsync(); error . Please call init(); first!");
//判斷是否連接
if (!mIsServiceConnected) connectionService();
//Purchase 對(duì)象包含 isAcknowledged() 方法麸恍,該方法會(huì)指示購買交易是否已得到確認(rèn)
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED
&& !purchase.isAcknowledged()) {
ConsumeParams consumeParams = ConsumeParams
.newBuilder()
// .setDeveloperPayload(purchase.getDeveloperPayload())//指定開發(fā)人員有效負(fù)載與購買信息一起發(fā)回。
.setPurchaseToken(purchase.getPurchaseToken())//指定標(biāo)識(shí)要使用的購買的標(biāo)記搀矫。
.build();
billingClient.consumeAsync(consumeParams, listener);
}
}
/**
* 確認(rèn)“訂閱商品”交易
* <p>
* <p>
* 消費(fèi)“費(fèi)消耗品” 還可以使用服務(wù)器 API 中新增的 acknowledge() 方法抹沪。
*/
public static void acknowledgePurchase(@NonNull Purchase purchase, AcknowledgePurchaseResponseListener listener) {
if (billingClient == null)
throw new IllegalArgumentException("acknowledgePurchase(); error . Please call init(); first!");
//判斷是否連接
if (!mIsServiceConnected) connectionService();
//Purchase 對(duì)象包含 isAcknowledged() 方法刻肄,該方法會(huì)指示購買交易是否已得到確認(rèn)
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED
&& !purchase.isAcknowledged()) {
AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams
.newBuilder()
// .setDeveloperPayload(purchase.getDeveloperPayload())//這個(gè)參數(shù)不確定是否需要
.setPurchaseToken(purchase.getPurchaseToken())
.build();
billingClient.acknowledgePurchase(acknowledgePurchaseParams, listener);
}
}
/**
* 用戶通過應(yīng)用發(fā)起的購買交易的相關(guān)信息(使用 Google Play 商店應(yīng)用的緩存)
*
* @param type 購買類型(SkuType.INAPP 或 SkuType.SUBS)
* @return 注意:
* 在每次啟動(dòng)您的應(yīng)用時(shí)都調(diào)用 queryPurchases(),
* 以便您可以恢復(fù)用戶自應(yīng)用上次停止以來發(fā)起的任何購買交易采够。
* 在 onResume() 方法中調(diào)用 queryPurchases()肄方,
* 因?yàn)楫?dāng)您的應(yīng)用在后臺(tái)時(shí)冰垄,用戶可能會(huì)發(fā)起購買交易(例如蹬癌,在 Google Play 商店應(yīng)用中兌換促銷代碼)。
* <p>
* queryPurchases() 方法使用 Google Play 商店應(yīng)用的緩存虹茶,而不發(fā)起網(wǎng)絡(luò)請(qǐng)求逝薪。
* <p>
* 如果您需要查看用戶對(duì)每個(gè)商品 ID 發(fā)起的最近一筆購買交易,您可以使用 queryPurchaseHistoryAsync()
*/
public static List<Purchase> queryPurchases(@BillingClient.SkuType String type) {
if (billingClient == null)
throw new IllegalArgumentException("acknowledgePurchase(); error . Please call init(); first!");
Purchase.PurchasesResult result = billingClient.queryPurchases(type);
if (result.getResponseCode() == BillingClient.BillingResponseCode.OK) {
// BillingResult billingResult = result.getBillingResult();
return result.getPurchasesList();
}
return null;
}
/**
* 查詢最近的購買交易(網(wǎng)絡(luò))
*
* @param type
* @param listener 注意: 該方法走網(wǎng)絡(luò)
* 如果使用 queryPurchaseHistoryAsync()蝴罪,您也可以將其與刷新按鈕結(jié)合使用董济,使用戶能更新其購買交易列表。
*/
public static void queryPurchaseHistoryAsync(@BillingClient.SkuType String type, PurchaseHistoryResponseListener listener) {
if (billingClient == null)
throw new IllegalArgumentException("acknowledgePurchase(); error . Please call init(); first!");
final List<PurchaseHistoryRecord> purchaseHistoryRecords = new ArrayList<>();
billingClient.queryPurchaseHistoryAsync(type, listener);
}
}
上面的代碼要门,對(duì)Api進(jìn)行簡單的封裝虏肾,使用前先調(diào)用 init
方法,具體使用例如:查詢應(yīng)用內(nèi)商品詳情欢搜,調(diào)用這個(gè)方法即可封豪,最后不定長參數(shù)傳入上面的 商品id 即可
/**
* 要異步查詢商品詳情,應(yīng)用會(huì)使用您在 Google Play 管理中心內(nèi)配置商品時(shí)定義的商品 ID炒瘟。
*
* @param itemType 針對(duì)一次性商品或獎(jiǎng)勵(lì)產(chǎn)品:SkuType.INAPP 吹埠; 訂閱:SkuType.SUBS
* @param skuList 指定產(chǎn)品 ID 字符串列表
* @param listener
*/
public static void querySkuDetailsAsync(@BillingClient.SkuType String itemType,
SkuDetailsResponseListener listener, @NonNull String... skuList) {
if (billingClient == null)
throw new IllegalArgumentException("querySkuDetailsAsync(); error . Please call init(); first!");
//判斷是否連接
if (!mIsServiceConnected) connectionService();
SkuDetailsParams skuDetailsParams = SkuDetailsParams.newBuilder()
.setType(itemType)
.setSkusList(Arrays.asList(skuList))//轉(zhuǎn)換成數(shù)組
.build();
billingClient.querySkuDetailsAsync(skuDetailsParams, listener);
}
在使用過程中,發(fā)現(xiàn)一個(gè)比較好用的三方庫:https://github.com/anjlab/android-inapp-billing-v3 疮装, 對(duì)這個(gè)庫相應(yīng)的 Api 也進(jìn)行了相應(yīng)的封裝缘琅,附上代碼:
/**
* Date: 2019/8/13
* create by cuishuxiang
* description: 管理類
*
* tp: 1,需要調(diào)用初始化方法{@link BillingManager#init(Activity, String, BillingProcessor.IBillingHandler)}
* 2,具體的操作,需要使用到{@link BillingProcessor},這里也提供了{(lán)@link BillingManager#getBillingProcessor()}來獲取實(shí)例
*
* 注意:下面的信息可能會(huì)用到
* 1, 處理已取消的訂閱
* 調(diào)用bp.getSubscriptionTransactionDetails(...)并檢查purchaseInfo.purchaseData.autoRenewing標(biāo)志廓推。
* 訂閱取消后刷袍,它將設(shè)置為False。
* 另請(qǐng)注意樊展,您需要定期調(diào)用bp.loadOwnedPurchasesFromGoogle()方法才能更新訂閱信息
* 2, 促銷代碼支持
* 您可以使用促銷代碼和此庫做个。 促銷代碼可以在購買對(duì)話框或Google Play應(yīng)用中輸入。
* 網(wǎng)址https://play.google.com/redeem?code=YOUR_PROMO_CODE將啟動(dòng)已添加促銷代碼的Google Play應(yīng)用滚局。
* 如果您想讓用戶選擇在您的應(yīng)用中輸入促銷代碼居暖,這可能會(huì)派上用場。
*
* 3,錯(cuò)誤碼查閱參考:{@link Constants}
*
* 參考:https://github.com/anjlab/android-inapp-billing-v3/blob/master/README.md
*/
public class BillingManager {
private static final String TAG = "BillingManager";
private static BillingProcessor bp;
private static Activity mActivity;
private static String mLicenseKey;
/**
* 初始化方法藤肢,需要先調(diào)用這個(gè)方法
*
* @param activity
* @param licenseKey
*/
public static void init(Activity activity, String licenseKey, BillingProcessor.IBillingHandler iBillingHandler) {
mActivity = activity;
mLicenseKey = licenseKey;
bp = BillingProcessor.newBillingProcessor(activity, licenseKey, iBillingHandler);
//商戶id獲得:GooglePayConsole后臺(tái)--->設(shè)置---->付款設(shè)置(注意太闺,商家id需要放置到安全的地方)
// bp = BillingProcessor.newBillingProcessor(activity, licenseKey, "商戶id", iBillingHandler);
bp.initialize();
}
public static BillingProcessor getBillingProcessor() {
return bp;
}
/**
* 在使用之前,最好檢查應(yīng)用內(nèi)的結(jié)算服務(wù)可用性嘁圈。 在某些舊設(shè)備或中國設(shè)備中省骂,可能會(huì)出現(xiàn)Play Market不可用或已棄用且不支持應(yīng)用內(nèi)結(jié)算的情況蟀淮。
*
* @return true 可用; false:不可用
*/
public static boolean isPayServiceAvailable() {
if (mActivity == null)
throw new IllegalArgumentException("isPayServiceAvailable() error. Call the init method first , Please check it!");
return BillingProcessor.isIabServiceAvailable(mActivity);
}
/**
* 請(qǐng)注意钞澳,調(diào)用BillingProcessor.isIabServiceAvailable()(僅檢查是否安裝了Play Market應(yīng)用程序)是不夠的怠惶,
* 因?yàn)榭赡艽嬖诜祷豻rue但仍然無法付款的情況。
* <p>
* 因此轧粟,最好在初始化BillingProcessor之后調(diào)用isOneTimePurchaseSupported():
*
* @return 最好true的時(shí)候策治,調(diào)用支付流程
*/
public static boolean isPurchaseSupported() {
if (bp == null)
throw new IllegalArgumentException("isPurchaseSupported() error . Call the init method first , Please check it!");
return bp.isOneTimePurchaseSupported();
}
/**
* 檢測是否支持訂閱
*
* @return
*/
public static boolean isSubscribeUpdateSupported() {
if (bp == null)
throw new IllegalArgumentException("isSubscriptionUpdateSupported() error . Call the init method first , Please check it!");
return bp.isSubscriptionUpdateSupported();
}
/**
* 購買方法
*
* @param purchaseId id
*/
public static boolean purchase(String purchaseId) {
if (mActivity == null || bp == null)
throw new IllegalArgumentException("Call the init method first , Please check it!");
//檢測服務(wù)是否可用
if (!isPayServiceAvailable()) {
Log.e(TAG, "purchase: 服務(wù)不可用,請(qǐng)檢查!");
return false;
}
//檢測是否支持購買
if (!isPurchaseSupported()) {
Log.e(TAG, "purchase: 不支持購買兰吟,請(qǐng)檢查!");
return false;
}
return bp.purchase(mActivity, purchaseId);
}
/**
* 暫時(shí)不知道 "developerPayload" 什么意思
* <p>
* 重要信息:當(dāng)您提供有效負(fù)載時(shí)通惫,庫內(nèi)部會(huì)為您的負(fù)載預(yù)先添加一個(gè)字符串。
* 對(duì)于訂閱混蔼,它前綴為“subs:\ <productId \>:”履腋,
* 對(duì)于產(chǎn)品,它預(yù)先添加“inapp:\ <productId \>:\ <UUID \>:”惭嚣。
* <p>
* 了解您是否對(duì)成功購買后從Google Play返回的有效內(nèi)容進(jìn)行了任何驗(yàn)證遵湖,這一點(diǎn)非常重要。
*
* @param productId
* @param developerPayload
* @param extraParams 放置參數(shù)如下所示
* @return
*/
public static boolean purchase(String productId, String developerPayload, Bundle extraParams) {
/**
* Bundle extraParams = new Bundle()
* extraParams.putString("accountId", "MY_ACCOUNT_ID");
*/
if (mActivity == null || bp == null)
throw new IllegalArgumentException("purchase() error . Call the init method first , Please check it!");
//檢測服務(wù)是否可用
if (!isPayServiceAvailable()) {
Log.e(TAG, "purchase: 服務(wù)不可用晚吞,請(qǐng)檢查!");
return false;
}
//檢測是否支持購買
if (!isPurchaseSupported()) {
Log.e(TAG, "purchase: 不支持購買延旧,請(qǐng)檢查!");
return false;
}
return bp.subscribe(mActivity, productId, developerPayload, extraParams);
}
/**
* 訂閱方法
*
* @param purchaseId
*/
public static boolean subscribe(String purchaseId) {
if (mActivity == null || bp == null)
throw new IllegalArgumentException("subscribe() error . Call the init method first , Please check it!");
//檢測服務(wù)是否可用
if (!isPayServiceAvailable()) {
Log.e(TAG, "subscribe: 服務(wù)不可用,請(qǐng)檢查!");
return false;
}
//檢測是否支持購買
if(!isPurchaseSupported()){
Log.e(TAG, "subscribe: 不支持購買载矿,請(qǐng)檢查!");
return false;
}
return bp.subscribe(mActivity, purchaseId);
//注意:還有一個(gè) 三個(gè)參數(shù)的負(fù)載垄潮,暫時(shí)不知道什么意思
// bp.subscribe(mActivity, purchaseId, "");
}
/**
* 訂閱方法 (developerPayload 負(fù)載,暫時(shí)不知道什么意思)
* <p>
* 重要信息:當(dāng)您提供有效負(fù)載時(shí)闷盔,庫內(nèi)部會(huì)為您的負(fù)載預(yù)先添加一個(gè)字符串弯洗。
* 對(duì)于訂閱,它前綴為“subs:\ <productId \>:”逢勾,
* 對(duì)于產(chǎn)品牡整,它預(yù)先添加“inapp:\ <productId \>:\ <UUID \>:”。
*
* @param purchaseId
* @param developerPayload
* @param extraParams
* @return
*/
public static boolean subscribe(String purchaseId, String developerPayload, Bundle extraParams) {
/**
* Bundle extraParams = new Bundle()
* extraParams.putString("accountId", "MY_ACCOUNT_ID");
*/
if (mActivity == null || bp == null)
throw new IllegalArgumentException("subscribe() error . Call the init method first , Please check it!");
//檢測服務(wù)是否可用
if (!isPayServiceAvailable()) {
Log.e(TAG, "subscribe: 服務(wù)不可用溺拱,請(qǐng)檢查!");
return false;
}
//檢測是否支持購買
if(!isPurchaseSupported()){
Log.e(TAG, "subscribe: 不支持購買,請(qǐng)檢查!");
return false;
}
return bp.subscribe(mActivity, purchaseId, developerPayload, extraParams);
}
/**
* 消費(fèi)購買的商品
*
* 注:您可以調(diào)用該方法沐扳,隨時(shí)消費(fèi)購買并允許多次購買相同的產(chǎn)品
* @param purchaseId
* @return
*/
public static boolean consumePurchase(String purchaseId) {
if ( bp == null)
throw new IllegalArgumentException("consumePurchase() error . Call the init method first , Please check it!");
return bp.consumePurchase(purchaseId);
}
/**
* 商品詳情
* @param productId
* @return
*/
public static SkuDetails getSkuDetail(String productId) {
if ( bp == null)
throw new IllegalArgumentException("getSkuDetail() error . Call the init method first , Please check it!");
return bp.getPurchaseListingDetails(productId);
}
public static List<SkuDetails> getSkuDetailList(ArrayList<String> productIdList) {
if ( bp == null)
throw new IllegalArgumentException("getSkuDetail() error . Call the init method first , Please check it!");
return bp.getPurchaseListingDetails(productIdList);
}
/**
* 獲得交易詳情(商品)
* @param productId
* @return
*/
public static TransactionDetails getPurchaseTransactionDetails(String productId) {
if ( bp == null)
throw new IllegalArgumentException("getPurchaseTransactionDetails() error . Call the init method first , Please check it!");
return bp.getPurchaseTransactionDetails(productId);
}
/**
* 獲得交易詳情(訂閱)
* @param productId
* @return
*/
public static TransactionDetails getSubscribeTransactionDetails(String productId) {
if ( bp == null)
throw new IllegalArgumentException("getSubscribeTransactionDetails() error . Call the init method first , Please check it!");
return bp.getSubscriptionTransactionDetails(productId);
}
/**
* 獲得 應(yīng)用內(nèi)商品 購買歷史記錄
* @param extraParams
* @return
*/
public static List<BillingHistoryRecord> getInappHistory(Bundle extraParams) {
if ( bp == null)
throw new IllegalArgumentException("getInappHistory() error . Call the init method first , Please check it!");
try {
//請(qǐng)注意句占,此API需要版本6或更高版本的結(jié)算API,因此您應(yīng)該事先檢查是否支持它:
if (!bp.isRequestBillingHistorySupported(Constants.PRODUCT_TYPE_MANAGED)) {
Log.e(TAG, "getInappHistory: isRequestBillingHistorySupported 版本不支持:");
return null;
}
return bp.getPurchaseHistory(Constants.PRODUCT_TYPE_MANAGED, extraParams);
} catch (BillingCommunicationException e) {
e.printStackTrace();
Log.e(TAG, "getInappHistory: 異常:" + e);
return null;
}
}
/**
* 獲得 訂閱商品 購買歷史記錄
* @param extraParams
* @return
*/
public static List<BillingHistoryRecord> getSubscribeHistory(Bundle extraParams) {
if ( bp == null)
throw new IllegalArgumentException("getSubscribeHistory() error . Call the init method first , Please check it!");
try {
//請(qǐng)注意杨拐,此API需要版本6或更高版本的結(jié)算API祈餐,因此您應(yīng)該事先檢查是否支持它:
if (!bp.isRequestBillingHistorySupported(Constants.PRODUCT_TYPE_SUBSCRIPTION)) {
Log.e(TAG, "getInappHistory: getSubscribeHistory 版本不支持:");
return null;
}
return bp.getPurchaseHistory(Constants.PRODUCT_TYPE_SUBSCRIPTION, extraParams);
} catch (BillingCommunicationException e) {
e.printStackTrace();
Log.e(TAG, "getSubscribeHistory: 異常:" + e);
return null;
}
}
/**
* 恢復(fù)購買和訂閱
* @return
*/
public static boolean restore() {
if ( bp == null)
throw new IllegalArgumentException("restore() error . Call the init method first , Please check it!");
return bp.loadOwnedPurchasesFromGoogle();
}
/**
* 檢查交易有效性 (調(diào)用該方法,在初始化 BillingProcessor 需要設(shè)置商家id)
* @param transactionDetails
* @return
*
*
* 安全性 參考:https://developer.android.com/google/play/billing/billing_best_practices.html#validating-purchase-device
*/
public static boolean isValid(TransactionDetails transactionDetails) {
if ( bp == null)
throw new IllegalArgumentException("isValid() error . Call the init method first , Please check it!");
return bp.isValidTransactionDetails(transactionDetails);
}
/**
* 用于接收回調(diào)帆阳,在Activity可以這樣調(diào)用屋吨,示例:
* @Override
* protected void onActivityResult(int requestCode, int resultCode, Intent data) {
* if (!bp.handleActivityResult(requestCode, resultCode, data))
* super.onActivityResult(requestCode, resultCode, data);
* }
*/
public static boolean handleActivityResult(int requestCode, int resultCode, Intent data){
return bp.handleActivityResult(requestCode, resultCode, data);
}
/**
* 在Activity onDestroy 調(diào)用該方法
*/
public static void release() {
if (bp != null) {
bp.release();
bp = null;
}
}
}
上面有兩個(gè)封裝离赫,一個(gè)基于三方庫的塌碌、一個(gè)是對(duì)Google原生Api封裝台妆,已經(jīng)親測,都可以使用看需挑選吧G欣濉懊缺!如果要是哪里有問題鹃两,歡迎拍磚!途蒋!
后續(xù)的訂單驗(yàn)證步驟馋记,可以參考我的另一篇:Google Play 訂單驗(yàn)證
需要調(diào)用Google Api 坑有點(diǎn)多L菪选H紫啊!!