已实现Firebase实时数据库存储的android应用中的多个应用内产品

问题描述

我有一个应用程序,向用户显示回收站视图,其中包含来自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();
        }
    }
}

Here's one image example

Here's a second example

我还想卖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

您还没有提交完整的代码

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...