Intereting Posts
КоординаторLayout с CollapsingToolbarLayout прерывается с помощью клавиатуры в диалоговом фрагменте Объект не может быть передан в Void в AsyncTask Установите интерполятор для анимации андроида в Java Android: Как установить слушателя в MenuButton? Элементы управления аудио Bluetooth в Android Получить последние и запущенные списки приложений не обрабатывать Как найти статус VPN-соединения с помощью интерфейсных API или любого другого эффективного метода? Как отправлять / получать данные с помощью телефона bluetooth android на медицинское оборудование, имеющее Bluetooth Android YouTube api v3 – ориентация OnListItemClick не работает для listview? Можете ли вы установить «порядок вкладок» в XML-макете? MediaExtractor, MediaMetadataRetriever с файлом Raw / Asset Базовый уровень шрифта для Android, привязанный к сетке 4dp Есть ли способ, которым приложение может проверить, разрешено ли ему получать уведомления? RxJava с презентатором и сохраненным фрагментом для изменений конфигурации

Android в покупке приложения: проверка подписи не выполнена

Я попытался в течение нескольких дней решить эту проблему, используя демо-код Dungeons, который поставляется вместе с SDK. Я попробовал Google для ответа, но не могу найти его.

  • В демо Dungeons я передал свой открытый ключ из консоли dev.
  • Подписано apk и загружено на консоль без публикации.
  • Тестирование для android.test.purchased и списка продуктов, созданных на консоли с опубликованным для подписки (основная функция, которую я хочу для своего приложения).

Но все же я получаю сообщение об ошибке Signature verification failed а затем подпись не соответствует данным. Как я могу это решить?

 public static ArrayList<VerifiedPurchase> verifyPurchase(String signedData, String signature) { if (signedData == null) { Log.e(TAG, "data is null"); return null; } if (Consts.DEBUG) { Log.i(TAG, "signedData: " + signedData); } boolean verified = false; if (!TextUtils.isEmpty(signature)) { String base64EncodedPublicKey = "MIIBIjA....AQAB"; PublicKey key = Security.generatePublicKey(base64EncodedPublicKey); verified = Security.verify(key, signedData, signature); if (!verified) { Log.w(TAG, "signature does not match data."); return null; } } } public static boolean verify(PublicKey publicKey, String signedData, String signature) { if (Consts.DEBUG) { Log.i(TAG, "signature: " + signature); } Signature sig; try { sig = Signature.getInstance(SIGNATURE_ALGORITHM); sig.initVerify(publicKey); sig.update(signedData.getBytes()); if (!sig.verify(Base64.decode(signature))) { Log.e(TAG, "Signature verification failed."); return false; } return true; } catch (NoSuchAlgorithmException e) { Log.e(TAG, "NoSuchAlgorithmException."); } catch (InvalidKeyException e) { Log.e(TAG, "Invalid key specification."); } catch (SignatureException e) { Log.e(TAG, "Signature exception."); } catch (Base64DecoderException e) { Log.e(TAG, "Base64 decoding failed."); } return false; } 

Solutions Collecting From Web of "Android в покупке приложения: проверка подписи не выполнена"

Эта проблема все еще продолжается в текущей платежной версии Google. В основном нарушена работа android.test.purchased ; После покупки android.test.purchased функция verifyPurchase в Security.java всегда будет терпеть неудачу, и QueryInventoryFinishedListener остановится в строке if (result.isFailure ()) ; Это потому, что элемент android.test.purchased всегда терпит ошибку TextUtils.isEmpty (подпись) в Security.java, поскольку он не является реальным элементом и не имеет сигнатуры, возвращенной сервером.

Мой совет (из-за отсутствия какого-либо другого решения) заключается в том, чтобы НИКОГДА не использовать «android.test.purchased». В сети есть различные настройки кода, но ни один из них не работает на 100%.

