在应用内购买 - 如何处理第二次点击?

时间:2018-04-15 15:09:47

标签: java android in-app-purchase in-app-billing buttonclick

我只想在我的应用中实施应用内购买。这是一个具有不同规则集的纸牌游戏。所以现在想要实现2个新的规则集,它们应该作为我的产品和应用程序内购买。 我有这个:

`go = (Button)findViewById(R.id.go);
 go.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View view) {
        ArrayList skuList = new ArrayList();
        skuList.add(inappid);
        Bundle querySkus = new Bundle();
        querySkus.putStringArrayList("ITEM_ID_LIST", skuList);
        Bundle skuDetails;
            try {
                skuDetails = mservice.getSkuDetails(3, getPackageName(),
                        "inapp", querySkus);
                int response = skuDetails.getInt("RESPONSE_CODE");
                if (response == 0) {
                    ArrayList<String> responseList = 
                    skuDetails.getStringArrayList("DETAILS_LIST");
                    for (String thisResponse : responseList) {
                        JSONObject object = new JSONObject(thisResponse);
                        String sku = object.getString("productId");
                        String price = object.getString("price");
                        if (sku.equals(inappid)) {
                            System.out.println("price " + price);
                            Bundle buyIntentBundle = 
                            mservice.getBuyIntent(3, getPackageName(), sku,
                                    "inapp",
                                    "blablabla");
                            PendingIntent pendingIntent = 
                            buyIntentBundle.getParcelable("BUY_INTENT");
                            startIntentSenderForResult(
                                    pendingIntent.getIntentSender(), 1001,
                                    new Intent(), Integer.valueOf(0),
                                    Integer.valueOf(0), Integer.valueOf(0));
                        }
                    }
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            } catch (JSONException e) {
                e.printStackTrace();
            } catch (IntentSender.SendIntentException e ) {
                e.printStackTrace();
            }
        }
    });`

首先点击我的规则集工作正常。第二次单击会触发应用程序崩溃,并显示以下错误: java.lang.NullPointerException:尝试调用虚拟方法&#39; android.content.IntentSender android.app.PendingIntent.getIntentSender()&#39;在空对象引用上

你有一些很好的应用内教程或tipp吗?

提前致谢 JD

1 个答案:

答案 0 :(得分:1)

这是我在我需要的任何地方使用的BaseClass。只需按此BaseInAppPurchaseActivity

扩展您的活动即可

本课程的奖金。

您可以获取可供购买的商品,因此如果商品不可用,则用户无法获得将来的例外情况,例如

 checkAvailablePurchases(skuList, new OnResultInApp() {
                @Override
                public void onResult(ArrayList<AvailablePurchase> availablePurchaseArrayList) {
                    .. logic for showing view with available purchaseItem
                }
            });

购买商品

 purchaseItem(googleInAppId, new OnResultPurchase() {
            @Override
            public void onSuccess(PurchaseResponseBean purchaseResponseBean, String inAppPurchaseData) {
               // your stuff 
            }

            @Override
            public void onError() {
                showToast(R.string.something_went_wrong);
            }
        });

这看起来很干净漂亮。

BaseInAppPurchaseActivity.class

package in.kpis.nearyou.base;

import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.ServiceConnection;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;

import com.android.vending.billing.IInAppBillingService;
import com.google.gson.Gson;

import org.json.JSONException;
import org.json.JSONObject;

import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import in.kpis.nearyou.entity.AvailablePurchase;
import in.kpis.nearyou.entity.Helper;
import in.kpis.nearyou.entity.PurchaseResponseBean;
import in.kpis.nearyou.entity.UserPurchaseItemsBean;
import in.kpis.nearyou.utilities.AppPreference;

import static in.kpis.nearyou.base.BaseInAppPurchaseActivity.ConsuptionResponseType.SUCCESS;
import static in.kpis.nearyou.base.BaseInAppPurchaseActivity.PurchaseStateTypes.PURCHASED;


public class BaseInAppPurchaseActivity extends BaseAppCompatActivity {
    private static final String TAG = BaseInAppPurchaseActivity.class.getSimpleName();
    private IInAppBillingService mService;


    private static final char[] symbols = new char[36];

    static {
        for (int idx = 0; idx < 10; ++idx)
            symbols[idx] = (char) ('0' + idx);
        for (int idx = 10; idx < 36; ++idx)
            symbols[idx] = (char) ('a' + idx - 10);
    }

    public void startInAppPurchaseServices() {
        Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
        serviceIntent.setPackage("com.android.vending");
        bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
    }

