Android In-App Purchase V3 Ошибка: требуется аутентификация

Я внедряю Google In-app Purchase V3 и выполняю все шаги, указанные здесь, а также в официальной документации. Я загрузил свое приложение в Google Playstore для Alpha Testing и я загрузил его с URL-адреса playstore на свое реальное устройство, но это дало мне ошибку


Требуется аутентификация. Вам нужно войти в свою учетную запись Google.

Введите описание изображения здесь

Мой код для покупки In-app находится здесь:

 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 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.drawable.premium :; // "Upgrade" button is only visible if the user is not premium // findViewById( ? // View.GONE : View.VISIBLE); // "Get infinite gas" button is only visible if the user is not // subscribed yet // ( ? // View.GONE : View.VISIBLE); // update gas gauge to reflect tank status if (mSubscribedToInfiniteGas) { // ((ImageView)findViewById(; } else { int index = mTank >= TANK_RES_IDS.length ? TANK_RES_IDS.length - 1 : mTank; // ((ImageView)findViewById([index]); } } // Enables or disables the "please wait" screen. void setWaitScreen(boolean set) { // findViewById( ? View.GONE : // View.VISIBLE); // findViewById( ? 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. You need to sign into your Google Account. Error Authentication is required. You need to sign into your Google Account.

Solutions Collecting From Web of "Android In-App Purchase V3 Ошибка: требуется аутентификация"

Убедитесь, что ваш идентификатор продукта в PlayStore для покупки приложения, который является «test_product», вы должны использовать тот же sku в своем коде. И если вы измените sku из своего приложения, тогда все возможные имена sku должны существовать в PlayStore как в приложениях. Однажды я столкнулся с этой проблемой, и причина в том, что мой элемент SKU не существовал в продуктах Google Playstore для приложений, и я просто добавляю их в PlayStore, и это было разрешено.

Ошибка IAB для Android – требуется проверка подлинности

Кажется, вам нужно публиковать APK. Я тоже столкнулся с этой проблемой.

Это немного длинный, но ваше приложение «Google Play Store» может работать неправильно.

У меня есть отчет от клиента, что он не может сделать покупку In-App, и он получает эту же ошибку. Я также знаю, что мы все еще получаем покупки. Поэтому я не думаю, что вы обязательно настроили что-то неправильно. IAB v3 может быть просто неисправен с вашим приложением «Google Play Store».

Попробуйте «Настройки» откройте Диспетчер приложений и выберите приложение «Магазин Google Play» в списке и нажмите кнопку «Удалить обновления», которая появляется там. Затем попробуйте сделать покупку снова. Если ваше старое приложение Google Play поддерживает In-App billing v3, оно будет работать. Если этого не произойдет, попробуйте снова обновить приложение «Google Play Store», возможно, вы получите новую / новую версию приложения магазина, и вы сможете совершить покупку.

В качестве альтернативы вы можете попробовать и настроить второе тестовое устройство с другой учетной записью Google … или попросить друга присоединиться к группе бета-тестирования и совершить пробную покупку.

Я не очень доволен IAB v3. Он чувствует себя немного неуклюжим. У V2 было меньше функций, но они были твердыми.