1

我从 Android 中实现了关于如何实现In-App Billing(IAB) 的示例。以下是我必须添加到我的代码中以使其工作的 10 个类之一。我以为我可以正常工作,但是当我在手机上对其进行测试并将应用程序导航到以下BibleStudy活动时,屏幕加载然后开始“闪烁”或可能一遍又一遍地重新加载屏幕,因此看起来屏幕只是一遍又一遍地闪烁。

我不完全理解这个类(以及其他 9 个类)中的 IAB 过程,所以我对下面代码中的错误位置有点困惑。

所以我的问题是,在我下面的代码中,是什么让我的活动在加载时不断闪烁?

public class BibleStudy extends SwarmActivity {

    static final String SKU_SPREADSHEET = "spreadsheet";

    boolean mIsPurchased = false;

    TextView title, link;
    Button purchaseBtn;

    Context c;

    IabHelper mHelper;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.biblestudy);

        c = this;

        String base64EncodedPublicKey = a + b + d + e + f + g + h + i + j + k;

        // Create the helper, passing it our context and the public key to verify signatures with
        mHelper = new IabHelper(this, base64EncodedPublicKey);

        // Start setup. This is asynchronous and the specified listener will be called once setup completes.
        mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
            public void onIabSetupFinished(IabResult result) {

                if (!result.isSuccess()) {
                    // Oh noes, there was a problem.
                    complain("An error has occurred.  We apologize for the inconvenience.    " + c.getResources().getString(R.string.problem1) + " " + result);
                    return;
                }

                // Hooray, IAB is fully set up. Now, let's get an inventory of stuff we own.
                mHelper.queryInventoryAsync(mGotInventoryListener);
            }
        });

        if(mIsPurchased == true) {
            purchaseBtn.setText(c.getResources().getString(R.string.thankyou2));
            title.setText(c.getResources().getString(R.string.thankyou));
            purchaseBtn.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    alreadyOwned();
                }
            });
        } else {
            title.setText(c.getResources().getString(R.string.biblestudy));
            purchaseBtn.setText(c.getResources().getString(R.string.purchaseBtn));
            purchaseBtn.setOnClickListener(new OnClickListener() {
                // User clicked the "Download NOW!" button.
                public void onClick(View v) {
                    String payload = "";
                    test(payload);
                }
            });
        }
    }

    public void alreadyOwned() {

        final Dialog dialog = new Dialog(c);
        dialog.setContentView(R.layout.alreadyowned);

        TextView tv = (TextView)dialog.findViewById(R.id.tv);

        tv.setText(c.getResources().getString(R.string.alreadyowned));

        dialog.show();
    }

    public void test(String payload) {
        mHelper.launchPurchaseFlow(this, SKU_SPREADSHEET, 10001, mPurchaseFinishedListener, payload);
    }

    // Listener that's called when we finish querying the items and subscriptions we own.
    IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
        public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
            if (result.isFailure()) {
                complain("An error has occurred.  We apologize for the inconvenience.  " + c.getResources().getString(R.string.failedtoquery) + " " + 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().
             */

            Purchase spreadsheetPurchase = inventory.getPurchase(SKU_SPREADSHEET);

            mIsPurchased = (spreadsheetPurchase != null && verifyDeveloperPayload(spreadsheetPurchase));

            updateUi();
        }
    };

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent 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);
        }
    }

    /** Verifies the developer payload of a purchase. */
    boolean verifyDeveloperPayload(Purchase p) {
        String payload = p.getDeveloperPayload();

        /*
         * TODO: verify that the developer payload of the purchase is correct. It will be
         * the same one that you sent when initiating the purchase.
         * 
         * WARNING: Locally generating a random string when starting a purchase and 
         * verifying it here might seem like a good approach, but this will fail in the 
         * case where the user purchases an item on one device and then uses your app on 
         * a different device, because on the other device you will not have access to the
         * random string you originally generated.
         *
         * So a good developer payload has these characteristics:
         * 
         * 1. If two different users purchase an item, the payload is different between them,
         *    so that one user's purchase can't be replayed to another user.
         * 
         * 2. The payload must be such that you can verify it even when the app wasn't the
         *    one who initiated the purchase flow (so that items purchased by the user on 
         *    one device work on other devices owned by the user).
         * 
         * Using your own server to store and verify developer payloads across app
         * installations is recommended.
         */

        return true;
    }

    // Callback for when a purchase is finished
    IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
        public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
            if(result.isFailure()) {
                complain("An error has occurred.  We apologize for the inconvenience.  " + result);
                return;
            }

            if(!verifyDeveloperPayload(purchase)) {
                complain("An error has occurred.  We apologize for the inconvenience.  " + c.getResources().getString(R.string.error2));
                return;
            }

            else if(purchase.getSku().equals(SKU_SPREADSHEET)) {
                // this appears to the user immediately after purchasing.
                alert(c.getResources().getString(R.string.purchased));
                mIsPurchased = true;
                updateUi();
            }
        }
    };

    // updates UI to reflect model
    public void updateUi() {

        if(mIsPurchased == true) {
            link.setClickable(true);
            link.setMovementMethod(LinkMovementMethod.getInstance());
            String a = "<a href='https://docs.google.com/spreadsheet/ccc?key=0At8avx-xtho6dHhkVzRUNkpJWFBNeGc4S3U1X0k0RFE&usp=sharing'>here</a>";
            String b = c.getResources().getString(R.string.link1) + " ";
            String e = " " + c.getResources().getString(R.string.link3);
            String d = b + a + e;
            link.setText(Html.fromHtml(d));

            Intent intent = new Intent(BibleStudy.this, BibleStudy.class);
            startActivity(intent);
        }
    }

    void complain(String message) {
        alert("Error: " + message);
    }

    void alert(String message) {
        AlertDialog.Builder bld = new AlertDialog.Builder(this);
        bld.setMessage(message);
        bld.setNeutralButton("OK", null);
        bld.create().show();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if(mHelper != null) mHelper.dispose();
        mHelper = null;
    }
}
4