    private String appPackageName;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        appPackageName = this.getPackageName();
        startInAppPurchaseServices();
    }

    ServiceConnection mServiceConn = new ServiceConnection() {
        @Override
        public void onServiceDisconnected(ComponentName name) {
            mService = null;
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mService = IInAppBillingService.Stub.asInterface(service);
            startAsyncForCheckingAvailablePurchase();
        }
    };

    private void startAsyncForCheckingAvailablePurchase() {
        if (skuListByNearyouServer != null && skuListByNearyouServer.size() > 0 & onResultInApp != null) {
            AvailablePurchaseAsyncTask mAsyncTask = new AvailablePurchaseAsyncTask(appPackageName, skuListByNearyouServer, onResultInApp);
            mAsyncTask.execute();
        }
    }

    private ArrayList<String> skuListByNearyouServer = new ArrayList<>();
    OnResultInApp onResultInApp;

    public void checkAvailablePurchases(ArrayList<String> skuList, OnResultInApp onResultInApp) {
        skuListByNearyouServer = skuList;
        this.onResultInApp = onResultInApp;

        if (mService == null) startInAppPurchaseServices();
        else startAsyncForCheckingAvailablePurchase();
    }


    public interface OnResultPurchase {
        void onSuccess(PurchaseResponseBean purchaseResponseBean, String inAppPurchaseData);

        void onError();
    }

    private OnResultPurchase onResultPurchase;
    private String itemToPurchaseSku;

    public void purchaseItem(String sku, OnResultPurchase onResultPurchase) {
        this.onResultPurchase = onResultPurchase;
        itemToPurchaseSku = sku;
        if (isBillingSupported()) {
            String generatedPayload = getPayLoad();
            AppPreference.getInstance(BaseInAppPurchaseActivity.this).setDeveloperPayload(generatedPayload);
            try {
                Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(), sku, "inapp", generatedPayload);
                PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
                try {
                    startIntentSenderForResult(pendingIntent.getIntentSender(), Helper.RESPONSE_CODE, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0));
                } catch (IntentSender.SendIntentException e) {
                    e.printStackTrace();
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == Helper.RESPONSE_CODE) {
            if (data != null && data.getExtras() != null && data.getStringExtra("INAPP_DATA_SIGNATURE") != null & data.getStringExtra("INAPP_PURCHASE_DATA") != null) {

                int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
                String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
                String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
                if (resultCode == RESULT_OK && responseCode == 0) {
                    try {
                        PurchaseResponseBean purchaseResponseBean = new Gson().fromJson(purchaseData, PurchaseResponseBean.class);
                        String sku = purchaseResponseBean.getProductId();
                        String developerPayload = purchaseResponseBean.getDeveloperPayload();
                        int responseCodeConsuption = consumePurchaseItem(purchaseResponseBean.getPurchaseToken());
                        if (responseCodeConsuption == SUCCESS) {
                            if (purchaseResponseBean.getPurchaseState() == PURCHASED && itemToPurchaseSku.equals(sku) && developerPayload.equals(AppPreference.getInstance(BaseInAppPurchaseActivity.this).getDeveloperPayload())) {
                                if (onResultPurchase != null)
                                    onResultPurchase.onSuccess(purchaseResponseBean, purchaseData);
                            } else onErrorOfPurchase();
                        } else onResultPurchase.onSuccess(purchaseResponseBean, purchaseData);
                    } catch (Exception e) {
                        e.printStackTrace();
                        onErrorOfPurchase();
                    }
                } else onErrorOfPurchase();
            }
        } else onErrorOfPurchase();
    }

    private void onErrorOfPurchase() {
        if (onResultPurchase != null) onResultPurchase.onError();
    }

    interface PurchaseStateTypes {
        int PURCHASED = 0;
        int CANCELED = 1;
        int REFUNDED = 2;

    }

    interface ConsuptionResponseType {
        int SUCCESS = 0;
    }


    private String getPayLoad() {
        RandomString randomString = new RandomString(36);
        String payload = randomString.nextString();
        return payload;
    }

    private class RandomString {
        private final Random random = new Random();
        private final char[] buf;

        RandomString(int length) {
            if (length < 1)
                throw new IllegalArgumentException("length < 1: " + length);
            buf = new char[length];
        }

        String nextString() {
            for (int idx = 0; idx < buf.length; ++idx)
                buf[idx] = symbols[random.nextInt(symbols.length)];
            return new String(buf);
        }
    }

    public final class SessionIdentifierGenerator {
        private SecureRandom random = new SecureRandom();

        public String nextSessionId() {
            return new BigInteger(130, random).toString(32);
        }
    }

    public interface OnResultInApp {
        void onResult(ArrayList<AvailablePurchase> canPurchaseList);
    }

    private class AvailablePurchaseAsyncTask extends AsyncTask<Void, Void, Bundle> {
        String packageName;
        ArrayList<String> skuList;
        OnResultInApp OnResultInApp;

        AvailablePurchaseAsyncTask(String packageName, ArrayList<String> skuList, OnResultInApp OnResultInApp) {
            this.packageName = packageName;
            this.skuList = skuList;
            this.OnResultInApp = OnResultInApp;
        }

        @Override
        protected Bundle doInBackground(Void... voids) {

            Bundle query = new Bundle();
            query.putStringArrayList(Helper.ITEM_ID_LIST, skuList);
            Bundle skuDetails = null;
            try {
                skuDetails = mService.getSkuDetails(3, packageName, "inapp", query);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            return skuDetails;
        }

        @Override
        protected void onPostExecute(Bundle skuDetails) {
            ArrayList<AvailablePurchase> availablePurchaseArrayList = new ArrayList<>();
            if (skuDetails != null) {
                int response = skuDetails.getInt("RESPONSE_CODE");
                if (response == 0) {
                    ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST");
                    if (responseList != null) {
                        for (String thisResponse : responseList) {
                            JSONObject object = null;
                            try {
                                object = new JSONObject(thisResponse);
                                String sku = object.getString("productId");
                                String price = object.getString("price");
                                availablePurchaseArrayList.add(new AvailablePurchase(sku, price, false));
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
            for (AvailablePurchase availablePurchase : availablePurchaseArrayList) {
                for (String sku : skuList) {
                    if (sku.equals(availablePurchase.getSku())) {
                        availablePurchase.setActive(true);
                    }
                }
            }

            if (OnResultInApp != null) {
                OnResultInApp.onResult(availablePurchaseArrayList);
            }
        }
    }


    public boolean isBillingSupported() {
        int response = 1;
        try {
            response = mService.isBillingSupported(3, getPackageName(), "inapp");
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        if (response > 0) {
            return false;
        }
        return true;
    }

    public int consumePurchaseItem(String purchaseToken) {
        if (isBillingSupported()) {
            try {
                int response = mService.consumePurchase(3, getPackageName(), purchaseToken);
                return response;
            } catch (RemoteException e) {
                e.printStackTrace();
                return -1;
            }
        } else return -1;
    }

    public Bundle getAllUserPurchase() {
        Bundle ownedItems = null;
        try {
            ownedItems = mService.getPurchases(3, getPackageName(), "inapp", null);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return ownedItems;
    }

    public List<UserPurchaseItemsBean> extractAllUserPurchase(Bundle ownedItems) {
        List<UserPurchaseItemsBean> mUserItems = new ArrayList<UserPurchaseItemsBean>();
        int response = ownedItems.getInt("RESPONSE_CODE");
        if (response == 0) {
            ArrayList<String> ownedSkus = ownedItems.getStringArrayList("INAPP_PURCHASE_ITEM_LIST");
            ArrayList<String> purchaseDataList = ownedItems.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
            ArrayList<String> signatureList = ownedItems.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
            String continuationToken = ownedItems.getString("INAPP_CONTINUATION_TOKEN");
            if (purchaseDataList != null) {
                for (int i = 0; i < purchaseDataList.size(); ++i) {
                    String purchaseData = purchaseDataList.get(i);
                    assert signatureList != null;
                    String signature = signatureList.get(i);
                    assert ownedSkus != null;
                    String sku = ownedSkus.get(i);
                    UserPurchaseItemsBean allItems = new UserPurchaseItemsBean(sku, purchaseData, signature);
                    mUserItems.add(allItems);
                }
            }
        }
        return mUserItems;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stopInAppPurchaseService();

    }

    private void stopInAppPurchaseService() {
        if (mService != null) {
            unbindService(mServiceConn);
        }
    }
}

AvailablePurchase.class

/**
 * Created by KHEMRAJ on 7/13/2017.
 */
public class AvailablePurchase {
    private String sku;
    private String price;
    private boolean isActive;
    public AvailablePurchase(String sku, String price, boolean isActive) {
        this.sku = sku;
        this.price = price;
        this.isActive = isActive;
    }
    public String getSku() {
        return sku;
    }
    public String getPrice() {
        return price;
    }

    public boolean isActive() {
        return isActive;
    }

    public void setActive(boolean active) {
        isActive = active;
    }
}

Helper.class

/**
 * Created by KHEMRAJ on 7/13/2017.
 */
import android.content.Context;
import android.widget.Toast;

public class Helper {
    public static final String ITEM_ID_LIST = "ITEM_ID_LIST";
    public static final String ITEM_ONE_ID = "android.test.purchased";
    public static final String ITEM_TWO_ID = "2";
    public static final String ITEM_THREE_ID = "3";
    public static final String ITEM_FIVE_ID= "4";
    public static final String ITEM_SIX_ID = "5";
    public static final int RESPONSE_CODE = 1001;

    public static void displayMessage(Context context, String message){
        Toast.makeText(context.getApplicationContext(), message, Toast.LENGTH_LONG).show();
    }
}

PurchaseResponseBean.class

/**
 * Created by KHEMRAJ on 7/15/2017.
 */

public class PurchaseResponseBean {
    private String productId;
    private String developerPayload;
    private String purchaseToken;
    private String orderId;
    private String purchaseTime;
    private int purchaseState;


    public String getProductId() {
        return productId;
    }

    public void setProductId(String productId) {
        this.productId = productId;
    }

    public String getDeveloperPayload() {
        return developerPayload;
    }

    public void setDeveloperPayload(String developerPayload) {
        this.developerPayload = developerPayload;
    }

    public String getPurchaseToken() {
        return purchaseToken;
    }

    public void setPurchaseToken(String purchaseToken) {
        this.purchaseToken = purchaseToken;
    }

    public String getOrderId() {
        return orderId;
    }

    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }

    public String getPurchaseTime() {
        return purchaseTime;
    }

    public void setPurchaseTime(String purchaseTime) {
        this.purchaseTime = purchaseTime;
    }

    public int getPurchaseState() {
        return purchaseState;
    }

    public void setPurchaseState(int purchaseState) {
        this.purchaseState = purchaseState;
    }
}

UserPurchaseItemsBean.class

public class UserPurchaseItemsBean {
    private String sku;
    private String purchasedata;
    private String signature;
    public UserPurchaseItemsBean(String sku, String purchasedata, String signature) {
        this.sku = sku;
        this.purchasedata = purchasedata;
        this.signature = signature;
    }
    public String getSku() {
        return sku;
    }
    public String getPurchasedata() {
        return purchasedata;
    }
    public String getSignature() {
        return signature;
    }
}

AppPreference.java

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;

public class AppPreference {
    String DEVELOPERPAYLOAD = "DEVELOPERPAYLOAD";
    String PURCHASETOKEN = "PURCHASETOKEN";
    //Configuration Variable
    private static AppPreference singletonPreference = null;
    private SharedPreferences sp;

    private Context context;

    private AppPreference(Context context) {
        if (context == null)
            return;
        this.context = context;
        sp = context.getSharedPreferences(Constants.sharedPreference.PREFERENCE, 0);
    }

    public static AppPreference getInstance(Context context) {
        if (singletonPreference == null)
            singletonPreference = new AppPreference(context);
        return singletonPreference;
    }

    public void clearOnlogout() {
        Editor prefsEditor = sp.edit();
        prefsEditor.clear();
        prefsEditor.apply();
    }

    void removeData(String key) {
        SharedPreferences.Editor editor = sp.edit();
        editor.remove(key);
        editor.apply();
    }

    public void setStringData(String pKey, String pData) {
        SharedPreferences.Editor editor = sp.edit();
        editor.putString(pKey, pData);
        editor.apply();
    }

    public void setBooleanData(String pKey, boolean pData) {
        SharedPreferences.Editor editor = sp.edit();
        editor.putBoolean(pKey, pData);
        editor.apply();
    }

    void setIntegerData(String pKey, int pData) {
        SharedPreferences.Editor editor = sp.edit();
        editor.putInt(pKey, pData);
        editor.apply();
    }

    public String getStringData(String pKey) {
        return sp.getString(pKey, "");
    }

    public boolean getBooleanData(String pKey) {
        return sp.getBoolean(pKey, false);
    }

    public int getIntegerData(String pKey) {
        return sp.getInt(pKey, 0);
    }

    public String getDeveloperPayload() {
        return sp.getString(DEVELOPERPAYLOAD, "");
    }

    public void setDeveloperPayload(String developerPayload) {
        SharedPreferences.Editor editor = sp.edit();
        editor.putString(DEVELOPERPAYLOAD, developerPayload);
        editor.apply();
    }


}

快乐编码:)