Android studio Android Studio应用内计费如何验证设备上的购买?
我在安卓工作室工作了很短时间,这是我的第一个项目。我不知道很多要点,我为我复杂的代码道歉。我的应用程序中只有1个消费品,给用户20条生命。经过长期努力,我成功地将应用程序内购买添加到我的应用程序中。在我的应用程序中,我可以用自己的产品ID使用谷歌测试卡进行购买。到目前为止,我没有遇到任何问题。由于我没有服务器,我必须在设备上进行购买验证。我在一个活动中编写了所有购买和验证代码。我想这听起来可能有点傻,但我不知道在哪里确认购买。即使签名不正确,我的应用程序也会接受验证。我在代码中遗漏了什么Android studio Android Studio应用内计费如何验证设备上的购买?,android-studio,in-app-purchase,signature,verification,Android Studio,In App Purchase,Signature,Verification,我在安卓工作室工作了很短时间,这是我的第一个项目。我不知道很多要点,我为我复杂的代码道歉。我的应用程序中只有1个消费品,给用户20条生命。经过长期努力,我成功地将应用程序内购买添加到我的应用程序中。在我的应用程序中,我可以用自己的产品ID使用谷歌测试卡进行购买。到目前为止,我没有遇到任何问题。由于我没有服务器,我必须在设备上进行购买验证。我在一个活动中编写了所有购买和验证代码。我想这听起来可能有点傻,但我不知道在哪里确认购买。即使签名不正确,我的应用程序也会接受验证。我在代码中遗漏了什么 pub
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();
}
}
公共类MagazaActivity扩展了AppCompatActivity{
按钮baslik,购买按钮;
坎克;
int can;
私人计费客户mBillingClient;
private final List mpources=new ArrayList();
私有静态最终字符串BASE_64_ENCODED_PUBLIC_KEY=“XXXXX”;
私有静态最终字符串TAG=“IABUtil/Security”;
私有静态最终字符串密钥\u工厂\u算法=“RSA”;
私有静态最终字符串签名\u算法=“SHA1withRSA”;
弦坎菲亚特;
mBillingClient=BillingClient.newBuilder(magazactivity.this)。
setListener(新的PurchasesUpdatedListener(){
@凌驾
购买时公共无效(内部响应代码,
@可为空的列表(购买){
if(responseCode==BillingClient.BillingResponse.OK
&&购买!=空){
用于(最终采购:采购){
ConsumerResponseListener侦听器=新建
消费主义者(){
@凌驾
公共空间
onConsumerResponse(@BillingClient.BillingResponse int-responseCode,字符串
outToken){
如果(响应代码==
BillingClient.BillingResponse.OK){
手工采购(采购);
}
}
};
mBillingClient.ConsumeAncy(purchase.getPurchaseToken(),侦听器);
}
}else if(responseCode==
BillingClient.BillingResponse.USER\u已取消){
BillingCancelled();
}
否则{
AlertDialog.builder2=新建
AlertDialog.Builder(MagazaActivity.this,R.style.AlertDialogCustom);
builder2.setMessage(“计费系统”sİnvalid);
builder2.setCancelable(true);
平整机厂=
Layoutiner.from(MagazaActivity.this);
最终视图=工厂充气(R.layout.sample4,
无效);
builder2.setView(视图);
builder2.setPositiveButton(
“好的”,
新建DialogInterface.OnClickListener(){
公共void onClick(对话框接口对话框,
int id){
dialog.cancel();
}
});
AlertDialog alert11=builder2.create();
alert11.show();
}
}
}).
build();
buy_button.setOnClickListener(新视图.OnClickListener(){
@凌驾
公共void onClick(视图v){
mBillingClient.startConnection(新的BillingClientStateListener()
{
@凌驾
公共空间
onBillingSetupFinished(@BillingClient.BillingResponse int
billingResponseCode){
如果(billingResponseCode==
BillingClient.BillingResponse.OK){
最终列表skuList=新的ArrayList();
skuList。添加(“XXX”);
SkuDetailsParams SkuDetailsParams=
sku.sparams.newBuilder()
.setSkusList(skuList).setType(BillingClient.SkuType.INAPP).build();
mBillingClient.queryskuedetailsasync(skuedetailsparams,
新SkuDetailsResponseListener(){
@凌驾
公共无效详细信息响应(int)
响应代码,
列表(详细信息列表){
BillingFlowParams flowParams=
BillingFlowParams.newBuilder()
.setsku详细信息(skuDetailsList.get(0))
.build();
int billingResponseCode=
mBillingClient.launchBillingFlow(MagazaActivity.this,flowParams);
如果(billingResponseCode==
BillingClient.BillingResponse.OK){
对于(SKU详细信息)SKU详细信息:
SKU(详细信息列表){
字符串sku=
skuDetails.getSku();
字符串价格=
skuedetails.getPrice();
如果(“XXX”。等于(sku)){
canfiyat=价格;
}
}
}
}
});
}
}
@凌驾
公共无效onBillingServiceDisconnected(){
AlertDialog.Builder=新建
AlertDialog.Builder(MagazaActivity.this);
builder.setMessage(“连接错误”)
.setCancelable(错误)
.setPositiveButton(“重试”,新建
DialogInterface.OnClickListener(){
公共空隙(直径