Sometimes my users report that an in-app purchase isn't being logged (even though it goes through and is authorized). I used the TrivialDrive sample and have the following code:
public class FragmentGoPro extends Fragment{
private static final String TAG = AppConstants.Keys.TAG;
private final String SKU_PREMIUM = "001";
private IabHelper mHelper;
private static final int RC_REQUEST = 546731;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View rootView = inflater.inflate(R.layout.fragment_billing, container, false);
getActivity().getActionBar().setTitle(getActivity().getString(R.string.app_name));
setupHelper();
TextView descriptionView = (TextView)rootView.findViewById(R.id.pro_description);
String proDescription = getString(R.string.pro_description);
descriptionView.setText(proDescription);
Button goPro = (Button)rootView.findViewById(R.id.purchase);
goPro.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
makePurchase();
}
});
return rootView;
}
private void setupHelper() {
mHelper = new IabHelper(getActivity(), AppConstants.Keys.PRO);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
// Oh noes, there was a problem.
complain("Problem setting up in-app billing: " + result);
return;
}
// Hooray, IAB is fully set up. Now, let's get an inventory of stuff we own.
mHelper.queryInventoryAsync(mGotInventoryListener);
}
});
}
private void makePurchase() {
Log.i(TAG, "MakePurchase requested.");
mHelper.launchPurchaseFlow(getActivity(), SKU_PREMIUM, RC_REQUEST,
mPurchaseFinishedListener, null);
}
// Callback for when a purchase is finished
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.i(TAG, "Purchase finished: " + result + ", purchase: " + purchase);
if (result.isFailure()) {
complain("Error purchasing: " + result);
return;
}
Log.i(TAG, "Purchase of " + purchase.getSku() + " Sku confirmed.");
if (purchase.getSku().equals(SKU_PREMIUM)) {
// bought the premium upgrade!
alert("Thank you for upgrading to premium!");
Log.i(TAG, "Premium features unlocked!");
setPreference("mIsPremium", true);
setPreference("Purchased", true);
updateMetrics();
updateNav();
}
}
};
protected IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
if (result.isFailure()) {
complain("Failed to query inventory: " + result);
return;
}
/*
* Check for items we own. Notice that for each purchase, we check
* the developer payload to see if it's correct! See
* verifyDeveloperPayload().
*/
// Do we have the premium upgrade?
Purchase premiumPurchase = inventory.getPurchase(SKU_PREMIUM);
boolean mIsPremium = (premiumPurchase != null);
if (mIsPremium) {
Log.i(TAG, "Premium purchased previously, restoring transactions.");
setPreference("mIsPremium", mIsPremium);
setPreference("Purchased", true);
updateNav();
}
}
};
private void updateMetrics() {
EasyTracker.getInstance().setContext(getActivity());
flurryEvent("state", "purchase_state", "purchased");
if (!checkIfTesting()) {
Log.i(TAG, "Purchase Logged");
Transaction myTrans = new Transaction.Builder(
"0_3164", // (String) Transaction Id, should be unique.
(long) 2.99 * 1000000) // (long) Order total (in micros)
.setAffiliation("In-App Google Play") // (String) Affiliation
.build();
myTrans.addItem(new Transaction.Item.Builder(
"001", // (String) Product SKU
"Pro License", // (String) Product name
(long) 2.99 * 1000000, // (long) Product price (in micros)
(long) 1 ) // (long) Product quantity
.build());
Tracker myTracker = EasyTracker.getTracker(); // Get reference to tracker.
myTracker.sendTransaction(myTrans); // Track the transaction.
}
}
protected void updateNav() {
Activity activity = getActivity();
if(activity instanceof MainActivity) {
((MainActivity) activity).initializeNavigation();
} else {
getActivity().finish();
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
// Pass on the activity result to the helper for handling
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
}
else {
Log.d(TAG, "onActivityResult handled by IABUtil.");
}
}
It appears that my updateMetrics() and updateNav() are not being called but it looks to me like it always should. Again, this is only happening in a small percentage of users.
I believe it has to do with my orderID being static. I followed the guide here to use the updated analytics. Using System.currentTimeInMillis() should give a unique orderID and prevent clashes of data.
Additionally, I was using this in a fragment so onActivityResult was not being called (strangely it worked on my test devices) so I needed to modify the billing code.
Related
i'm looking to study in App Billing.
i have created a test app. I can see my in app product insered into Play Console, with getSkuDetails, but when i start launchPurchaseFlow, the interface to buy in app product not start, and i can see only the log(Log its ok)
public class MainActivity extends Activity implements View.OnClickListener {
Button compra,click,controllo;
private IabHelper.QueryInventoryFinishedListener mQueryFinishedListener;
IInAppBillingService mService;
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);
}
};
private static final String TAG="INappBILLING";
IabHelper mHelper;
static final String ITEM_SKU="dsada";
public monky.myapplication.util.IabHelper.OnIabPurchaseFinishedListener
mPurchaseFinishedListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent serviceIntent =
new Intent("com.android.vending.billing.InAppBillingService.BIND");
serviceIntent.setPackage("com.android.vending");
bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
compra=(Button) findViewById(R.id.buybtn);
compra.setOnClickListener(this);
click=(Button)findViewById(R.id.clickbtn);
click.setOnClickListener(this);
controllo=(Button) findViewById(R.id.controllo);
controllo.setOnClickListener(this);
String base64EncodedPublicKey="mykey";
mHelper=new IabHelper(this,base64EncodedPublicKey);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
// Oh no, there was a problem.
Log.d(TAG, "Problem setting up In-app Billing: " + result);
}
// Hooray, IAB is fully set up!
}
});
}
#Override
public void onDestroy() {
super.onDestroy();
if (mService != null) {
unbindService(mServiceConn);
}
}
#Override
public void onClick(View view) {
switch (view.getId()){
case R.id.clickbtn:
List additionalSkuList = new ArrayList();
additionalSkuList.add(ITEM_SKU);
mHelper.queryInventoryAsync(true, additionalSkuList,
mQueryFinishedListener);
mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory)
{
if (result.isFailure()) {
Log.i(TAG, " - Prezzo Error" );
return;
}
String prezzo = inventory.getSkuDetails(ITEM_SKU).getPrice();
String titolo = inventory.getSkuDetails(ITEM_SKU).getTitle();
String desc = inventory.getSkuDetails(ITEM_SKU).getDescription();
String type = inventory.getSkuDetails(ITEM_SKU).getType();
String SkU = inventory.getSkuDetails(ITEM_SKU).getSku();
Toast.makeText(getApplicationContext(),"Titolo: "+titolo+" Desc "+desc+" Prezzo "+prezzo+" Tipo "+type+"SKU"+SkU ,Toast.LENGTH_LONG).show();
Log.i(TAG, " - Prezzo " + prezzo);
// update the UI
}
};
break;
case R.id.buybtn:
if (!mHelper.isAsyncInProgress()){
mHelper.launchPurchaseFlow(this, ITEM_SKU, 10001,
mPurchaseFinishedListener,"" );
Log.i(TAG, " sono passato " );}
else {
Log.i(TAG, " Non sono passato " );
}
break;
case R.id.controllo:
controlloaq();
break;
}
}
private void controlloaq() {
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener
= new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase)
{
if (purchase.getSku().equals(ITEM_SKU)) {
Log.i(TAG, " passato e comprato" );
}
if (result.isFailure()) {
Log.i(TAG, "Error purchasing: " + result);
return;
}
}
};
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + ","
+ data);
// Pass on the activity result to the helper for handling
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
} else {
Log.d(TAG, "onActivityResult handled by IABUtil.");
}
}
}
I think your code is almost correct. What's happening is your mPurchaseFinishedListener is not triggering because you placed it inside a function, controlloaq() therefore it will only execute if you call controlloaq().
Looking at the official Google In App Billing sample, you're not supposed to enclose it inside a function, unless you know what you're doing.
// Callback for when a purchase is finished
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.d(TAG, "Purchase finished: " + result + ", purchase: " + purchase);
// if we were disposed of in the meantime, quit.
if (mHelper == null) return;
if (result.isFailure()) {
complain("Error purchasing: " + result);
setWaitScreen(false);
return;
}
if (!verifyDeveloperPayload(purchase)) {
complain("Error purchasing. Authenticity verification failed.");
setWaitScreen(false);
return;
}
Log.d(TAG, "Purchase successful.");
if (purchase.getSku().equals(SKU_GAS)) {
// bought 1/4 tank of gas. So consume it.
Log.d(TAG, "Purchase is gas. Starting gas consumption.");
try {
mHelper.consumeAsync(purchase, mConsumeFinishedListener);
} catch (IabAsyncInProgressException e) {
complain("Error consuming gas. Another async operation in progress.");
setWaitScreen(false);
return;
}
}
else if (purchase.getSku().equals(SKU_PREMIUM)) {
// bought the premium upgrade!
Log.d(TAG, "Purchase is premium upgrade. Congratulating user.");
alert("Thank you for upgrading to premium!");
mIsPremium = true;
updateUi();
setWaitScreen(false);
}
else if (purchase.getSku().equals(SKU_INFINITE_GAS_MONTHLY)
|| purchase.getSku().equals(SKU_INFINITE_GAS_YEARLY)) {
// bought the infinite gas subscription
Log.d(TAG, "Infinite gas subscription purchased.");
alert("Thank you for subscribing to infinite gas!");
mSubscribedToInfiniteGas = true;
mAutoRenewEnabled = purchase.isAutoRenewing();
mInfiniteGasSku = purchase.getSku();
mTank = TANK_MAX;
updateUi();
setWaitScreen(false);
}
}
};
I want to use In-App purchase using Google API and JNI in C++ is there sample or tutorial that use JNI for In-app Billing ?
item in my Game is consumable.
i can use IAP in java and this is main activity class But how i call it From JNI
public class IAPActivity extends Activity {
public static final String RSA= "********";
// Debug tag, for logging
private static final String TAG = "LOG";
// SKUs for our products: the premium upgrade (non-consumable)
private static final String SKU_PREMIUM = "gp";
// Does the user have the premium upgrade?
private boolean mIsPremium = false;
// (arbitrary) request code for the purchase flow
//static final int RC_REQUEST = ;
// The helper object
private IabHelper mHelper;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// You can find it in your Bazaar console, in the Dealers section.
// It is recommended to add more security than just pasting it in your source code;
mHelper = new IabHelper(this, RSA);
final IabHelper.QueryInventoryFinishedListener onQueryInventoryFinished = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
Log.d(TAG, "Query inventory finished.");
//kharid nakarde
if (result.isFailure()) {
Log.d(TAG, "Failed to query inventory: " + result);
return;
}
else {
Log.d(TAG, "Query inventory was successful.");
// does the user have the premium upgrade?
mIsPremium = inventory.hasPurchase(SKU_PREMIUM);
// update UI accordingly
Log.d(TAG, "User is " + (mIsPremium ? "PREMIUM" : "NOT PREMIUM"));
}
Log.d(TAG, "Initial inventory query finished; enabling main UI.");
}
};
final IabHelper.OnIabPurchaseFinishedListener onIabPurchaseFinished = new OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
// TODO Auto-generated method stub
if (result.isFailure()) {
Log.d(TAG, "Error purchasing: " + result);
return;
}
else if (purchase.getSku().equals(SKU_PREMIUM)) {
// give user access to premium content and update the UI
}
}
};
Log.d(TAG, "Starting setup.");
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
Log.d(TAG, "Setup finished.");
if (!result.isSuccess()) {
// Oh noes, there was a problem.
Log.d(TAG, "Problem setting up In-app Billing: " + result);
}
// Hooray, IAB is fully set up!
mHelper.queryInventoryAsync(onQueryInventoryFinished);
}
});
Button btnPurchase=(Button) findViewById(R.id.btnPurchaseGP);
btnPurchase .setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
// TODO Auto-generated method stub
mHelper.launchPurchaseFlow(IAPActivity.this, SKU_PREMIUM, 0, onIabPurchaseFinished, "payload-string");
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
// Pass on the activity result to the helper for handling
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
} else {
Log.d(TAG, "onActivityResult handled by IABUtil.");
}
}
#Override
public void onDestroy() {
super.onDestroy();
if (mHelper != null) mHelper.dispose();
mHelper = null;
}
}
Unfortunately JNI is very complex and i don't any idea for use it please Help me
I'm implementing in-app billing where the user shall be able to buy access to premium content. This is typical non-consumable items. (Let's say the premium content is extra questions or categories in an question-app)
I have used this tutorial to create the first version. The problem is how I shall implement the non-consumable part..
How do I know that the user has bought the premium content? One solution I'm think of is to have a column in my question-table that is initially "0". When the user buy premium access, the this column is set to "1".
Is this a way to go?
Where in my code do I get the message from the billing API that the content is already bought? (If it is..)
My code.. (From tutorial, "buy the possibility to click a button")
public class BuyExtras extends Activity {
private static final String TAG = "inAppBilling";
static final String ITEM_SKU = "android.test.purchased";
IabHelper mHelper;
private Button clickButton;
private Button buyButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "onCreate CALLED");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_buy_extras);
buyButton = (Button)findViewById(R.id.buyButton);
clickButton = (Button)findViewById(R.id.clickButton);
clickButton.setEnabled(false);
String base64EncodedPublicKey =
"<myKey>";
mHelper = new IabHelper(this, base64EncodedPublicKey);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result)
{
if (!result.isSuccess()) {
Log.d(TAG, "In-app Billing setup failed: " +
result);
} else {
Log.d(TAG, "In-app Billing is set up OK");
}
}
});
}
public void buyClick(View view) {
mHelper.launchPurchaseFlow(this, ITEM_SKU, 10001, mPurchaseFinishedListener, "mypurchasetoken");
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
super.onActivityResult(requestCode, resultCode, data);
}
}
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase)
{
if (result.isFailure()) {
// Handle error
return;
}
else if (purchase.getSku().equals(ITEM_SKU)) {
consumeItem();
buyButton.setEnabled(false);
}
}
};
public void consumeItem() {
mHelper.queryInventoryAsync(mReceivedInventoryListener);
}
IabHelper.QueryInventoryFinishedListener mReceivedInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
if (result.isFailure()) {
// Handle failure
} else {
mHelper.consumeAsync(inventory.getPurchase(ITEM_SKU), mConsumeFinishedListener);
}
}
};
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
public void onConsumeFinished(Purchase purchase, IabResult result) {
if (result.isSuccess()) {
clickButton.setEnabled(true);
} else {
// handle error
}
}
};
public void buttonClicked (View view)
{
clickButton.setEnabled(false);
buyButton.setEnabled(true);
}
#Override
public void onDestroy() {
super.onDestroy();
if (mHelper != null) mHelper.dispose();
mHelper = null;
}
}
I read this question indicating that I not should call the
mHelper.consumeAsync(purchase, mConsumeFinishedListener);
But is just removing it ok? Where should I handle the case that the user tries a second buy?
If you don't want consume, then don't use consumeAsync.
#Override
public void onQueryInventoryFinished(IabResult result, Inventory inv)
{
if (result.isFailure())
{
Log.e(TAG, "In-app Billing query failed: " + result);
return;
} else
{
boolean hasPurchased_ITEM_SKU_PURCHASE_1 = inv.hasPurchase(ITEM_SKU_PURCHASE_1);
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
SharedPreferences.Editor editor = sharedPref.edit();
editor.putBoolean(KEY_PREF_PURCHASE_1_AVAILABLE, !hasPurchased_ITEM_SKU_PURCHASE_1);
editor.commit();
// You can update your UI here, ie. Buy buttons.
}
}
You can use the sharedpref to store the purchase info, and also check every onCreate of the activity and update the sharedpref accordingly.
The key part on how to check if a SKU is purchased is:
boolean hasPurchased_ITEM_SKU_PURCHASE_1 = inv.hasPurchase(ITEM_SKU_PURCHASE_1);
Do your query sync in your IAP setup and update your UI accordingly.
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result)
{
if (!result.isSuccess()) {
Log.d(TAG, "In-app Billing setup failed: " +
result);
} else {
mHelper.queryInventoryAsync(mReceivedInventoryListener);
Log.d(TAG, "In-app Billing is set up OK");
}
}
});
I'm trying to implement in-app purchases on fragments. I used the tutorial http://twigstechtips.blogspot.com/2013/12/android-setting-up-in-app-billing-api.html including modifying IabHelper. I also needed to modify MainActivity:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
PremiumFragment premiumFragment = new PremiumFragment();
premiumFragment.onActivityResult(requestCode, resultCode, data);
}
to send the result to a fragment. Problem is when google billing dialog box disappears, I need manualy reload fragment, to call OnIabPurchaseFinishedListener. My code:
public class PremiumFragment extends Fragment implements NamedTopBar,
OnClickListener {
static final String ITEM_SKU_SUBSCRIPTION = "test";
static final int RC_REQUEST = 10001;
IabHelper iabHelper;
private Button subscriptionButton;
private boolean mBillingServiceReady;
private boolean subBool;
// Callback for when a purchase is finished
private IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
#Override
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.d(TAG, "mPurchaseFinishedListener");
// if we were disposed of in the meantime, quit.
if (iabHelper == null) {
return;
}
// Don't complain if cancelling
if (result.getResponse() == IabHelper.IABHELPER_USER_CANCELLED) {
Log.d(TAG, "User canceled purchase");
return;
}
if (!result.isSuccess()) {
Log.d(TAG, "Error purchasing: " + result.getMessage());
if (result.getResponse() == 7) {
Toast.makeText(getActivity(), "item already purchased!",
Toast.LENGTH_LONG).show();
}
return;
}
if (!verifyDeveloperPayload(purchase)) {
Log.d(TAG,
"Error purchasing. Authenticity verification failed.");
return;
}
// Purchase was success! Update accordingly
if (purchase.getSku().equals(ITEM_SKU_SUBSCRIPTION)) {
Toast.makeText(getActivity(),
"Thank you for buying SUBSCRIPTION!", Toast.LENGTH_LONG)
.show();
subBool = true;
}
initialiseStuff(subBool);
}
};
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
#Override
public void onConsumeFinished(Purchase purchase, IabResult result) {
// if we were disposed of in the meantime, quit.
if (iabHelper == null) {
return;
}
if (result.isSuccess()) {
iabHelper.queryInventoryAsync(iabInventoryListener());
} else {
Log.d(TAG, "Error while consuming: " + result);
}
// Update the UI to reflect their latest purchase
initialiseStuff(subBool);
}
};
private View window;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
Log.d(TAG, "onCreate");
initialiseBilling();
}
private void initialiseBilling() {
if (iabHelper != null) {
return;
}
String base64EncodedPublicKey = "";
iabHelper = new IabHelper(getActivity(), base64EncodedPublicKey);
iabHelper.enableDebugLogging(false);
Log.d(TAG, "Starting setup.");
iabHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
#Override
public void onIabSetupFinished(IabResult result) {
// Have we been disposed of in the meantime? If so, quit.
if (iabHelper == null) {
return;
}
// Something went wrong
if (!result.isSuccess()) {
Log.d(TAG,
"Problem setting up in-app billing: "
+ result.getMessage()
);
return;
}
// IAB is fully set up. Now, let's get an inventory of stuff we
// own.
Log.d(TAG, "In-app Billing is set up OK");
mBillingServiceReady = true;
iabHelper.queryInventoryAsync(iabInventoryListener());
}
});
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
window = inflater.inflate(R.layout.premium_fragment, null);
initViews();
return window;
}
#Override
public void onDestroy() {
super.onDestroy();
if (iabHelper != null) {
iabHelper.dispose();
iabHelper = null;
}
}
private void initViews() {
subscriptionButton = (Button) window
.findViewById(R.id.buy_premium_button);
subscriptionButton.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.buy_premium_button:
Log.d(TAG, "buy_premium_button");
if (mBillingServiceReady) {
/*
* TODO: for security, generate your payload here for
* verification. See the comments on verifyDeveloperPayload()
* for more info. Since this is a SAMPLE, we just use an empty
* string, but on a production app you should carefully generate
* this.
*/
if (iabHelper != null)
iabHelper.flagEndAsync();
String payload = "";
iabHelper.launchPurchaseFlow(getActivity(),
ITEM_SKU_SUBSCRIPTION, RC_REQUEST,
mPurchaseFinishedListener, payload);
} else {
showToast();
}
break;
}
}
private void showToast() {
Toast.makeText(
getActivity(),
"Purchase requires Google Play Store (billing) on your Android.",
Toast.LENGTH_LONG).show();
}
private IabHelper.QueryInventoryFinishedListener iabInventoryListener() {
return new IabHelper.QueryInventoryFinishedListener() {
#Override
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
// Have we been disposed of in the meantime? If so, quit.
if (iabHelper == null) {
return;
}
// Something went wrong
if (!result.isSuccess()) {
Log.d(TAG,
"onFailure: QueryInventoryFinishedListener," +
"result: " + result
);
return;
}
Log.d(TAG, "Checking for purchases");
Purchase purchaseSubscription = inventory
.getPurchase(ITEM_SKU_SUBSCRIPTION);
subBool = (purchaseSubscription != null && verifyDeveloperPayload(purchaseSubscription));
initialiseStuff(subBool);
}
};
}
private void initialiseStuff(boolean subBool) {
if (subBool) {
subscriptionButton.setText("You already have premium");
subscriptionButton.setEnabled(false);
} else {
subscriptionButton.setEnabled(true);
}
}
boolean verifyDeveloperPayload(Purchase purchase) {
// String payload = p.getDeveloperPayload();
return true;
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (iabHelper == null)
return;
// Pass on the activity result to the helper for handling
if (!iabHelper.handleActivityResult(requestCode, resultCode, data)) {
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
} else {
Log.d(TAG, "onActivityResult handled by IABUtil.");
}
}
How to call mPurchaseFinishedListener automatically after dialog box disappears?
I have been struggling with this for over a week. I am working on subscriptions on the android use their In-App Billing Version 3 I built the code and have it running for purchase but as it was done last year this version did not support subscriptions and since I put this together from the example I don't have code to build the code to use subscriptions.
Here is the code I have in place for purchases and as I understand it I need to alter these to work with subscriptions instead of purchases plus add the code for determining if a subscription is valid on the google server. I do not see code for that right now.
String base64EncodedPublicKey = "MI...QAB";
mHelper = new IabHelper(this, base64EncodedPublicKey);
// enable debug logging (for a production application, you should set
// this to false).
mHelper.enableDebugLogging(false);
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
// Oh noes, there was a problem.
// complain("1 "+"Problem setting up in-app billing: " +
// result);
return;
}
mHelper.queryInventoryAsync(mGotInventoryListener);
}
});
// Listener that's called when we finish querying the items we own
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
// ///Log.d(TAG, "Query inventory finished.");
if (result.isFailure()) {
// complain("2 "+"Failed to query inventory: " + result);
return;
}
// ///Log.d(TAG, "Query inventory was successful.");
// place code here to proceess purchase without reaccessing database
if (inventory.hasPurchase(appSKU)) {
// ///Log.i("Purchase","purchase consumed here");
//mHelper.consumeAsync(inventory.getPurchase(appSKU),mConsumeFinishedListener);
return;
}
}
};
public void order(String appSKU) {
mHelper.launchPurchaseFlow(this, appSKU, RC_REQUEST,
mPurchaseFinishedListener);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + ","
// + data);
// Pass on the activity result to the helper for handling
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
} else {
// ///Log.d(TAG, "onActivityResult handled by IABUtil.");
}
}
// Callback for when a purchase is finished
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
// ///Log.d(TAG, "Purchase finished: " + result + ", purchase: " +
// purchase);
if(purchase == null) {
;
}else {
String tester1 = purchase.toString();
// ///Log.d(TAG, "Purchase successful.");
// mHelper.consumeAsync(purchase, mConsumeFinishedListener);
// myCallServer(udid, calltype, data, OrderID, ProductId, PurchaseToken) {
Bundle myBundle = new Bundle();
myBundle.putString("AppTitle", AppTitle);
Intent myIntent = new Intent(getBaseContext(),
IntroALevActivity.class);
myIntent.putExtras(myBundle);
startActivity(myIntent);
}
}
};
// Called when consumption is complete
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
public void onConsumeFinished(Purchase purchase, IabResult result) {
// ///Log.d(TAG, "Consumption finished. Purchase: " + purchase +
// ", result: " + result);
// We know this is the "gas" sku because it's the only one we
// consume,
// so we don't check which sku was consumed. If you have more than
// one
// sku, you probably should check...
if (result.isSuccess()) {
// successfully consumed, so we apply the effects of the item in
// our
// game world's logic, which in our case means filling the gas
// tank a bit
alert("You made a purchase");
} else {
;
}
}
};
I have looked online but I have only found broken pieces of code to help me determine what the exact method code would be to check for existing subscriptions. If some one could look at my code and supply the method I am missing it would be great. Google examples have usually been good but since subscriptions have just been added to V3 as of Feb 15th there are not a lot of coding examples to build from.
I am struggling so if you have any questions or need additional information just let me know and I will do the best I can to supply it.
Thanks to the stackoverflow members
Even though I'm not using subscriptions in my implementation you can check that in your IabHelper.QueryInventoryFinishedListener mGotInventoryListener function. So instead of this:
// ///Log.d(TAG, "Query inventory was successful.");
// place code here to proceess purchase without reaccessing database
if (inventory.hasPurchase(appSKU)) {
// ///Log.i("Purchase","purchase consumed here");
//mHelper.consumeAsync(inventory.getPurchase(appSKU),mConsumeFinishedListener);
return;
}
Use this:
Purchase haspurchase = inventory.getPurchase(appSKU);
if (haspurchase = null) {
// do something since there wasn't a purchase
}
else {
// do something if you have the purchase
}
To work with in app subscription i think you will gave to call "launchSubscriptionPurchaseFlow()" method on IabHelper instance you create.
mHelper.launchSubscriptionPurchaseFlow(Activity act, String sku, int requestCode,
OnIabPurchaseFinishedListener listener, String extraData);
OR
mHelper.launchPurchaseFlow(Activity act, String sku, String itemType, int requestCode,
OnIabPurchaseFinishedListener listener, String extraData);
Where itemType = IabHelper.ITEM_TYPE_SUBS