Если вы использовали android.test.purchased, то один из способов избавиться от ошибки состоит в следующем: –

  1. Измените Security.java и измените строку «return false» в verifyPurchase на «return true» – это временно, мы вернем ее через минуту.
  2. В вашем QueryInventoryFinishedListener после строки «if (result.isFailure ()) {…}» добавьте следующее, чтобы потреблять и избавляться от вашего бесконечного продукта android.test.purchased:

     if (inventory.hasPurchase(SKU_ANDROID_TEST_PURCHASE_GOOD)) { mHelper.consumeAsync(inventory.getPurchase(SKU_ANDROID_TEST_PURCHASE_GOOD),null); } 
  3. Запустите приложение, так что consunmeAsync произойдет, это избавится от пункта «android.test.purchased» на сервере.

  4. Удалите код consumeAsync (или прокомментируйте его).
  5. Вернитесь в Security.java, измените «return true» на «return false».

Ваш QueryInventoryFinishedListener больше не будет проверять ошибку, все возвращается к «нормальному» (если вы можете это назвать). Помните – не беспокойтесь, используя android.test.purchased снова, так как это просто вызовет эту ошибку снова … это сломано! Единственный реальный способ проверить его покупку, чтобы загрузить APK, дождаться его появления, а затем протестировать его (тот же APK) на вашем устройстве с включенным протоколированием.

Да, проблема все еще возникает. После того, как я купил android.test.purchased, я начал получать ошибку при запросе инвентаря. Вы можете исправить свой телефон, просто очистив данные приложения Google Play Store и запустив Google Play один раз. Когда вы очищаете данные в Google Play, он забывает, что вы купили android.test.purchased

Проверьте, что base64EncodedPublicKey и один из Play Developer Console равны. После повторной загрузки APK в консоли разработчика открытый ключ может измениться, если обновить base64EncodedPublicKey .

