17
17
import com .google .android .gms .ads .MobileAds ;
18
18
19
19
import java .util .ArrayList ;
20
+ import java .util .Collections ;
20
21
import java .util .HashMap ;
21
22
import java .util .List ;
22
23
import java .util .Map ;
@@ -39,18 +40,21 @@ public SupportRepository(Context context) {
39
40
public void initBillingClient (Runnable onConnected ) {
40
41
billingClient = BillingClient .newBuilder (context )
41
42
.setListener ((billingResult , purchases ) -> {
43
+ // To be implemented in a later release
42
44
})
43
45
.enablePendingPurchases (
44
46
PendingPurchasesParams .newBuilder ()
45
47
.enableOneTimeProducts ()
46
48
.build ())
49
+ // Added as a best practice from the official documentation for v8+
50
+ .enableAutoServiceReconnection ()
47
51
.build ();
48
52
49
53
billingClient .startConnection (new BillingClientStateListener () {
50
54
@ Override
51
55
public void onBillingSetupFinished (@ NonNull BillingResult billingResult ) {
52
56
if (billingResult .getResponseCode () == BillingClient .BillingResponseCode .OK ) {
53
- // Billing service connected
57
+ // The BillingClient is ready. You can query purchases here.
54
58
if (onConnected != null ) {
55
59
onConnected .run ();
56
60
}
@@ -59,7 +63,9 @@ public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
59
63
60
64
@ Override
61
65
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.
63
69
}
64
70
});
65
71
}
@@ -73,53 +79,76 @@ public void queryProductDetails(List<String> productIds, OnProductDetailsListene
73
79
return ;
74
80
}
75
81
76
- List <QueryProductDetailsParams .Product > products = new ArrayList <>();
82
+ List <QueryProductDetailsParams .Product > productList = new ArrayList <>();
77
83
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
+ );
82
90
}
83
91
84
92
QueryProductDetailsParams params = QueryProductDetailsParams .newBuilder ()
85
- .setProductList (products )
93
+ .setProductList (productList )
86
94
.build ();
87
95
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 ) -> {
90
99
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 ()) {
93
105
for (ProductDetails productDetails : productDetailsList ) {
94
106
productDetailsMap .put (productDetails .getProductId (), productDetails );
95
107
}
96
108
if (listener != null ) {
97
109
listener .onProductDetailsRetrieved (productDetailsList );
98
110
}
99
111
}
112
+ // Optionally handle unfetched products if needed:
113
+ // List<UnfetchedProduct> unfetched = queryProductDetailsResult.getUnfetchedProductList();
100
114
}
115
+ // Handle other billingResult response codes here if necessary.
101
116
});
102
117
}
103
118
119
+
104
120
/**
105
121
* Launch the billing flow for a particular product.
106
122
*/
107
123
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 ();
119
132
}
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 );
120
148
}
121
149
}
122
150
151
+
123
152
/**
124
153
* Initialize Mobile Ads (usually done once in your app, but
125
154
* can be done here if needed for the support screen).
@@ -135,5 +164,4 @@ public void initMobileAds(ActivitySupportBinding binding) {
135
164
public interface OnProductDetailsListener {
136
165
void onProductDetailsRetrieved (List <ProductDetails > productDetailsList );
137
166
}
138
-
139
167
}
0 commit comments