草庐IT

Android 应用内购买 V3 错误 : Authentication is required

coder 2023-06-07 原文

我正在实现 Google In-app Purchase V3 并遵循 here 中所述的所有步骤以及官方文档 here .我已经在 Google Playstore 中上传了我的应用程序以进行 Alpha 测试,并且我已经从 playstore URL 下载到我的真实设备中,但它给了我错误

Error

Authentication is required. You need to sign into your Google Account.

我的应用内购买代码在这里:

public class BuyPointsFragment extends Fragment
//In app Billing variable start

    // Debug tag, for logging
        static final String TAG = "com.myApp";

        // Does the user have the premium upgrade?
        boolean mIsPremium = false;

        // Does the user have an active subscription to the infinite gas plan?
        boolean mSubscribedToInfiniteGas = false;

        // SKUs for our products: the premium upgrade (non-consumable) and gas
        // (consumable)
        static final String SKU_PREMIUM = "premium";
        static final String SKU_GAS = "gas";

        // SKU for our subscription (infinite gas)
        static final String SKU_INFINITE_GAS = "infinite_gas";

        // (arbitrary) request code for the purchase flow
        static final int RC_REQUEST = 10001;

        // Graphics for the gas gauge
        static int[] TANK_RES_IDS = {};

        // How many units (1/4 tank is our unit) fill in the tank.
        static final int TANK_MAX = 4;

        // Current amount of gas in tank, in units
        int mTank;

        // The helper object
        IabHelper mHelper;
        
    

    //In app billing variable end



@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
    //inapp  load game data
            loadData();
            
            String base64EncodedPublicKey = "Base64Key from publisher account";

            // 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.");
            }
            if (getActivity().getPackageName().startsWith("com.myApp.activity")) {
                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
            Log.d(TAG, "Creating IAB helper.");
            mHelper = new IabHelper(getActivity(), base64EncodedPublicKey);

            // enable debug logging (for a production application, you should set
            // this to false).
            mHelper.enableDebugLogging(true);

            // Start setup. This is asynchronous and the specified listener
            // will be called once setup completes.
            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.
                        complain(getString(R.string.problem_setting_inapp_billing) + result);
                        return;
                    }

                    // Have we been disposed of in the meantime? If so, quit.
                    if (mHelper == null)
                        return;

                    // IAB is fully set up. Now, let's get an inventory of stuff we
                    // own.
                    Log.d(TAG, "Setup successful. Querying inventory.");
                    mHelper.queryInventoryAsync(mGotInventoryListener);
                    
                    
                    
                }
            });

            //In app billing code end here
    }

//应用内计费方式从这里开始

