Skip to content

Commit 044f056

Browse files
fix: Corrected BillingClient usage in SupportRepository
This commit addresses issues with the Google Play Billing Library integration in `SupportRepository.java`: - **BillingClient Initialization:** Added `enableAutoServiceReconnection()` during BillingClient setup as a best practice for v8+ of the library. - **Product Details Query:** - Corrected the lambda expression in `queryProductDetailsAsync` to properly accept a single `QueryProductDetailsResult` object, aligning with the official documentation. - Ensured that `productDetailsList` is retrieved from the `QueryProductDetailsResult` object. - **Purchase Initiation:** - Updated `initiatePurchase` to correctly use `setOfferToken()` when building `BillingFlowParams.ProductDetailsParams`. - Simplified the creation of `productDetailsParamsList` using `Collections.singletonList()`.
1 parent 78c1b8c commit 044f056

File tree

2 files changed

+68
-29
lines changed

2 files changed

+68
-29
lines changed

.idea/workspace.xml

Lines changed: 16 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/support/repository/SupportRepository.java

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.google.android.gms.ads.MobileAds;
1818

1919
import java.util.ArrayList;
20+
import java.util.Collections;
2021
import java.util.HashMap;
2122
import java.util.List;
2223
import java.util.Map;
@@ -39,18 +40,21 @@ public SupportRepository(Context context) {
3940
public void initBillingClient(Runnable onConnected) {
4041
billingClient = BillingClient.newBuilder(context)
4142
.setListener((billingResult, purchases) -> {
43+
// To be implemented in a later release
4244
})
4345
.enablePendingPurchases(
4446
PendingPurchasesParams.newBuilder()
4547
.enableOneTimeProducts()
4648
.build())
49+
// Added as a best practice from the official documentation for v8+
50+
.enableAutoServiceReconnection()
4751
.build();
4852

4953
billingClient.startConnection(new BillingClientStateListener() {
5054
@Override
5155
public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
5256
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
53-
// Billing service connected
57+
// The BillingClient is ready. You can query purchases here.
5458
if (onConnected != null) {
5559
onConnected.run();
5660
}
@@ -59,7 +63,9 @@ public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
5963

6064
@Override
6165
public void onBillingServiceDisconnected() {
62-
// Attempt reconnection or handle gracefully
66+
// Try to restart the connection on the next request to
67+
// Google Play by calling the startConnection() method.
68+
// With enableAutoServiceReconnection(), this is handled automatically.
6369
}
6470
});
6571
}
@@ -73,53 +79,76 @@ public void queryProductDetails(List<String> productIds, OnProductDetailsListene
7379
return;
7480
}
7581

76-
List<QueryProductDetailsParams.Product> products = new ArrayList<>();
82+
List<QueryProductDetailsParams.Product> productList = new ArrayList<>();
7783
for (String id : productIds) {
78-
products.add(QueryProductDetailsParams.Product.newBuilder()
79-
.setProductId(id)
80-
.setProductType(BillingClient.ProductType.INAPP)
81-
.build());
84+
productList.add(
85+
QueryProductDetailsParams.Product.newBuilder()
86+
.setProductId(id)
87+
.setProductType(BillingClient.ProductType.INAPP)
88+
.build()
89+
);
8290
}
8391

8492
QueryProductDetailsParams params = QueryProductDetailsParams.newBuilder()
85-
.setProductList(products)
93+
.setProductList(productList)
8694
.build();
8795

88-
billingClient.queryProductDetailsAsync(params, result -> {
89-
BillingResult billingResult = result.getBillingResult();
96+
// **FIXED**: The lambda now correctly accepts a single QueryProductDetailsResult
97+
// object as the second parameter, directly matching the official documentation.
98+
billingClient.queryProductDetailsAsync(params, (billingResult, queryProductDetailsResult) -> {
9099
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
91-
List<ProductDetails> productDetailsList = result.getProductDetailsList();
92-
if (productDetailsList != null && !productDetailsList.isEmpty()) {
100+
101+
// The list of products is retrieved from the QueryProductDetailsResult object.
102+
List<ProductDetails> productDetailsList = queryProductDetailsResult.getProductDetailsList();
103+
104+
if (!productDetailsList.isEmpty()) {
93105
for (ProductDetails productDetails : productDetailsList) {
94106
productDetailsMap.put(productDetails.getProductId(), productDetails);
95107
}
96108
if (listener != null) {
97109
listener.onProductDetailsRetrieved(productDetailsList);
98110
}
99111
}
112+
// Optionally handle unfetched products if needed:
113+
// List<UnfetchedProduct> unfetched = queryProductDetailsResult.getUnfetchedProductList();
100114
}
115+
// Handle other billingResult response codes here if necessary.
101116
});
102117
}
103118

119+
104120
/**
105121
* Launch the billing flow for a particular product.
106122
*/
107123
public void initiatePurchase(Activity activity, String productId) {
108-
if (productDetailsMap.containsKey(productId)) {
109-
ProductDetails details = productDetailsMap.get(productId);
110-
if (details != null) {
111-
BillingFlowParams.ProductDetailsParams productParams =
112-
BillingFlowParams.ProductDetailsParams.newBuilder()
113-
.setProductDetails(details)
114-
.build();
115-
BillingFlowParams flowParams = BillingFlowParams.newBuilder()
116-
.setProductDetailsParamsList(List.of(productParams))
117-
.build();
118-
billingClient.launchBillingFlow(activity, flowParams);
124+
ProductDetails details = productDetailsMap.get(productId);
125+
if (details != null) {
126+
// Note: In a real app, you would select a specific offer. For simplicity,
127+
// we're assuming there's only one or we're using the base plan.
128+
// For subscriptions, this would be ProductDetails.getSubscriptionOfferDetails()
129+
String offerToken = "";
130+
if (details.getOneTimePurchaseOfferDetails() != null) {
131+
offerToken = details.getOneTimePurchaseOfferDetails().getOfferToken();
119132
}
133+
134+
assert offerToken != null;
135+
List<BillingFlowParams.ProductDetailsParams> productDetailsParamsList =
136+
Collections.singletonList(
137+
BillingFlowParams.ProductDetailsParams.newBuilder()
138+
.setProductDetails(details)
139+
.setOfferToken(offerToken)
140+
.build()
141+
);
142+
143+
BillingFlowParams flowParams = BillingFlowParams.newBuilder()
144+
.setProductDetailsParamsList(productDetailsParamsList)
145+
.build();
146+
147+
billingClient.launchBillingFlow(activity, flowParams);
120148
}
121149
}
122150

151+
123152
/**
124153
* Initialize Mobile Ads (usually done once in your app, but
125154
* can be done here if needed for the support screen).
@@ -135,5 +164,4 @@ public void initMobileAds(ActivitySupportBinding binding) {
135164
public interface OnProductDetailsListener {
136165
void onProductDetailsRetrieved(List<ProductDetails> productDetailsList);
137166
}
138-
139167
}

0 commit comments

Comments
 (0)