App Billing v3 购买
App Billing v3 purchase
在我的测试应用程序中,用户单击购买按钮并购买了商品。购买完成后,文本视图会显示 "Purchase completed"。都好。 :).但是,当我终止该应用程序并再次打开它时,购买按钮再次出现......:/。为什么会这样? Google 这个不是很清楚。这是代码。
public class MainActivity extends Activity {
IInAppBillingService mService;
ServiceConnection connection;
String inappid = "victory.walkto.testingpaymentsd.productid"; //replace this with your in-app product id
Button purchaseBtn;
Button clickBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
serviceIntent.setPackage("com.android.vending");
// first this
connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IInAppBillingService.Stub.asInterface(service);
}
};
// then this
bindService(serviceIntent,connection, Context.BIND_AUTO_CREATE);
purchaseBtn = (Button) findViewById(R.id.purchase);
clickBtn = (Button) findViewById(R.id.clickButton);
clickBtn.setVisibility(View.GONE);
purchaseBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ArrayList skuList = new ArrayList();
skuList.add(inappid);
Bundle querySkus = new Bundle();
querySkus.putStringArrayList("ITEM_ID_LIST", skuList);
Bundle skuDetails;
try {
Bundle ownedItems = mService.getPurchases(3,
getPackageName(), "inapp", null);
// Check response
int responseCode =
ownedItems.getInt("RESPONSE_CODE");
if (responseCode != 0) {
throw new Exception("Error");
}
// Get the list of purchased items
ArrayList<String> purchaseDataList =
ownedItems.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
for (String purchaseData : purchaseDataList) {
JSONObject o = new JSONObject(purchaseData);
String purchaseToken = o.optString("token", o.optString("purchaseToken"));
// Consume purchaseToken, handling any errors
mService.consumePurchase(3, getPackageName(), purchaseToken);
}
skuDetails = mService.getSkuDetails(3, getPackageName(),
"inapp", querySkus);
int response = skuDetails.getInt("RESPONSE_CODE");
if (response == 0) {
ArrayList<String> responseList = skuDetails
.getStringArrayList("DETAILS_LIST");
for (String thisResponse : responseList) {
JSONObject object = new JSONObject(thisResponse);
String sku = object.getString("productId");
String price = object.getString("price");
if (sku.equals(inappid)) {
System.out.println("price " + price);
Bundle buyIntentBundle = mService
.getBuyIntent(3, getPackageName(), sku,
"inapp",
"bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
PendingIntent pendingIntent = buyIntentBundle
.getParcelable("BUY_INTENT");
startIntentSenderForResult(
pendingIntent.getIntentSender(), 1001,
new Intent(), Integer.valueOf(0),
Integer.valueOf(0), Integer.valueOf(0));
purchaseBtn.setVisibility(View.GONE);
clickBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(),"I am clicked",Toast.LENGTH_SHORT).show();
}
});
}
}
}
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IntentSender.SendIntentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1001) {
String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
if (resultCode == RESULT_OK) {
clickBtn.setVisibility(View.VISIBLE);
try {
JSONObject jo = new JSONObject(purchaseData);
String sku = jo.getString(inappid);
Toast.makeText(
MainActivity.this,
"You have bought the " + sku
+ ". Excellent choice,adventurer!",
Toast.LENGTH_LONG).show();
} catch (JSONException e) {
System.out.println("Failed to parse purchase data.");
e.printStackTrace();
}
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (connection != null) {
unbindService(connection);
}
}
}
固定
IabHelper 中没有错误 Class。我必须将从 JSON 响应中获取的 orderId 值存储为 SharedPreference key/value 对。
类似这样。
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
SharedPreferences.Editor editor = settings.edit();
editor.putString("productId", sku);
editor.putString("purchaseToken", purchaseToken);
editor.putString("orderId", orderId);
editor.commit();
检索它们。
SharedPreferences spreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
productId = spreferences.getString("productId", "");
purchaseToken = spreferences.getString("purchaseToken", "");
orderId = spreferences.getString("orderId", "");
最后使用 if 条件使视图可见或不可见
if(orderId.isEmpty()) {
entryFee.setVisibility(View.VISIBLE);
paymentButton.setVisibility(View.VISIBLE);
paymentText.setVisibility(View.VISIBLE);
teamTextField.setVisibility(View.GONE);
btn.setVisibility(View.GONE);
paymentButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ArrayList skuList = new ArrayList();
skuList.add(inappid);
querySkus = new Bundle();
querySkus.putStringArrayList("ITEM_ID_LIST", skuList);
checkPayment();
}
});
}else{
entryFee.setVisibility(View.GONE);
paymentButton.setVisibility(View.GONE);
paymentText.setVisibility(View.GONE);
teamTextField.setVisibility(View.VISIBLE);
btn.setVisibility(View.VISIBLE);
}
解决方案并不难,但我必须通读大量文档,使用调试器点,仅此而已:)。
使您的代码不那么复杂。将嵌套的点击侦听器移到 oncreate 之外,并适当地命名这些方法。如果我是对的,你想做的是
onCreate:
## init listeners here
## then query purchase
if purchased:
hide purchase button
show click button
else:
hide click button
show purchase button
purchaseClickListener:
make purchase
if successfull:
hide purchase button
show click button
Read the documentation thoroughly before implementing
- Querying for Purchased Items:这不应该在
onCLickListener
内,而是从 onCreate
调用以检查是否已购买。
- Purchasing an Item: This is what should happen when the user clicks the purchase button and you may or may not Query for Items Available for Purchase 购买前。
- 购买成功后必须Consume the Purchase。这是里面
onActivityResult
当您终止您的应用程序时,它会再次运行 onCeeate,从头开始设置。您需要检查是否适合在 onCreate 中显示您的按钮,方法是使用付款 Api 检查(如果可能)或将您的状态本地存储在 SharedPreference 中并检查。
您想为 IAP 尝试一些第 3 方库吗?我推荐使用这个库:OpenIAB。使用此库,您不仅可以在 Google Play Store 中进行 IAP,还可以在其他商店(Amazon store、Slide me...)中进行 IAP。查看更多详细信息。
这不容易破解,但我找到了所需的解决方法。最近对 Google 感到非常失望,他们的 Android 网站变得一团糟(很难找到有用的信息)并且他们的示例代码很差。几年前我在做一些 Android 开发时,一切都变得如此简单!这是另一个例子...
确实 IabUtil 有问题,它没有正确地取消它自己的异步任务。整套必要的解决方法来稳定这个东西:
1) 制作方法 flagEndAsync public。它就在那里,只是看不见。
2) 让每个侦听器调用 iabHelper.flagEndAsync 以确保程序正确标记为完成;似乎所有听众都需要它。
3) 用 try/catch 包围调用以捕获可能发生的 IllegalStateException,并以这种方式处理它。
下面的代码可以帮到你,
try {
if (helper != null) {
helper.flagEndAsync();
}
helper.launchPurchaseFlow(.....)
}catch(IllegalStateException e){
e.printStackTrace();
}
我在这里发布答案,以供可能遇到相同问题的人使用。
您应该将来自 Google 服务器的 oprderId 和 transactionId 存储在共享首选项中。只有这样您的程序才会知道何时使购买按钮可见或不可见。
希望这会有所帮助。
在我的测试应用程序中,用户单击购买按钮并购买了商品。购买完成后,文本视图会显示 "Purchase completed"。都好。 :).但是,当我终止该应用程序并再次打开它时,购买按钮再次出现......:/。为什么会这样? Google 这个不是很清楚。这是代码。
public class MainActivity extends Activity {
IInAppBillingService mService;
ServiceConnection connection;
String inappid = "victory.walkto.testingpaymentsd.productid"; //replace this with your in-app product id
Button purchaseBtn;
Button clickBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
serviceIntent.setPackage("com.android.vending");
// first this
connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IInAppBillingService.Stub.asInterface(service);
}
};
// then this
bindService(serviceIntent,connection, Context.BIND_AUTO_CREATE);
purchaseBtn = (Button) findViewById(R.id.purchase);
clickBtn = (Button) findViewById(R.id.clickButton);
clickBtn.setVisibility(View.GONE);
purchaseBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ArrayList skuList = new ArrayList();
skuList.add(inappid);
Bundle querySkus = new Bundle();
querySkus.putStringArrayList("ITEM_ID_LIST", skuList);
Bundle skuDetails;
try {
Bundle ownedItems = mService.getPurchases(3,
getPackageName(), "inapp", null);
// Check response
int responseCode =
ownedItems.getInt("RESPONSE_CODE");
if (responseCode != 0) {
throw new Exception("Error");
}
// Get the list of purchased items
ArrayList<String> purchaseDataList =
ownedItems.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
for (String purchaseData : purchaseDataList) {
JSONObject o = new JSONObject(purchaseData);
String purchaseToken = o.optString("token", o.optString("purchaseToken"));
// Consume purchaseToken, handling any errors
mService.consumePurchase(3, getPackageName(), purchaseToken);
}
skuDetails = mService.getSkuDetails(3, getPackageName(),
"inapp", querySkus);
int response = skuDetails.getInt("RESPONSE_CODE");
if (response == 0) {
ArrayList<String> responseList = skuDetails
.getStringArrayList("DETAILS_LIST");
for (String thisResponse : responseList) {
JSONObject object = new JSONObject(thisResponse);
String sku = object.getString("productId");
String price = object.getString("price");
if (sku.equals(inappid)) {
System.out.println("price " + price);
Bundle buyIntentBundle = mService
.getBuyIntent(3, getPackageName(), sku,
"inapp",
"bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
PendingIntent pendingIntent = buyIntentBundle
.getParcelable("BUY_INTENT");
startIntentSenderForResult(
pendingIntent.getIntentSender(), 1001,
new Intent(), Integer.valueOf(0),
Integer.valueOf(0), Integer.valueOf(0));
purchaseBtn.setVisibility(View.GONE);
clickBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(),"I am clicked",Toast.LENGTH_SHORT).show();
}
});
}
}
}
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IntentSender.SendIntentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1001) {
String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
if (resultCode == RESULT_OK) {
clickBtn.setVisibility(View.VISIBLE);
try {
JSONObject jo = new JSONObject(purchaseData);
String sku = jo.getString(inappid);
Toast.makeText(
MainActivity.this,
"You have bought the " + sku
+ ". Excellent choice,adventurer!",
Toast.LENGTH_LONG).show();
} catch (JSONException e) {
System.out.println("Failed to parse purchase data.");
e.printStackTrace();
}
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (connection != null) {
unbindService(connection);
}
}
}
固定
IabHelper 中没有错误 Class。我必须将从 JSON 响应中获取的 orderId 值存储为 SharedPreference key/value 对。
类似这样。
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
SharedPreferences.Editor editor = settings.edit();
editor.putString("productId", sku);
editor.putString("purchaseToken", purchaseToken);
editor.putString("orderId", orderId);
editor.commit();
检索它们。
SharedPreferences spreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
productId = spreferences.getString("productId", "");
purchaseToken = spreferences.getString("purchaseToken", "");
orderId = spreferences.getString("orderId", "");
最后使用 if 条件使视图可见或不可见
if(orderId.isEmpty()) {
entryFee.setVisibility(View.VISIBLE);
paymentButton.setVisibility(View.VISIBLE);
paymentText.setVisibility(View.VISIBLE);
teamTextField.setVisibility(View.GONE);
btn.setVisibility(View.GONE);
paymentButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ArrayList skuList = new ArrayList();
skuList.add(inappid);
querySkus = new Bundle();
querySkus.putStringArrayList("ITEM_ID_LIST", skuList);
checkPayment();
}
});
}else{
entryFee.setVisibility(View.GONE);
paymentButton.setVisibility(View.GONE);
paymentText.setVisibility(View.GONE);
teamTextField.setVisibility(View.VISIBLE);
btn.setVisibility(View.VISIBLE);
}
解决方案并不难,但我必须通读大量文档,使用调试器点,仅此而已:)。
使您的代码不那么复杂。将嵌套的点击侦听器移到 oncreate 之外,并适当地命名这些方法。如果我是对的,你想做的是
onCreate:
## init listeners here
## then query purchase
if purchased:
hide purchase button
show click button
else:
hide click button
show purchase button
purchaseClickListener:
make purchase
if successfull:
hide purchase button
show click button
Read the documentation thoroughly before implementing
- Querying for Purchased Items:这不应该在
onCLickListener
内,而是从onCreate
调用以检查是否已购买。 - Purchasing an Item: This is what should happen when the user clicks the purchase button and you may or may not Query for Items Available for Purchase 购买前。
- 购买成功后必须Consume the Purchase。这是里面
onActivityResult
当您终止您的应用程序时,它会再次运行 onCeeate,从头开始设置。您需要检查是否适合在 onCreate 中显示您的按钮,方法是使用付款 Api 检查(如果可能)或将您的状态本地存储在 SharedPreference 中并检查。
您想为 IAP 尝试一些第 3 方库吗?我推荐使用这个库:OpenIAB。使用此库,您不仅可以在 Google Play Store 中进行 IAP,还可以在其他商店(Amazon store、Slide me...)中进行 IAP。查看更多详细信息。
这不容易破解,但我找到了所需的解决方法。最近对 Google 感到非常失望,他们的 Android 网站变得一团糟(很难找到有用的信息)并且他们的示例代码很差。几年前我在做一些 Android 开发时,一切都变得如此简单!这是另一个例子...
确实 IabUtil 有问题,它没有正确地取消它自己的异步任务。整套必要的解决方法来稳定这个东西:
1) 制作方法 flagEndAsync public。它就在那里,只是看不见。
2) 让每个侦听器调用 iabHelper.flagEndAsync 以确保程序正确标记为完成;似乎所有听众都需要它。
3) 用 try/catch 包围调用以捕获可能发生的 IllegalStateException,并以这种方式处理它。
下面的代码可以帮到你,
try {
if (helper != null) {
helper.flagEndAsync();
}
helper.launchPurchaseFlow(.....)
}catch(IllegalStateException e){
e.printStackTrace();
}
我在这里发布答案,以供可能遇到相同问题的人使用。
您应该将来自 Google 服务器的 oprderId 和 transactionId 存储在共享首选项中。只有这样您的程序才会知道何时使购买按钮可见或不可见。
希望这会有所帮助。