Ich habe mehrere Tage lang versucht, dieses Problem mithilfe des mit dem SDK gelieferten Dungeons-Demo-Codes zu lösen. Ich habe versucht, eine Antwort bei Google zu finden, kann aber keine finden.
- In der Dungeons-Demo habe ich meinen öffentlichen Schlüssel von der Entwicklerkonsole übergeben.
- Signierte die apk und lud sie ohne Veröffentlichung auf die Konsole hoch.
- Testen auf beide
android.test.purchased
und auf der Konsole erstellte Produktliste mit Abonnement veröffentlicht (die Hauptfunktion, die ich für meine App möchte).
Trotzdem bekomme ich einen Fehler von Signature verification failed
und dann stimmt die Signatur nicht mit den Daten überein. Wie kann ich das lösen?
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;
}
quelle
Ja, das Problem tritt weiterhin auf. Nachdem ich android.test.purchased gekauft habe, erhalte ich den Fehler beim Abfragen des Inventars. Sie können Ihr Telefon reparieren, indem Sie einfach die Daten der Google Play Store-Anwendung löschen und Google Play einmal ausführen. Wenn Sie Daten von Google Play löschen, wird vergessen, dass Sie android.test.purchased gekauft haben
quelle
Bitte überprüfen Sie, ob
base64EncodedPublicKey
und die von der Play Developer Console gleich sind. Sobald Sie die APK in der Entwicklerkonsole erneut hochladen , kann sich der öffentliche Schlüssel ändern. Aktualisieren Sie in diesem Fall Ihrenbase64EncodedPublicKey
.quelle
Sie können den Überprüfungsprozess für diese Produkt-IDs "android.test. *" Überspringen. Wenn Sie den Beispielcode aus dem TrivialDrive-Beispiel verwenden, öffnen Sie IabHelper.java, suchen Sie den folgenden Zeilencode und ändern Sie ihn von
if (Security.verifyPurchase(mSignatureBase64, purchaseData, dataSignature)) { ... }
in
boolean verifySignature = !sku.startsWith("android.test."); // or inplace the condition in the following line if (verifySignature && !Security.verifyPurchase(mSignatureBase64, purchaseData, dataSignature)) { ... }
Es ist harmlos, auch wenn Sie vergessen haben, den Code zurückzusetzen. So können Sie den weiteren Workflow-Schritt weiter testen.
quelle
Basierend auf der Antwort von GMTDev ist dies das, was ich tue, um die Testprobleme beim Konsum von Produkten auf einfachste Weise zu beheben . Ersetzen Sie in Security.java die verifyPurchase () -Methode durch folgende:
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); }
Ich habe nur eine Zeile geändert (siehe Kommentar). Auf diese Weise können Sie den Code für das Debuggen beibehalten und Ihre Release-Versionen dennoch sicher veröffentlichen.
quelle
Der Fehler wird durch den falschen Lizenzschlüssel verursacht. Möglicherweise stammt der Lizenzschlüssel von Ihrer anderen App.
Die Lösung besteht darin, den richtigen Lizenzschlüssel zu verwenden von:
quelle
Bei der Verwendung von In-App Billing v3 und den enthaltenen Dienstprogrammklassen hat sich für mich der Testkauf innerhalb des zurückgegebenen onActivityResult-Aufrufs bewährt.
Es sind keine Änderungen an IabHelper, Security oder einer der In-App Billing Util-Klassen erforderlich, um dies für zukünftige Testkäufe zu vermeiden.
Wenn Sie bereits versucht haben, das Testprodukt zu kaufen, und nun den Fehler "Überprüfung der Kaufsignaturprüfung fehlgeschlagen" haben, den Sie wahrscheinlich haben, da Sie nach Antworten auf diesen Fehler suchen, sollten Sie:
Dies ermöglicht nicht nur einen reibungslosen Kaufprozess, sondern sollte auch Konflikte vermeiden, wenn iab beim Versuch, das Testprodukt zurückzukaufen, den Fehler " Item Already Owned " zurückgibt.
Wenn dies aus einem Fragment heraus aufgerufen wird und das onActivityResult Ihres Fragments nicht aufgerufen wird, rufen Sie bei Bedarf YourFragmentName.onActivityResult (requestCode, resultCode, data) von Ihrem übergeordneten ActivityFragment auf. Dies wird ausführlicher unter Aufrufen von startIntentSenderForResult aus Fragment (Android Billing v3) erläutert. .
@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(); } } } }
Der Kauf wird nur entfernt, wenn die SKU "android.test.purchased" lautet, sodass die Verwendung sicher sein sollte.
quelle
onActivityResult()
Rückruf weggelassen haben .Diese Lösung hat bei mir funktioniert. Ich habe die neue verifyPurchase-Methode in der Kaufklasse durch die alte geändert.
quelle
Die Signaturüberprüfung schlägt nur für das Standardtestprodukt fehl. Eine schnelle Lösung:
Security.verifyPurchase
.Das ist es!
Denken Sie daran, die Änderungen rückgängig zu machen, wenn das Testprodukt durch das tatsächliche Produkt ersetzt wird
quelle
Heute (30. Oktober 2018) ist das gleiche Problem aufgetreten (Überprüfung der Signatur und Abschaffung des Testkaufs).
Das Signaturproblem wird wahrscheinlich durch die Tatsache verursacht, dass diese Test-Skus nicht wirklich Teil Ihrer App sind und daher nicht über die Signatur Ihrer App verfügen. Ich habe ein Ticket bei Google geöffnet, bin mir aber nicht sicher, ob sie das beheben können. Die Problemumgehung besteht, wie andere betonten, darin, den Code zu ersetzen
if (verifyValidSignature(purchase.getOriginalJson(), purchase.getSignature())) {
mit
if (verifyValidSignature(purchase.getOriginalJson(), purchase.getSignature()) || (purchase.getSku().startsWith("android.test.")) ) {
In Bezug auf "Wie man den Kauf von android.test.purchased SKU loswird" stellte ich fest, dass ein einfacher Neustart des Geräts, gefolgt von etwa einer Minute Wartezeit und / oder ein paar Neustarts der App, das Problem behoben hat für mich (dh ich musste den Kauf nicht per Code "konsumieren"). Ich vermute, dass das Warten erforderlich ist, damit der Play Store die Synchronisierung mit den Servern von Google abschließt. (Ich bin mir nicht sicher, ob dies auch in Zukunft so funktionieren wird. Wenn es jetzt für Sie funktioniert, kann dies Ihnen helfen, weiterzukommen.)
quelle
Überprüfen Sie diese Antwort :
Und es ist ein Kommentar:
Zuvor erlaubte der Beispielcode (der von vielen großen Apps verwendet wird) aus der Google Play Billing Library eine leere Signatur. Deshalb haben dort statische Einkäufe funktioniert.
Da es sich jedoch um eine Sicherheitslücke handelte , hat Google bei der Veröffentlichung ein Update eingereicht .
quelle
Ich habe das gleiche Problem und folge @Deadolus basierend auf https://www.gaffga.de/implementing-in-app-billing-for-android/
Der entscheidende Punkt ist, dass die SKU konsumierbar ist, auch wenn das Ergebnis der Bestandsabfrage fehlschlägt. Unten ist das Beispiel, wie ich das gemacht habe.
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(). */ } };
Ersetzen Sie PACKAGE_NAME im obigen Code durch den Paketnamen Ihrer App.
quelle
Das hat bei mir funktioniert:
Der Schritt 3 sollte nicht notwendig sein, denn als ich onSkuDetailsResponse erhielt, sollte es in Ordnung sein, aber es ist nicht so, ich musste ein wenig warten. Nachdem dieser Kauf funktioniert, wird kein Fehler "Artikel nicht verfügbar" angezeigt. So habe ich es getestet:
quelle
Für Cordova- und Hybrid-Apps müssen Sie die Methode this.iap.subscribe (this.productId) verwenden, um InAppPurchase zu abonnieren.
Folgendes ist der Code, der für mich gut funktioniert:
getProdutIAP() { this.navCtrl.push('subscribeDialogPage'); this.iap .getProducts(['productID1']).then((products: any) => { this.buy(products); }) .catch((err) => { console.log(JSON.stringify(err)); alert('Finished Purchase' + JSON.stringify(err)); console.log(err); }); } buy(products: any) { // this.getProdutIAP(); // alert(products[0].productId); this.iap.subscribe(products[0].productId).then((buydata: any) => { alert('buy Purchase' + JSON.stringify(buydata)); // this.sub(); }).catch((err) => { // this.navCtrl.push('subscribeDialogPage'); alert('buyError' + JSON.stringify(err)); }); } sub() { this.platform.ready().then(() => { this.iap .subscribe(this.productId) .then((data) => { console.log('subscribe Purchase' + JSON.stringify(data)); alert('subscribe Purchase' + JSON.stringify(data)); this.getReceipt(); }).catch((err) => { this.getReceipt(); alert('subscribeError' + JSON.stringify(err)); console.log(err); }); }) }
quelle