Основываясь на ответе GMTDev, это то, что я делаю, чтобы исправить проблемы тестирования, когда вы потребляете продукты самым простым способом . В Security.java замените метод verifyPurchase () следующим образом:

 public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature) { if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey) || TextUtils.isEmpty(signature)) { Log.e(TAG, "Purchase verification failed: missing data."); return BuildConfig.DEBUG; // Line modified by Cristian. Original line was: return false; } PublicKey key = Security.generatePublicKey(base64PublicKey); return Security.verify(key, signedData, signature); } 

Я только изменил одну строку (см. Комментарий), и таким образом вы можете сохранить такой код для отладки и по-прежнему публиковать свои версии выпуска безопасно.

Вы можете пропустить процесс проверки этих идентификаторов продуктов «android.test. *». Если вы используете пример кода из примера TrivialDrive, откройте IabHelper.java, найдите следующий код строки, измените его из

  if (Security.verifyPurchase(mSignatureBase64, purchaseData, dataSignature)) { ... } 

в

  boolean verifySignature = !sku.startsWith("android.test."); // or inplace the condition in the following line if (verifySignature && !Security.verifyPurchase(mSignatureBase64, purchaseData, dataSignature)) { ... } 

Это безвредно, даже если вы забыли отменить код. Таким образом, вы можете продолжить тестирование следующего шага рабочего процесса.

Это решение работало для меня. Я изменил новый метод verifyPurchase в классе покупки со старым.

То, что сработало для меня, при использовании In-app Billing v3 и включенных классов утилиты, потребляло тестовую покупку в возвращенном вызове onActivityResult.

Никакие изменения в IabHelper, Security или любые классы использования In-app Billing необходимы, чтобы избежать этого для будущих пробных покупок.

Если вы уже попробовали приобрести тестовый продукт и теперь застряли на ошибке проверки подлинности подписи на покупку, которая, скорее всего, с тех пор, как вы ищете ответы на эту ошибку, вам необходимо:

  1. Внесите изменения, рекомендованные GMTDev
  2. Запустите приложение, чтобы убедиться, что он потребляет продукт
  3. Удалить / отменить изменения в GMTDev
  4. Выполните код ниже внутри onActivityResult.

Это не только позволяет процессу тестирования покупки быть текучим, но также следует избегать любых противоречащих друг другу проблем, когда iab возвращает ошибку « Item Ownered Own » при попытке выкупа тестового продукта.

Если это вызвано изнутри фрагмента, а onActivityResult вашего фрагмента не вызывается, тогда обязательно вызовите YourFragmentName.onActivityResult (requestCode, resultCode, data) из родительского ActivityFragment, если это необходимо. Это объясняется более подробно в Calling startIntentSenderForResult из Fragment (Android Billing v3) .

 @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_PURCHASE) { //this ensures that the mHelper.flagEndAsync() gets called //prior to starting a new async request. mHelper.handleActivityResult(requestCode, resultCode, data); //get needed data from Intent extra to recreate product object int responseCode = data.getIntExtra("RESPONSE_CODE", 0); String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA"); String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE"); // Strip out getActivity() if not being used within a fragment if (resultCode == getActivity().RESULT_OK) { try { JSONObject jo = new JSONObject(purchaseData); String sku = jo.getString("productId"); //only auto consume the android.test.purchased product if (sku.equals("android.test.purchased")) { //build the purchase object from the response data Purchase purchase = new Purchase("inapp", purchaseData, dataSignature); //consume android.test.purchased mHelper.consumeAsync(purchase,null); } } catch (JSONException je) { //failed to parse the purchase data je.printStackTrace(); } catch (IllegalStateException ise) { //most likely either disposed, not setup, or //another billing async process is already running ise.printStackTrace(); } catch (Exception e) { //unexpected error e.printStackTrace(); } } } } 

Он удалит только покупку, если это sku – «android.test.purchased», поэтому он должен быть безопасным в использовании.

Проверка подписи завершается только для тестового продукта по умолчанию. Быстрое исправление:

  • Перейти к классу IabHelper.
  • Инвертируйте условия if Security.verifyPurchase .

Это оно!

Не забывайте возвращать изменения при замене тестового продукта на фактический продукт

Проверьте этот ответ :

Является ли основная учетная запись вашего тестового устройства такой же, как ваша учетная запись разработчика Google Play?

Если нет, вы не будете получать подписи на андроид.test. * Статические ответы, если приложение не было опубликовано в Play раньше.

Полный список условий см. В таблице на странице http://developer.android.com/guide/market/billing/billing_testing.html#static-responses-table .

И это комментарий:

Я не думаю, что статические идентификаторы возвращают подпись. См. https://groups.google.com/d/topic/android-developers/PCbCJdOl480/discussion.

Кроме того, ранее образец кода (используемый многими большими приложениями) из Библиотеки биллинга Google Play допускал пустую подпись. Вот почему там работают статические покупки.
Но это была дыра в безопасности, поэтому, когда она была опубликована , Google отправил обновление .

У меня такая же проблема, и я следую @Deadolus на основе https://www.gaffga.de/implementing-in-app-billing-for-android/

Ключевым моментом является то, что нам нужно сделать SKU расходным, даже если результат запроса инвентаризации не удался. Ниже приведен пример того, как я это сделал.

 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()) { try { Purchase purchase = new Purchase("inapp", "{\"packageName\":\"PACKAGE_NAME\","+ "\"orderId\":\"transactionId.android.test.purchased\","+ "\"productId\":\"android.test.purchased\",\"developerPayload\":\"\",\"purchaseTime\":0,"+ "\"purchaseState\":0,\"purchaseToken\":\"inapp:PACKAGE_NAME :android.test.purchased\"}", ""); } catch (JSONException e) { e.printStackTrace(); } mHelper.consumeAsync(purchase, null); complain("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(). */ } }; 

Замените PACKAGE_NAME в коде выше с именем пакета вашего приложения.