1 回答 1

0

确保您使用的是谷歌开发者控制台中给出的正确 base64EncodedPublicKey。

我看过你的代码并且有一些代码可能会解决你的错误。您尚未将此代码放入您的活动中,请尝试将其添加到您的活动中。但如果它不起作用,请不要删除它,它不会影响您的代码,但它是应用程序内所必需的计费。

// 你可以用这个替换 BibleActivity java 文件。圣经活动.java:

public class BibleStudy extends SwarmActivity {

    static final String SKU_SPREADSHEET = "spreadsheet";

    boolean mIsPurchased = false;

    TextView title, link;
    Button purchaseBtn;

    Context c;

    IabHelper mHelper;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.biblestudy);

        c = this;

        String base64EncodedPublicKey = a + b + d + e + f + g + h + i + j + k;

        // Some sanity checks to see if the developer (that's you!) really
    // followed the
    // instructions to run this sample (don't put these checks on your app!)
    if (base64EncodedPublicKey.contains("CONSTRUCT_YOUR")) {
        throw new RuntimeException(
                "Please put your app's public key in MainActivity.java. See README.");
    }
            // add your packageName here
    if (getPackageName().startsWith("add_your_package_name_here")) {
        // throw new
        // RuntimeException("Please change the sample's package name! See README.");
    }

        // Create the helper, passing it our context and the public key to verify signatures with
        mHelper = new IabHelper(this, base64EncodedPublicKey);

        // Start setup. This is asynchronous and the specified listener will be called once setup completes.
        mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
            public void onIabSetupFinished(IabResult result) {

                if (!result.isSuccess()) {
                    // Oh noes, there was a problem.
                    complain("An error has occurred.  We apologize for the inconvenience.    " + c.getResources().getString(R.string.problem1) + " " + result);
                    return;
                }

                // Hooray, IAB is fully set up. Now, let's get an inventory of stuff we own.
                mHelper.queryInventoryAsync(mGotInventoryListener);
            }
        });

        if(mIsPurchased == true) {
            purchaseBtn.setText(c.getResources().getString(R.string.thankyou2));
            title.setText(c.getResources().getString(R.string.thankyou));
            purchaseBtn.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    alreadyOwned();
                }
            });
        } else {
            title.setText(c.getResources().getString(R.string.biblestudy));
            purchaseBtn.setText(c.getResources().getString(R.string.purchaseBtn));
            purchaseBtn.setOnClickListener(new OnClickListener() {
                // User clicked the "Download NOW!" button.
                public void onClick(View v) {
                    String payload = "";
                    test(payload);
                }
            });
        }
    }

    public void alreadyOwned() {

        final Dialog dialog = new Dialog(c);
        dialog.setContentView(R.layout.alreadyowned);

        TextView tv = (TextView)dialog.findViewById(R.id.tv);

        tv.setText(c.getResources().getString(R.string.alreadyowned));

        dialog.show();
    }

    public void test(String payload) {
      // if device is not supported
       if (!mHelper.subscriptionsSupported()) {
            complain("Subscriptions not supported on your device yet. Sorry!");
       return;
       }

        mHelper.launchPurchaseFlow(this, SKU_SPREADSHEET, 10001, mPurchaseFinishedListener, payload);
    }

    // Listener that's called when we finish querying the items and subscriptions we own.
    IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
        public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
            if (result.isFailure()) {
                complain("An error has occurred.  We apologize for the inconvenience.  " + c.getResources().getString(R.string.failedtoquery) + " " + 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().
             */

            Purchase spreadsheetPurchase = inventory.getPurchase(SKU_SPREADSHEET);

            mIsPurchased = (spreadsheetPurchase != null && verifyDeveloperPayload(spreadsheetPurchase));

            updateUi();
        }
    };

  // replace your onActivityResult() with this one.

   @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + ","
            + data);

    if (mHelper == null)
        return;

    // 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.");
    }
}

    /** Verifies the developer payload of a purchase. */
    boolean verifyDeveloperPayload(Purchase p) {
        String payload = p.getDeveloperPayload();

        /*
         * TODO: verify that the developer payload of the purchase is correct. It will be
         * the same one that you sent when initiating the purchase.
         * 
         * WARNING: Locally generating a random string when starting a purchase and 
         * verifying it here might seem like a good approach, but this will fail in the 
         * case where the user purchases an item on one device and then uses your app on 
         * a different device, because on the other device you will not have access to the
         * random string you originally generated.
         *
         * So a good developer payload has these characteristics:
         * 
         * 1. If two different users purchase an item, the payload is different between them,
         *    so that one user's purchase can't be replayed to another user.
         * 
         * 2. The payload must be such that you can verify it even when the app wasn't the
         *    one who initiated the purchase flow (so that items purchased by the user on 
         *    one device work on other devices owned by the user).
         * 
         * Using your own server to store and verify developer payloads across app
         * installations is recommended.
         */

        return true;
    }

    // Callback for when a purchase is finished
    IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
        public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
            if(result.isFailure()) {
                complain("An error has occurred.  We apologize for the inconvenience.  " + result);
                return;
            }

            if(!verifyDeveloperPayload(purchase)) {
                complain("An error has occurred.  We apologize for the inconvenience.  " + c.getResources().getString(R.string.error2));
                return;
            }

            if(purchase.getSku().equals(SKU_SPREADSHEET)) {
                // this appears to the user immediately after purchasing.
                alert(c.getResources().getString(R.string.purchased));
                Log.d(TAG, "Purchase is gas. Starting gas consumption.");
            mHelper.consumeAsync(purchase, mConsumeFinishedListener);
                mIsPurchased = true;
                updateUi();
            }
        }
    };

