Я недолго работал с Android Studio, и это мой первый проект.Я не знаю много пунктов, и я прошу прощения за мой сложный код.В моем приложении всего 1 расходный продукт, который дает пользователю 20 жизней.В результате долгих усилий мне удалось добавить в приложение покупку в приложении.В моем приложении я мог совершать покупки с помощью тестовых карт Google с собственным идентификатором продукта.У меня не было никаких проблем до здесь.Поскольку у меня нет сервера, я должен выполнить проверку покупки на устройстве.Я написал все коды покупки и проверки в действии.Я думаю, это может звучать немного глупо, но я не знаю, где сделать подтверждение покупки.Моя заявка принимает подтверждение, даже если это неверная подпись.Какой смысл я пропустил в своих кодах?
public class MagazaActivity extends AppCompatActivity {
Button baslik, buy_button;
Can hak;
int can;
private BillingClient mBillingClient;
private final List<Purchase> mPurchases = new ArrayList<>();
private static final String BASE_64_ENCODED_PUBLIC_KEY = "XXXXX";
private static final String TAG = "IABUtil/Security";
private static final String KEY_FACTORY_ALGORITHM = "RSA";
private static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
String canfiyat;
mBillingClient =BillingClient.newBuilder(MagazaActivity.this).
setListener(new PurchasesUpdatedListener() {
@Override
public void onPurchasesUpdated ( int responseCode,
@Nullable List<Purchase> purchases){
if (responseCode == BillingClient.BillingResponse.OK
&& purchases != null) {
for (final Purchase purchase : purchases) {
ConsumeResponseListener listener = new
ConsumeResponseListener() {
@Override
public void
onConsumeResponse(@BillingClient.BillingResponse int responseCode, String
outToken) {
if (responseCode ==
BillingClient.BillingResponse.OK) {
handlePurchase(purchase);
}
}
};
mBillingClient.consumeAsync(purchase.getPurchaseToken(), listener);
}
} else if (responseCode ==
BillingClient.BillingResponse.USER_CANCELED) {
billingCanceled();
}
else {
AlertDialog.Builder builder2 = new
AlertDialog.Builder(MagazaActivity.this, R.style.AlertDialogCustom);
builder2.setMessage("Billing System İs İnvalid");
builder2.setCancelable(true);
LayoutInflater factory =
LayoutInflater.from(MagazaActivity.this);
final View view = factory.inflate(R.layout.sample4,
null);
builder2.setView(view);
builder2.setPositiveButton(
"OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int id) {
dialog.cancel();
}
});
AlertDialog alert11 = builder2.create();
alert11.show();
}
}
}).
build();
buy_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mBillingClient.startConnection(new BillingClientStateListener()
{
@Override
public void
onBillingSetupFinished(@BillingClient.BillingResponse int
billingResponseCode) {
if (billingResponseCode ==
BillingClient.BillingResponse.OK) {
final List<String> skuList = new ArrayList<>();
skuList.add("XXX");
SkuDetailsParams skuDetailsParams =
SkuDetailsParams.newBuilder()
.setSkusList(skuList).setType(BillingClient.SkuType.INAPP).build();
mBillingClient.querySkuDetailsAsync(skuDetailsParams,
new SkuDetailsResponseListener() {
@Override
public void onSkuDetailsResponse(int
responseCode,
List<SkuDetails> skuDetailsList) {
BillingFlowParams flowParams =
BillingFlowParams.newBuilder()
.setSkuDetails(skuDetailsList.get(0))
.build();
int billingResponseCode =
mBillingClient.launchBillingFlow(MagazaActivity.this, flowParams);
if (billingResponseCode ==
BillingClient.BillingResponse.OK) {
for (SkuDetails skuDetails :
skuDetailsList) {
String sku =
skuDetails.getSku();
String price =
skuDetails.getPrice();
if ("XXX".equals(sku)) {
canfiyat = price;
}
}
}
}
});
}
}
@Override
public void onBillingServiceDisconnected() {
AlertDialog.Builder builder = new
AlertDialog.Builder(MagazaActivity.this);
builder.setMessage("Connection Error")
.setCancelable(false)
.setPositiveButton("Retry", new
DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
}
});
}
});
}
@Override
public void onBackPressed() {
Intent intentLayout8 = new Intent(MagazaActivity.this,
MainActivity.class);
startActivity(intentLayout8);
MagazaActivity.this.finish();
}
private void billingCanceled() {
AlertDialog.Builder builder = new
AlertDialog.Builder(MagazaActivity.this);
builder.setMessage("Purchase Canceled")
.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
}
public static PublicKey generatePublicKey(String encodedPublicKey) {
try {
byte[] decodedKey = Base64.decode(encodedPublicKey,
Base64.DEFAULT);
KeyFactory keyFactory =
KeyFactory.getInstance(KEY_FACTORY_ALGORITHM);
return keyFactory.generatePublic(new
X509EncodedKeySpec(decodedKey));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (InvalidKeySpecException e) {
Log.e(TAG, "Invalid key specification.");
throw new IllegalArgumentException(e);
}
}
public static boolean verifyPurchase(String base64PublicKey, String
signedData, String signature) {
if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey)
||
TextUtils.isEmpty(signature)) {
Log.e("HATA", "Purchase verification failed");
return false;
}
PublicKey key = MagazaActivity.generatePublicKey(base64PublicKey);
return MagazaActivity.verify(key, signedData, signature);
}
public static boolean verify(PublicKey publicKey, String signedData, String
signature) {
byte[] signatureBytes;
try {
signatureBytes = Base64.decode(signature, Base64.DEFAULT);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Base64 decoding failed.");
return false;
}
try {
Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
sig.initVerify(publicKey);
sig.update(signedData.getBytes());
if (!sig.verify(signatureBytes)) {
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.");
}
return false;
}
private boolean verifyValidSignature(String signedData, String signature) {
try {
return MagazaActivity.verifyPurchase(BASE_64_ENCODED_PUBLIC_KEY,
signedData, signature);
} catch (Exception e) {
Log.e(TAG, "Got an exception trying to validate a purchase: " + e);
return false;
}
}
public void handlePurchase(Purchase purchase) {
if (!verifyValidSignature(purchase.getOriginalJson(),
purchase.getSignature())) {
Log.i("Warning", "Purchase: " + purchase + "; signature
failure...");
return;
}
Log.d("MESAJ", "Got a verified purchase: " + purchase);
hak.cancan = hak.cancan + 20;
SharedPreferences pref =
getApplicationContext().getSharedPreferences("MyPref", MODE_PRIVATE);
SharedPreferences.Editor editor = pref.edit();
editor.putInt("kalp", hak.cancan);
editor.apply();
mPurchases.add(purchase);
}
public void onResume() {
super.onResume();
}
}