问题描述
我有一个应用程序,向用户显示回收站视图,其中包含来自Firebase Realtime数据库的图像。当用户单击图像时,他们希望它带他们到带有购买按钮的页面,并显示他们选择的图像。
这是他们可以进行购买的活动代码
package com.khumomashapa.notes.activities;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.android.billingclient.api.AcknowledgePurchaseParams;
import com.android.billingclient.api.AcknowledgePurchaseResponseListener;
import com.android.billingclient.api.BillingClient;
import com.android.billingclient.api.BillingClientStateListener;
import com.android.billingclient.api.BillingFlowParams;
import com.android.billingclient.api.BillingResult;
import com.android.billingclient.api.Purchase;
import com.android.billingclient.api.PurchasesUpdatedListener;
import com.android.billingclient.api.SkuDetails;
import com.android.billingclient.api.SkuDetailsParams;
import com.android.billingclient.api.SkuDetailsResponseListener;
import com.khumomashapa.notes.R;
import com.khumomashapa.notes.billing.BillingActivity;
import com.khumomashapa.notes.billing.Security;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static com.android.billingclient.api.BillingClient.SkuType.INAPP;
public class PreviewActivity extends AppCompatActivity implements PurchasesUpdatedListener {
TextView purchaseStatus;
Button purchaseButton;
Button DownloadBtn;
ImageView Preview;
public static final String PREF_FILE= "MyPref";
public static final String PURCHASE_KEY= "purchase";
public static final String PRODUCT_ID= "purchase";
private BillingClient billingClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_preview);
Preview = findViewById(R.id.ImagePreview);
byte[] bytes = getIntent().getByteArrayExtra("image");
Bitmap bmp = BitmapFactory.decodeByteArray(bytes,bytes.length);
Preview.setImageBitmap(bmp);
purchaseStatus = (TextView) findViewById(R.id.purchase_status);
purchaseButton = (Button) findViewById(R.id.PurchaseBtn);
DownloadBtn = (Button) findViewById(R.id.DownloadBtn);
// Establish connection to billing client
//check purchase status from google play store cache
//to check if item already Purchased previously or refunded
billingClient = BillingClient.newBuilder(this)
.enablePendingPurchases().setListener(this).build();
billingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(BillingResult billingResult) {
if(billingResult.getResponseCode()==BillingClient.BillingResponseCode.OK){
Purchase.PurchasesResult queryPurchase = billingClient.queryPurchases(INAPP);
List queryPurchases = queryPurchase.getPurchasesList();
if(queryPurchases!=null && queryPurchases.size()>0){
handlePurchases(queryPurchases);
}
//check which items are in purchase list and which are not in it
//if items that are found add them to purchaseFound
//check status of found items and save values to preference
//item which are not found simply save false values to their preference
//indexOf return index of item in purchase list from 0-3 (because we have 4 items) else returns -1 if not found
ArrayList purchaseFound =new ArrayList ();
if(queryPurchases!=null && queryPurchases.size()>0){
//check item in purchase list
for(Purchase p:queryPurchases){
int index=purchaseItemIDs.indexOf(p.getSku());
//if purchase found
if(index>-1)
{
purchaseFound.add(index);
if(p.getPurchaseState() == Purchase.PurchaseState.PURCHASED)
{
savePurchaseItemValueToPref(purchaseItemIDs.get(index),true);
}
else{
savePurchaseItemValueToPref(purchaseItemIDs.get(index),false);
}
}
}
//items that are not found in purchase list mark false
//indexOf returns -1 when item is not in foundlist
for(int i=0;i < purchaseItemIDs.size(); i++){
if(purchaseFound.indexOf(i)==-1){
savePurchaseItemValueToPref(purchaseItemIDs.get(i),false);
}
}
}
//if purchase list is empty that means no item is not purchased
//Or purchase is refunded or canceled
//so mark them all false
else{
for( String purchaseItem: purchaseItemIDs ){
savePurchaseItemValueToPref(purchaseItem,false);
}
}
}
}
@Override
public void onBillingServiceDisconnected() {
}
});
//item Purchased
if(getPurchaseValueFromPref()){
purchaseButton.setVisibility(View.GONE);
purchaseStatus.setText("Purchase Status: Purchased");
DownloadBtn.setVisibility(View.VISIBLE);
}
//item not Purchased
else{
purchaseButton.setVisibility(View.VISIBLE);
purchaseStatus.setText("Purchase Status: Not Purchased");
}
}
private static ArrayList purchaseItemIDs = new ArrayList() {{
add("abduction");
add("blocked_rainbow");
add("blue_cinema");
add("blue_clouds");
add("blue_grey");
add("lightmode_wallpaper");
add("ic_cloudy_night");
add("dark_blue");
add("flowers");
add("green_blue_plants");
add("green_clouds");
add("greeb_lights_with_stars");
add("green_nightstreak");
add("hexa_pattern");
add("hexa_pattern_red");
add("ic_logo");
add("lollipop");
add("moon_with_stars");
add("ic_night");
add("ic_clouds_night");
add("orange_nightstreak");
add("pink_dase");
add("rain_drops");
add("rainbow_ghost");
add("sunset");
add("tropical");
add("white_clouds");
add("yellow_gradient");
add("yellow_orange_gradient");
}};
private boolean getPurchaseItemValueFromPref(String purchaseItem){
return getPreferenceObject().getBoolean(purchaseItem,false);
}
private void savePurchaseItemValueToPref(String purchaseItem,boolean value){
getPreferenceEditObject().putBoolean(purchaseItem,value).commit();
}
private SharedPreferences getPreferenceObject() {
return getApplicationContext().getSharedPreferences(PREF_FILE,0);
}
private SharedPreferences.Editor getPreferenceEditObject() {
SharedPreferences pref = getApplicationContext().getSharedPreferences(PREF_FILE,0);
return pref.edit();
}
private boolean getPurchaseValueFromPref(){
return getPreferenceObject().getBoolean( PURCHASE_KEY,false);
}
private void savePurchaseValueToPref(boolean value){
getPreferenceEditObject().putBoolean(PURCHASE_KEY,value).commit();
}
//initiate purchase on button click
public void purchase(View view) {
//check if service is already connected
if (billingClient.isReady()) {
initiatePurchase();
}
//else reconnect service
else{
billingClient = BillingClient.newBuilder(this).enablePendingPurchases().setListener(this).build();
billingClient.startConnection(new BillingClientStateListener() {
@Override
public void onBillingSetupFinished(BillingResult billingResult) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
initiatePurchase();
} else {
Toast.makeText(getApplicationContext(),"Error "+billingResult.getDebugMessage(),Toast.LENGTH_SHORT).show();
}
}
@Override
public void onBillingServiceDisconnected() {
}
});
}
}
private void initiatePurchase() {
List<String> skuList = new ArrayList<>();
skuList.add(PRODUCT_ID);
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(INAPP);
billingClient.querySkuDetailsAsync(params.build(),new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(BillingResult billingResult,List<SkuDetails> skuDetailsList) {
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
if (skuDetailsList != null && skuDetailsList.size() > 0) {
BillingFlowParams flowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetailsList.get(0))
.build();
billingClient.launchBillingFlow(PreviewActivity.this,flowParams);
}
else{
//try to add item/product id "purchase" inside managed product in google play console
Toast.makeText(getApplicationContext(),"Purchase Item not Found",Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getApplicationContext()," Error "+billingResult.getDebugMessage(),Toast.LENGTH_SHORT).show();
}
}
});
}
@Override
public void onPurchasesUpdated(BillingResult billingResult,@Nullable List<Purchase> purchases) {
//if item newly purchased
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null) {
handlePurchases(purchases);
}
//if item already purchased then check and reflect changes
else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED) {
Purchase.PurchasesResult queryAlreadyPurchasesResult = billingClient.queryPurchases(INAPP);
List<Purchase> alreadyPurchases = queryAlreadyPurchasesResult.getPurchasesList();
if(alreadyPurchases!=null){
handlePurchases(alreadyPurchases);
}
}
//if purchase cancelled
else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) {
Toast.makeText(getApplicationContext(),"Purchase Canceled",Toast.LENGTH_SHORT).show();
}
// Handle any other error msgs
else {
Toast.makeText(getApplicationContext(),Toast.LENGTH_SHORT).show();
}
}
void handlePurchases(List<Purchase> purchases) {
for(Purchase purchase:purchases) {
//if item is purchased
if (PRODUCT_ID.equals(purchase.getSku()) && purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED)
{
if (!verifyValidSignature(purchase.getOriginalJson(),purchase.getSignature())) {
// Invalid purchase
// show error to user
Toast.makeText(getApplicationContext(),"Error : Invalid Purchase",Toast.LENGTH_SHORT).show();
return;
}
// else purchase is valid
//if item is purchased and not acknowledged
if (!purchase.isAcknowledged()) {
AcknowledgePurchaseParams acknowledgePurchaseParams =
AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.getPurchaseToken())
.build();
billingClient.acknowledgePurchase(acknowledgePurchaseParams,ackPurchase);
}
//else item is purchased and also acknowledged
else {
// Grant entitlement to the user on item purchase
// restart activity
if(!getPurchaseValueFromPref()){
savePurchaseValueToPref(true);
Toast.makeText(getApplicationContext(),"Item Purchased",Toast.LENGTH_SHORT).show();
this.recreate();
}
}
}
//if purchase is pending
else if( PRODUCT_ID.equals(purchase.getSku()) && purchase.getPurchaseState() == Purchase.PurchaseState.PENDING)
{
Toast.makeText(getApplicationContext(),"Purchase is Pending. Please complete Transaction",Toast.LENGTH_SHORT).show();
}
//if purchase is unknown
else if(PRODUCT_ID.equals(purchase.getSku()) && purchase.getPurchaseState() == Purchase.PurchaseState.UNSPECIFIED_STATE)
{
savePurchaseValueToPref(false);
purchaseStatus.setText("Purchase Status : Not Purchased");
purchaseButton.setVisibility(View.VISIBLE);
Toast.makeText(getApplicationContext(),"Purchase Status Unknown",Toast.LENGTH_SHORT).show();
}
}
}
AcknowledgePurchaseResponseListener ackPurchase = new AcknowledgePurchaseResponseListener() {
@Override
public void onAcknowledgePurchaseResponse(BillingResult billingResult) {
if(billingResult.getResponseCode()==BillingClient.BillingResponseCode.OK){
//if purchase is acknowledged
//then it is auto saved in preference later during app restart
Toast.makeText(getApplicationContext(),"Item Purchased. Please restart Activity",Toast.LENGTH_SHORT).show();
}
}
};
/**
* Verifies that the purchase was signed correctly for this developer's public key.
* <p>Note: It's strongly recommended to perform such check on your backend since hackers can
* replace this method with "constant true" if they decompile/rebuild your app.
* </p>
*/
private boolean verifyValidSignature(String signedData,String signature) {
try {
// To get key go to Developer Console > Select your app > Development Tools > Services & APIs.
String base64Key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhBlajrk5nNjpRTPJjDtGxgtgAeKijz3Wc0KrRKKSCxxsViHl7DhsI+sUZfk4Y1jxSg4/3W1uRo/0UASM77XfJIq34bK9KYgoSAGYSuH8Z+4fK/MrPz7dHhsljkAi4GZkv8x9VhZdDdpn2GSHVFaxs8c+HBOFp9aWAErHrQhi9/7fYf39pQSTC3WkVcy9xNDZxiiKTfDN3dyEvS0XQ617ZJwqDuRdkU5Aw9+R8r+oXyURV/ekgCQkWfCUaTp/jWdySOIcR87Bde24lQAXbvJaL5uAYI4zPwO4sIP1AbXLuDtv3N2rFVmP/1cML/NHDcfI5FOoStz88jzJU26Ngpqu1QIDAQAB";
return Security.verifyPurchase(base64Key,signedData,signature);
} catch (IOException e) {
return false;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(billingClient!=null){
billingClient.endConnection();
}
}
}
我还想卖29张图片。如您所见,我还没有 完全实施了应用内结算,因为我不知道该怎么做 现在。我已经设置了我的应用内商品。我会处理 用户获取图像,但是我只想知道如何实现应用内 结算。
那么我该如何实施应用内结算,以便用户可以购买图片 他们的选择。
更新
我找到了一个教程,该教程解释了如何实施多个应用内购买,但是这些行存在问题:
ArrayList purchaseFound =new ArrayList ();
if(queryPurchases!=null && queryPurchases.size()>0){
//check item in purchase list
for(Purchase p:queryPurchases){
int index=purchaseItemIDs.indexOf(p.getSku());
//if purchase found
if(index>-1)
{
purchaseFound.add(index);
if(p.getPurchaseState() == Purchase.PurchaseState.PURCHASED)
{
savePurchaseItemValueToPref(purchaseItemIDs.get(index),false);
}
}
}
我不断收到此错误。
错误:类型不兼容:对象无法转换为购买 for(购买p:queryPurchases){ ^
我该如何解决?
解决方法
您可以在https://developer.android.com/google/play/billing/integrate
下找到有关如何实施Google Play结算库的更多信息。在这里您可以找到有关如何设置库以及如何执行购买的详细说明。
,error: incompatible types: Object cannot be converted to Purchase for(Purchase p:queryPurchases){ ^
您必须调用该错误,显示必须存在参数的无效位置,如下所示
List<Purchase> queryPurchases
您还没有提交完整的代码