public void inappCall(){
    
    setWaitScreen(true);
    Log.d(TAG, "Launching purchase flow for gas.");

    /*
     * 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.
     */
    String payload = "";

    mHelper.launchPurchaseFlow(getActivity(), SKU_GAS, RC_REQUEST,
            mPurchaseFinishedListener, payload);
}

    // updates UI to reflect model
        public void updateUi() {
            // update the car color to reflect premium status or lack thereof
            // ((ImageView)findViewById(R.id.free_or_premium)).setImageResource(mIsPremium
            // ? R.drawable.premium : R.drawable.free);

            // "Upgrade" button is only visible if the user is not premium
            // findViewById(R.id.upgrade_button).setVisibility(mIsPremium ?
            // View.GONE : View.VISIBLE);

            // "Get infinite gas" button is only visible if the user is not
            // subscribed yet
            // (R.id.infinite_gas_button).setVisibility(mSubscribedToInfiniteGas ?
            // View.GONE : View.VISIBLE);

            // update gas gauge to reflect tank status
            if (mSubscribedToInfiniteGas) {
                // ((ImageView)findViewById(R.id.gas_gauge)).setImageResource(R.drawable.gas_inf);
            } else {
                int index = mTank >= TANK_RES_IDS.length ? TANK_RES_IDS.length - 1
                        : mTank;
                // ((ImageView)findViewById(R.id.gas_gauge)).setImageResource(TANK_RES_IDS[index]);
            }
        }

        // Enables or disables the "please wait" screen.
        void setWaitScreen(boolean set) {
            // findViewById(R.id.screen_main).setVisibility(set ? View.GONE :
            // View.VISIBLE);
            // findViewById(R.id.screen_wait).setVisibility(set ? View.VISIBLE :
            // View.GONE);
        }

        void complain(String message) {
            Log.e(TAG, "**** TrivialDrive Error: " + message);
            alert("Error: " + message);
        }

        void alert(String message) {
            AlertDialog.Builder bld = new AlertDialog.Builder(getActivity());
            bld.setMessage(message);
            bld.setNeutralButton("OK", null);
            Log.d(TAG, "Showing alert dialog: " + message);
            bld.create().show();
        }

        void saveData() {

            /*
             * WARNING: on a real application, we recommend you save data in a
             * secure way to prevent tampering. For simplicity in this sample, we
             * simply store the data using a SharedPreferences.
             */

            SharedPreferences.Editor spe = getActivity().getPreferences(getActivity().MODE_PRIVATE).edit();
            spe.putInt("tank", mTank);
            spe.commit();
            Log.d(TAG, "Saved data: tank = " + String.valueOf(mTank));
        }

        void loadData() {
            SharedPreferences sp = getActivity().getPreferences(getActivity().MODE_PRIVATE);
            mTank = sp.getInt("tank", 2);
            Log.d(TAG, "Loaded data: tank = " + String.valueOf(mTank));
        }
    
        // We're being destroyed. It's important to dispose of the helper here!
        @Override
        public void onDestroy() {
            super.onDestroy();

            // very important:
            Log.d(TAG, "Destroying helper.");
            if (mHelper != null) {
                mHelper.dispose();
                mHelper = null;
            }
        }
        
        // 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) {
                Log.d(TAG, "Query inventory finished.");

                // Have we been disposed of in the meantime? If so, quit.
                if (mHelper == null)
                    return;

                // Is it a failure?
                if (result.isFailure()) {
                    complain(getString(R.string.failed_to_query_inventory) + result);
                    return;
                }

                Log.d(TAG, "Query inventory was successful.");

                /*
                 * 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);
                mIsPremium = (premiumPurchase != null && verifyDeveloperPayload(premiumPurchase));
                Log.d(TAG, "User is " + (mIsPremium ? "PREMIUM" : "NOT PREMIUM"));

                // Do we have the infinite gas plan?
                Purchase infiniteGasPurchase = inventory
                        .getPurchase(SKU_INFINITE_GAS);
                mSubscribedToInfiniteGas = (infiniteGasPurchase != null && verifyDeveloperPayload(infiniteGasPurchase));
                Log.d(TAG, "User "
                        + (mSubscribedToInfiniteGas ? "HAS" : "DOES NOT HAVE")
                        + " infinite gas subscription.");
                if (mSubscribedToInfiniteGas)
                    mTank = TANK_MAX;

                // Check for gas delivery -- if we own gas, we should fill up the
                // tank immediately
                Purchase gasPurchase = inventory.getPurchase(SKU_GAS);
                if (gasPurchase != null && verifyDeveloperPayload(gasPurchase)) {
                    Log.d(TAG, "We have gas. Consuming it.");
                    mHelper.consumeAsync(inventory.getPurchase(SKU_GAS),
                            mConsumeFinishedListener);
                    return;
                }

                updateUi();
                setWaitScreen(false);
                Log.d(TAG, "Initial inventory query finished; enabling main UI.");
            }
        };
        
        /** 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) {
                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(getString(R.string.error_purchase) + result);
                    setWaitScreen(false);
                    return;
                }
                if (!verifyDeveloperPayload(purchase)) {
                    complain(getString(R.string.error_purchase_authenitcity_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.");
                    mHelper.consumeAsync(purchase, mConsumeFinishedListener);
                } else if (purchase.getSku().equals(SKU_PREMIUM)) {
                    // bought the premium upgrade!
                    Log.d(TAG, "Purchase is premium upgrade. Congratulating user.");
                    alert(getString(R.string.thank_you_updgraing_premium));
                    mIsPremium = true;
                    updateUi();
                    setWaitScreen(false);
                } else if (purchase.getSku().equals(SKU_INFINITE_GAS)) {
                    // bought the infinite gas subscription
                    Log.d(TAG, "Infinite gas subscription purchased.");
                    alert("Thank you for subscribing to infinite gas!");
                    mSubscribedToInfiniteGas = true;
                    mTank = TANK_MAX;
                    updateUi();
                    setWaitScreen(false);
                }
            }
        };

        // 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);

                // if we were disposed of in the meantime, quit.
                if (mHelper == null)
                    return;

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

    
    //In app billing method end here

我的产品是 Managed products 在开发者帐户 In-app Products

编辑:

当我将 android.test.purchased 用作 SKU 时,它可以正常工作,并且当我用 更改 sku 时product_id 然后它给我 Error Authentication is required。您需要登录您的 Google 帐户。

最佳答案

请确保您在 Playstore 中用于应用内购买的产品 ID 是“test_product”,您应该在代码中使用相同的 sku。如果您从应用程序中更改 sku,则所有可能的 sku 名称必须作为应用内产品存在于 PlayStore 中。我曾经遇到过这个问题,原因是我的 SKU 项目在 Google Playstore 应用内产品中不存在,我只是将它添加到 Playstore 并解决了。

关于Android 应用内购买 V3 错误 : Authentication is required,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29814460/

有关Android 应用内购买 V3 错误 : Authentication is required的更多相关文章

  1. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  2. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  3. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  4. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  5. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

  6. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  7. ruby-on-rails - 迷你测试错误 : "NameError: uninitialized constant" - 2

    我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test

  8. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

  9. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  10. ruby-on-rails - 错误 : Error installing pg: ERROR: Failed to build gem native extension - 2

    我克隆了一个rails仓库,我现在正尝试捆绑安装背景:OSXElCapitanruby2.2.3p173(2015-08-18修订版51636)[x86_64-darwin15]rails-v在您的Gemfile中列出的或native可用的任何gem源中找不到gem'pg(>=0)ruby​​'。运行bundleinstall以安装缺少的gem。bundleinstallFetchinggemmetadatafromhttps://rubygems.org/............Fetchingversionmetadatafromhttps://rubygems.org/...Fe

随机推荐