1. 需要在google play console后台注冊開發者賬號,配置相關內購的商品等這是屬於運營來做
2. 在項目build.gradle文件添加
implementation 'com.google.android.gms:play-services-wallet:18.1.3' implementation 'com.android.billingclient:billing:3.0.3'
3.這邊是參考了網上的資料封裝的一個google支付工具類,這個類只支持4.0之前的google支付sdk,4.0的支付sdk有大的調整,這個暫時沒做兼容。后續有時間會寫一個兼容4.0的
public class GoogleBillingUtil { private static final String TAG = "```GoogleBillingUtil"; private static final boolean IS_DEBUG = true; private static String[] inAppSKUS; private String[] subsSKUS = new String[]{"6"};//訂閱ID,必填 public static final String BILLING_TYPE_INAPP = BillingClient.SkuType.INAPP;//內購 public static final String BILLING_TYPE_SUBS = BillingClient.SkuType.SUBS;//訂閱 private static BillingClient mBillingClient; private static BillingClient.Builder builder ; private static OnPurchaseFinishedListener mOnPurchaseFinishedListener; private static OnStartSetupFinishedListener mOnStartSetupFinishedListener ; private static OnQueryFinishedListener mOnQueryFinishedListener; private boolean isAutoConsumeAsync = true;//是否在購買成功后自動消耗商品 private static final GoogleBillingUtil mGoogleBillingUtil = new GoogleBillingUtil() ; private GoogleBillingUtil() { } public static GoogleBillingUtil getInstance(String productId) { //googleplay應用內商品欄,添加商品后得到 inAppSKUS = new String[]{productId};//內購ID,必填 cleanListener(); return mGoogleBillingUtil; } public GoogleBillingUtil build(Context context) { if(mBillingClient==null) { synchronized (mGoogleBillingUtil) { if(mBillingClient==null) { if(isGooglePlayServicesAvailable(context)) { builder = BillingClient.newBuilder(context); mBillingClient = builder.setListener(mGoogleBillingUtil.new MyPurchasesUpdatedListener()).enablePendingPurchases().build(); } else { if(IS_DEBUG) { log("警告:GooglePlay服務處於不可用狀態,請檢查"); } if(mOnStartSetupFinishedListener!=null) { mOnStartSetupFinishedListener.onSetupError(); } } } else { builder.setListener(mGoogleBillingUtil.new MyPurchasesUpdatedListener()); } } } else { builder.setListener(mGoogleBillingUtil.new MyPurchasesUpdatedListener()); } synchronized (mGoogleBillingUtil) { if(mGoogleBillingUtil.startConnection()) { mGoogleBillingUtil.queryInventoryInApp(); // mGoogleBillingUtil.queryInventorySubs(); mGoogleBillingUtil.queryPurchasesInApp(); } } return mGoogleBillingUtil; } public boolean startConnection() { if(mBillingClient==null) { log("初始化失敗:mBillingClient==null"); return false; } if(!mBillingClient.isReady()) { mBillingClient.startConnection(new BillingClientStateListener() { @Override public void onBillingSetupFinished(@NonNull BillingResult billingResult) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { queryInventoryInApp(); // queryInventorySubs(); queryPurchasesInApp(); if(mOnStartSetupFinishedListener!=null) { mOnStartSetupFinishedListener.onSetupSuccess(); } } else { log("初始化失敗:onSetupFail:code="+billingResult.getResponseCode()); if(mOnStartSetupFinishedListener!=null) { mOnStartSetupFinishedListener.onSetupFail(billingResult.getResponseCode()); } } } @Override public void onBillingServiceDisconnected() { if(mOnStartSetupFinishedListener!=null) { mOnStartSetupFinishedListener.onSetupError(); } log("初始化失敗:onBillingServiceDisconnected"); } }); return false; } else { return true; } } /** * Google購買商品回調接口(訂閱和內購都走這個接口) */ private class MyPurchasesUpdatedListener implements PurchasesUpdatedListener { @Override public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> list) { if(mOnPurchaseFinishedListener==null) { if(IS_DEBUG) { log("警告:接收到購買回調,但購買商品接口為Null,請設置購買接口。eg:setOnPurchaseFinishedListener()"); } return ; } if(billingResult.getResponseCode()== BillingClient.BillingResponseCode.OK&&list!=null) { if(isAutoConsumeAsync) { //消耗商品 for(Purchase purchase:list) { // ArrayList<String> sku = purchase.getSkus(); String sku = purchase.getSku(); if(sku!=null) { // String skuType = getSkuType(sku.get(0)); String skuType = getSkuType(sku); if(skuType!=null) { if(skuType.equals(BillingClient.SkuType.INAPP)) { consumeAsync(purchase.getPurchaseToken()); } } } } } mOnPurchaseFinishedListener.onPurchaseSuccess(list); } else { mOnPurchaseFinishedListener.onPurchaseFail(billingResult.getResponseCode()); } } } /** * 查詢內購商品信息 */ public void queryInventoryInApp() { queryInventory(BillingClient.SkuType.INAPP); } /** * 查詢訂閱商品信息 */ public void queryInventorySubs() { queryInventory(BillingClient.SkuType.SUBS); } private void queryInventory(final String skuType) { Runnable runnable = new Runnable() { @Override public void run() { if (mBillingClient == null) { if(mOnQueryFinishedListener!=null) { mOnQueryFinishedListener.onQueryError(); } return ; } ArrayList<String> skuList = new ArrayList<>(); if(skuType.equals(BillingClient.SkuType.INAPP)) { Collections.addAll(skuList, inAppSKUS); } else if(skuType.equals(BillingClient.SkuType.SUBS)) { Collections.addAll(skuList, subsSKUS); } SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); params.setSkusList(skuList).setType(skuType); mBillingClient.querySkuDetailsAsync(params.build(),new MySkuDetailsResponseListener(mOnQueryFinishedListener,skuType)); } }; executeServiceRequest(runnable); } /** * Google查詢商品信息回調接口 */ private class MySkuDetailsResponseListener implements SkuDetailsResponseListener { private OnQueryFinishedListener mOnQueryFinishedListener ; private String skuType ; private List<SkuDetails> list=new ArrayList<>(); public MySkuDetailsResponseListener(OnQueryFinishedListener onQueryFinishedListener,String skuType) { mOnQueryFinishedListener = onQueryFinishedListener; this.skuType = skuType; } @Override public void onSkuDetailsResponse(@NonNull BillingResult billingResult, @Nullable List<SkuDetails> list) { this.list=list; if(mOnQueryFinishedListener==null) { if(IS_DEBUG) { log("警告:接收到查詢商品回調,但查詢商品接口為Null,請設置購買接口。eg:setOnQueryFinishedListener()"); } return ; } if(billingResult.getResponseCode()== BillingClient.BillingResponseCode.OK&&list!=null) { mOnQueryFinishedListener.onQuerySuccess(skuType,list); } else { mOnQueryFinishedListener.onQueryFail(billingResult.getResponseCode()); } } } /** * 發起內購 * @param skuId * @return */ public void purchaseInApp(Activity activity,SkuDetails skuId) { purchase(activity,skuId, BillingClient.SkuType.INAPP); } /** * 發起訂閱 * @param skuId * @return */ public void purchaseSubs(Activity activity,SkuDetails skuId) { purchase(activity,skuId, BillingClient.SkuType.SUBS); } private void purchase(Activity activity,final SkuDetails skuId,final String skuType) { if(mBillingClient==null) { if(mOnPurchaseFinishedListener!=null) { mOnPurchaseFinishedListener.onPurchaseError(); } return ; } if(startConnection()) { BillingFlowParams flowParams = BillingFlowParams.newBuilder() .setSkuDetails(skuId) .build(); mBillingClient.launchBillingFlow(activity,flowParams); } else { if(mOnPurchaseFinishedListener!=null) { mOnPurchaseFinishedListener.onPurchaseError(); } } } /** * 消耗商品 * @param purchaseToken */ public void consumeAsync(String purchaseToken) { if(mBillingClient==null) { return ; } ConsumeParams consumeParams = ConsumeParams.newBuilder() .setPurchaseToken(purchaseToken) .build(); mBillingClient.consumeAsync(consumeParams, new MyConsumeResponseListener()); } /** * Googlg消耗商品回調 */ private class MyConsumeResponseListener implements ConsumeResponseListener { @Override public void onConsumeResponse(@NonNull BillingResult billingResult, @NonNull String s) { if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { Log.e("googlePayWay","消耗成功"); } } } /** * 獲取已經內購的商品 * @return */ public List<Purchase> queryPurchasesInApp() { return queryPurchases(BillingClient.SkuType.INAPP); } /** * 獲取已經訂閱的商品 * @return */ public List<Purchase> queryPurchasesSubs() { return queryPurchases(BillingClient.SkuType.SUBS); } private List<Purchase> queryPurchases(String skuType) { if(mBillingClient==null) { return null; } if(!mBillingClient.isReady()) { startConnection(); } else { Purchase.PurchasesResult purchasesResult = mBillingClient.queryPurchases(skuType); if(purchasesResult!=null) { if(purchasesResult.getResponseCode()== BillingClient.BillingResponseCode.OK) { List<Purchase> purchaseList = purchasesResult.getPurchasesList(); if(isAutoConsumeAsync) { if(purchaseList!=null) { for(Purchase purchase:purchaseList) { if(skuType.equals(BillingClient.SkuType.INAPP)) { consumeAsync(purchase.getPurchaseToken()); } } } } return purchaseList; } } } return null; } /** * 獲取有效訂閱的數量 * @return -1查詢失敗,0沒有有效訂閱,>0具有有效的訂閱 */ public int getPurchasesSizeSubs() { List<Purchase> list = queryPurchasesSubs(); if(list!=null) { return list.size(); } return -1; } /** * 通過sku獲取訂閱商品序號 * @param sku * @return */ public int getSubsPositionBySku(String sku) { return getPositionBySku(sku, BillingClient.SkuType.SUBS); } /** * 通過sku獲取內購商品序號 * @param sku * @return 成功返回需要 失敗返回-1 */ public int getInAppPositionBySku(String sku) { return getPositionBySku(sku, BillingClient.SkuType.INAPP); } private int getPositionBySku(String sku,String skuType) { if(skuType.equals(BillingClient.SkuType.INAPP)) { int i = 0; for(String s:inAppSKUS) { if(s.equals(sku)) { return i; } i++; } } else if(skuType.equals(BillingClient.SkuType.SUBS)) { int i = 0; for(String s:subsSKUS) { if(s.equals(sku)) { return i; } i++; } } return -1; } private void executeServiceRequest(final Runnable runnable) { if(startConnection()) { runnable.run(); } } /** * 通過序號獲取訂閱sku * @param position * @return */ public String getSubsSkuByPosition(int position) { if(position>=0&&position<subsSKUS.length) { return subsSKUS[position]; } else { return null; } } /** * 通過序號獲取內購sku * @param position * @return */ public String getInAppSkuByPosition(int position) { if(position>=0&&position<inAppSKUS.length) { return inAppSKUS[position]; } else { return null; } } /** * 通過sku獲取商品類型(訂閱獲取內購) * @param sku * @return inapp內購,subs訂閱 */ private String getSkuType(String sku) { if(Arrays.asList(inAppSKUS).contains(sku)) { return BillingClient.SkuType.INAPP; } else if(Arrays.asList(subsSKUS).contains(sku)) { return BillingClient.SkuType.SUBS; } return null; } /** * 檢測GooglePlay服務是否可用(需要導入包api "com.google.android.gms:play-services-location:11.8.0",也可以不檢查,跳過這個代碼) * @param context * @return */ public static boolean isGooglePlayServicesAvailable(Context context) { GoogleApiAvailability googleApiAvailability = GoogleApiAvailability.getInstance(); if(googleApiAvailability!=null) { int resultCode = googleApiAvailability.isGooglePlayServicesAvailable(context); return resultCode == ConnectionResult.SUCCESS; } return false; // return true;//不檢查直接跳過 } public GoogleBillingUtil setOnQueryFinishedListener(OnQueryFinishedListener onQueryFinishedListener) { mOnQueryFinishedListener = onQueryFinishedListener; return mGoogleBillingUtil; } public GoogleBillingUtil setOnPurchaseFinishedListener(OnPurchaseFinishedListener onPurchaseFinishedListener) { mOnPurchaseFinishedListener = onPurchaseFinishedListener; return mGoogleBillingUtil; } public OnStartSetupFinishedListener getOnStartSetupFinishedListener() { return mOnStartSetupFinishedListener; } public GoogleBillingUtil setOnStartSetupFinishedListener(OnStartSetupFinishedListener onStartSetupFinishedListener) { mOnStartSetupFinishedListener = onStartSetupFinishedListener; return mGoogleBillingUtil; } /** * 本工具查詢回調接口 */ public interface OnQueryFinishedListener{ //Inapp和sub都走這個接口查詢的時候一定要判斷skuType public void onQuerySuccess(String skuType, List<SkuDetails> list); public void onQueryFail(int responseCode); public void onQueryError(); } /** * 本工具購買回調接口(內購與訂閱都走這接口) */ public interface OnPurchaseFinishedListener{ public void onPurchaseSuccess(List<Purchase> list); public void onPurchaseFail(int responseCode); public void onPurchaseError(); } /** * google服務啟動接口 */ public interface OnStartSetupFinishedListener{ public void onSetupSuccess(); public void onSetupFail(int responseCode); public void onSetupError(); } public boolean isReady() { return mBillingClient!=null&&mBillingClient.isReady(); } public boolean isAutoConsumeAsync() { return isAutoConsumeAsync; } public void setIsAutoConsumeAsync(boolean isAutoConsumeAsync) { this.isAutoConsumeAsync= isAutoConsumeAsync; } /** * 清除所有監聽器,防止內存泄漏 * 如果有多個頁面使用了支付,需要確保上個頁面的cleanListener在下一個頁面的GoogleBillingUtil.getInstance()前使用。 * 所以不建議放在onDestory里調用 */ public static void cleanListener() { mOnPurchaseFinishedListener = null; mOnQueryFinishedListener = null; mOnStartSetupFinishedListener = null; if(builder!=null) { builder.setListener(null); } } /** * 斷開連接google服務 * 注意!!!一般情況不建議調用該方法,讓google保留連接是最好的選擇。 */ public static void endConnection() { //注意!!!一般情況不建議調用該方法,讓google保留連接是最好的選擇。 if(mBillingClient!=null) { if(mBillingClient.isReady()) { mBillingClient.endConnection(); mBillingClient = null; } } } private static void log(String msg) { if(IS_DEBUG) { Log.e(TAG,msg); } } /** * 是否支持內購 */ public boolean isIabServiceAvailable(Context context) { final PackageManager packageManager = context.getPackageManager(); List<ResolveInfo> list = packageManager.queryIntentServices(getBindServiceIntent(), 0); return list != null && list.size() > 0; } private Intent getBindServiceIntent() { Intent intent = new Intent("com.android.vending.billing.InAppBillingService.BIND"); intent.setPackage("com.android.vending"); return intent; } }
4.如何使用
首先需要定義三個類來實現購買回調接口,查詢商品回調接口,服務初始化結果回調接口
//服務初始化結果回調接口 private class MyOnStartSetupFinishedListener implements GoogleBillingUtil.OnStartSetupFinishedListener { @Override public void onSetupSuccess() { Log.e("googlePay","初始化成功"); } @Override public void onSetupFail(int responseCode) { Log.e("googlePay","初始化失敗="+responseCode); } @Override public void onSetupError() { Log.e("googlePayWay","初始化錯誤"); } //...; } //購買商品回調接口 private class MyOnPurchaseFinishedListener implements GoogleBillingUtil.OnPurchaseFinishedListener { @RequiresApi(api = Build.VERSION_CODES.O) @Override public void onPurchaseSuccess(List<Purchase> list) { //內購或者訂閱成功,可以通過purchase.getSku()獲取suk進而來判斷是哪個商品 } @Override public void onPurchaseFail(int responseCode) { Log.e("googlePayWay","購買失敗碼="+responseCode); } @Override public void onPurchaseError() { Log.e("googlePayWay","購買錯誤碼="); } } //查詢商品信息回調接口 private class MyOnQueryFinishedListener implements GoogleBillingUtil.OnQueryFinishedListener { @Override public void onQuerySuccess(String skuType,List<SkuDetails> list) { //查詢成功,返回商品列表, } @Override public void onQueryFail(int responseCode) { //查詢失敗 Log.e("googlePayWay","查詢失敗="+responseCode); } @Override public void onQueryError() { //查詢錯誤 Log.e("googlePayWay","查詢錯誤"); } }
然后在需要的地方加入以下代碼
private MyOnPurchaseFinishedListener mOnPurchaseFinishedListener = new MyOnPurchaseFinishedListener();//購買回調接口 private MyOnQueryFinishedListener mOnQueryFinishedListener = new MyOnQueryFinishedListener();//查詢回調接口 private MyOnStartSetupFinishedListener mOnStartSetupFinishedListener = new MyOnStartSetupFinishedListener();//服務初始化結果回調接口 GoogleBillingUtil googleBillingUtil = GoogleBillingUtil.getInstance(id)//這個id是google play console后台配置的商品id .setOnPurchaseFinishedListener(mOnPurchaseFinishedListener)//購買回調接口 .setOnQueryFinishedListener(mOnQueryFinishedListener)//查詢商品回調接口 .setOnStartSetupFinishedListener(mOnStartSetupFinishedListener)//服務初始化結果回調接口 .build(context); googleBillingUtil.setIsAutoConsumeAsync(true);//購買成功之后是否消耗商品
到此支付流程集成完成,如果不能支付成功返回碼是3的話 這邊存在很多因素,首先檢查支付賬號是否可以購買paly商店商品,如何檢查可以直接去paly商店點擊付費,看列表是否有數據,如果沒有說明賬號不支持支付也google支付也就不能支付成功,在確保賬號沒問題的情況下還不能支付成功,看google play console后台是否添加了測試賬號,還有一點就是要測試必須要先上google play console內測才能測試,還有其他一些因素像paly商店是否支持sdk相對應的版本
到此結束,有問題的話可以留言一起探討(*  ̄3)(ε ̄ *)