10

I am pulling my hair out! At one point in the last week, I had this working.

I have an Android app that I am trying to add in-ap billing to. I followed the sample TrivialDrive, and my code worked a few times. Now it doesn't.

I am creating a simple trivia game that has a number of free questions, and the option to upgrade to get more questions. When the user completes the list of free questions, they are taken to a "Game Over" screen where they can erase their answers and start again, or upgrade.

When I click the "Upgrade" button, I can make a successful purchase, but as soon as the Google "Payment Successful" dialog goes away, my activity is destroyed and I am sent back to my main activity.

When I try to go back and do my purchase again, my code catches the error ("You already own this item") and handles it appropriately. My code explains to the user that they already own the upgrade, and allows them to click a button to continue playing. So it looks like the OnIabPurchaseFinishedListener is firing at this point.

I have updated the Google helper code with the latest files.

Any help or suggestions as to where to look for answers is much appreciated.

Thanks.

This is the relevant code for my activity:

public class GameOverActivity extends BaseActivity
{

    private IabHelper       mHelper;
    private String          m_base64EncodedPublicKey;
    private static String   THE_UPGRADE_SKU = "upgrade52";
    public static int BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED = 7;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_game_over);

        setTitle("Game Over");

        Button butPlay = (Button) findViewById(R.id.buttonPlay);
        butPlay.setVisibility(View.INVISIBLE);

        PrepareIAB();
    }

    @Override
    protected void onResume()
    {
        super.onResume();
        CURRENT_ACTIVITY = ACTIVITY_GAME_OVER;
        SetMainText();
    }

    @Override
    protected void onDestroy()
    {
        super.onDestroy();
        try
        {
            if (mHelper != null)
            {
                mHelper.dispose();
                mHelper = null;
            }
        }
        catch (Exception e)
        {
        }       
    }

    private void PrepareIAB()
    {
        m_base64EncodedPublicKey = "MyKey";

        // compute your public key and store it in base64EncodedPublicKey
        mHelper = new IabHelper(this, m_base64EncodedPublicKey);
        mHelper.enableDebugLogging( true, TAG);

        mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener()
        {
            public void onIabSetupFinished(IabResult result)
            {
                if (!result.isSuccess())
                {

                    ShowMessage("There was an error connecting to the Google Play Store.");
                }
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {           
         try 
         {
            // 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.");
                }    
         }
         catch (Exception e)
         {
             super.onActivityResult(requestCode, resultCode, data); 
         }
    }



    IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener   = 
            new IabHelper.OnIabPurchaseFinishedListener()
            {
                public void onIabPurchaseFinished(IabResult result, Purchase purchase)
                {
                    try 
                    {
                        if (result.isFailure())
                        {                       
                            if (result.mResponse==7)
                            {
                                UpgradeComplete();
                                ShowMessage("Thank you for upgrading.\r\n\r\nThis version has 400 more questions.");        
                            }
                            else
                            {

                                ShowMessage("Error purchasing: " + String.valueOf(result.mResponse));                           
                                UpgradeError();

                                return;
                            }

                        }
                        else if (purchase.getSku().equals(THE_UPGRADE_SKU))
                        {               
                            UpgradeComplete();
                            ShowMessage("Thank you for upgrading.\r\n\r\nThis version has 400 more questions.");                                        
                        }
                        else
                        {
                            ShowMessage("Something else happened. ");
                        }
                    }
                    catch (Exception e)
                    {
                        Log.e(TAG, e.getLocalizedMessage());
                    }

                }
            };

    private void HideUpgrade()
    {
        try 
        {
            Button btnUpgrade = (Button) findViewById(R.id.buttonUpgrade);
            if (btnUpgrade != null)
            {
                btnUpgrade.setVisibility(View.INVISIBLE);
            }           

            TextView txtMessage = (TextView) findViewById(R.id.txtUpgradeFromGameOver);
            if (txtMessage!=null)
            {
                txtMessage.setVisibility(View.INVISIBLE);   
            }   
        }
        catch (Exception e)
        {

        }        
    }

    public void onQuitButtonClick(View view)
    {
        finish();
    }

    public void onResetDBButtonClick(View view)
    {
        ConfirmResetDatabase();
    }

    private void ConfirmResetDatabase()
    {
        DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener()
        {
            @Override
            public void onClick(DialogInterface dialog, int which)
            {
                switch (which)
                {
                    case DialogInterface.BUTTON_POSITIVE:

                        ResetDatabase();

                        Intent gameActivity = new Intent(getApplicationContext(), GameActivity.class);

                        gameActivity.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
                        // startActivityForResult(gameActivity, ACTIVITY_GAME);
                        startActivity(gameActivity);
                        break;

                    case DialogInterface.BUTTON_NEGATIVE:
                        // No button clicked
                        break;
                }
            }
        };

        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage("Do you want to erase your score and start over?").setPositiveButton("Yes", dialogClickListener).setNegativeButton("No", dialogClickListener).show();
    }


    public void onUpgradeButtonClick(View view)
    {           
        try 
        {
            if (mHelper != null)
            {
                mHelper.launchPurchaseFlow(this, THE_UPGRADE_SKU, 10001, mPurchaseFinishedListener, m_TriviaAppInstance.AppInstallID());
            }
            else
            {
                ShowMessage("Unable to connect to Google Play Store.");         
            }   
        }
        catch (Exception e)
        {
            ShowMessage("Unable to connect to Google Play Store.");
            SendErrorMessage(e.getLocalizedMessage());          
        }
    }



    private void UpgradeComplete()
    {
        try
        {    
            HideUpgrade();

            Button butPlay = (Button) findViewById(R.id.buttonPlay);
            if (butPlay!=null)
            {
                butPlay.setVisibility(View.VISIBLE);    
            }

            TextView txtReset = (TextView) findViewById(R.id.txtGameOverRestDB);
            if (txtReset!=null)
            {
                txtReset.setVisibility(View.INVISIBLE); 
            }

            Button btnReset = (Button)findViewById(R.id.buttonResetDB);
            if (btnReset!=null)
            {
                btnReset.setVisibility(View.INVISIBLE);
            }

            m_TriviaAppInstance.SetUpgradedStatus(true);

        }
        catch (Exception e)
        {

        }

        //

    }

    private void UpgradeError()
    {
        try
        {
            Button butUpgrade;
            butUpgrade = (Button) findViewById(R.id.buttonUpgrade);
            butUpgrade.setVisibility(View.INVISIBLE);

            TextView txtMessage = (TextView) findViewById(R.id.txtUpgradeScreen);
            txtMessage.setText(R.string.upgradeScreenTextError);
        }
        catch (Exception e)
        {
        }
    }


    public void onPlayButtonClick(View view)
    {
        Intent myIntent = new Intent(view.getContext(), GameActivity.class);
        myIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
        startActivityForResult(myIntent, ACTIVITY_GAME);
    }

    public void SetMainText()
    {
        TextView txt = (TextView) findViewById(R.id.txtScoreGlobal);
        txt.setText(Integer.toString(m_TriviaAppInstance.getGlobal()) + "%");
        SetPlayerScore(1);

        if (m_TriviaAppInstance.getUpgradedStatus() == true)
        {           
            HideUpgrade();          
        }       
    }

}
Jay MacDonald
  • 233
  • 3
  • 8
  • Update: My code must be doing something right. My test purchases are showing up in my Google merchant account. But something is still not working because the successful purchase is not being indicated to the user (me). – Jay MacDonald Jul 01 '13 at 14:34
  • The onIabPurchaseFinished event is not firing at all after a successful purchase. BUT, it does fire if the user already owns the item. – Jay MacDonald Jul 01 '13 at 14:51
  • 1
    FYI: I think I have this figured out - for anyone else that may come across it. The activity that I was using to launch Google Play store was called with a "FLAG_ACTIVITY_NO_HISTORY". I did this because I didn't want the user to be able to click to go back to this "Game Over" activity. BUT, this causes grief with "In App Billing". So, make sure you don't try to launch "In App Billing" from an activity that has had the "FLAG_ACTIVITY_NO_HISTORY" set. Peace – Jay MacDonald Jul 01 '13 at 18:50

3 Answers3

13

FYI: I think I have this figured out - for anyone else that may come across it.

The activity that I was using to launch "In App Billing" was called with a "FLAG_ACTIVITY_NO_HISTORY". I did this because I didn't want the user to be able to click to go back to this "Game Over" activity.

BUT, this causes grief with "In App Billing". So, make sure you don't try to launch "In App Billing" from an activity that has had the "FLAG_ACTIVITY_NO_HISTORY" set.

My original code:

private void GameOver()
    {
        m_TriviaAppInstance.setGameOver(true);
        Intent gameOver = new Intent(getApplicationContext(), GameOverActivity.class);
        gameOver.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
        startActivity(gameOver);
    }

Updated code:

private void GameOver()
    {
        m_TriviaAppInstance.setGameOver(true);
        Intent gameOver = new Intent(getApplicationContext(), GameOverActivity.class);       
        startActivity(gameOver);
    }

Peace

Jay MacDonald
  • 233
  • 3
  • 8
  • 1
    Omg, you are my hero! Saved my so much headache. This is from 2013 and Google still hasn't fixed this issue? Or even documented it. – Johan Paul Jun 07 '16 at 16:04
  • YOU, YOU, YOU! You, My friend, You deserve a standing ovation! I had been grappling with this for almost 2 hours now. And removing that one teeny-tiny flag solved everything!!!! And come to think of it, now everything is sooooooo easy. (Also, weird coincidence, I have been working on this project for 2 months now, and today, I tried was the first day that I tried two `startActivityForResult` from the same activity, which I have never done before. I am crazed as hell, thank you so much! ) – IcyFlame Jul 01 '16 at 10:35
8

I'm not high enough to comment, but bless you. I had

android:noHistory="true"

set in AndroidManifest.xml for my activity and was experiencing the same problem.

Took it out and IAB is working. Yay!

Mark
  • 689
  • 10
  • 17
1

Do not forget that your IabHelper.OnIabPurchaseFinishedListener is called on a different thread and before onResume() is called on your Activity!

So your UpgradeComplete() or UpgradeError() can cause a crash on older devices (Crashed every time on my Gingerbread Sony Xperia Mini Pro and worked without any trouble on Samsung Galaxy S4 (Android 4.2.2)

Caused a 3 day delay on my game..

Marek Halmo
  • 2,181
  • 2
  • 15
  • 18
  • So what was your solution to get it working on Gingerbread. I'm actually facing the same issue right now. What I can think of is, do I need to update UI related stuff on a UIThread? And may be that would solve the problem. Thanks for the pointer you already provided. – Souvik Ghosh Jul 07 '15 at 06:19