// Called when consumption is complete it is required for the console to verify transaction consume is completed. 
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
            Log.d(TAG, "Consumption successful. Provisioning.");
            mTank = mTank == TANK_MAX ? TANK_MAX : mTank + 1;
            // saveData();
            alert("You filled 1/4 tank. Your tank is now "
                    + String.valueOf(mTank) + "/4 full!");
        } else {
            complain("Error while consuming: " + result);
        }
        // updateUi();
        // setWaitScreen(false);
        Log.d(TAG, "End consumption flow.");
    }
};


    // updates UI to reflect model
    public void updateUi() {

        if(mIsPurchased == true) {
            link.setClickable(true);
            link.setMovementMethod(LinkMovementMethod.getInstance());
            String a = "<a href='https://docs.google.com/spreadsheet/ccc?key=0At8avx-xtho6dHhkVzRUNkpJWFBNeGc4S3U1X0k0RFE&usp=sharing'>here</a>";
            String b = c.getResources().getString(R.string.link1) + " ";
            String e = " " + c.getResources().getString(R.string.link3);
            String d = b + a + e;
            link.setText(Html.fromHtml(d));

            Intent intent = new Intent(BibleStudy.this, BibleStudy.class);
            startActivity(intent);
        }
    }

    void complain(String message) {
        alert("Error: " + message);
    }

    void alert(String message) {
        AlertDialog.Builder bld = new AlertDialog.Builder(this);
        bld.setMessage(message);
        bld.setNeutralButton("OK", null);
        bld.create().show();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if(mHelper != null) mHelper.dispose();
        mHelper = null;
    }
}

希望它会帮助你。

于 2013-06-15T06:26:45.647 回答