好吧,我会尝试解释一下我的经历。我不认为自己是这方面的专家,但几天来我伤透了脑筋。
对于初学者来说,我在尝试理解示例和应用程序的工作流程时经历了一段非常糟糕的时光。我认为最好从一个简单的示例开始,但是将代码分成小块并且不知道是否破坏了任何内容非常困难。我将告诉您我拥有什么以及我对示例进行了哪些更改以使其正常工作。
我有一个活动,我的所有购买都来自其中。它被称为专业版。
首先,您应该使用公共市场开发人员密钥更新 Security 类中的变量 base64EncodedPublicKey,否则您将看到一个不错的异常。
好吧,我将 Activity 绑定到 BillingService,如下所示:
public class Pro extends TrackedActivity implements OnItemClickListener {
private BillingService mBillingService;
private BillingPurchaseObserver mBillingPurchaseObserver;
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pro);
//Do my stuff
mBillingService = new BillingService();
mBillingService.setContext(getApplicationContext());
mHandler = new Handler();
mBillingPurchaseObserver = new BillingPurchaseObserver(mHandler);
}
}
@Override
protected void onStart() {
//Register the observer to the service
super.onStart();
ResponseHandler.register(mBillingPurchaseObserver);
}
@Override
protected void onStop() {
//Unregister the observer since you dont need anymore
super.onStop();
ResponseHandler.unregister(mBillingPurchaseObserver);
}
@Override
protected void onDestroy() {
//Unbind the service
super.onDestroy();
mBillingService.unbind();
}
这样,所有购买都会与该服务进行通信,然后该服务会将 JSON 请求发送到市场。您可能认为购买是在同一时刻进行的,但事实并非如此。您发送请求,购买可能会在几分钟或几小时后完成。我认为这主要是服务器过载和信用卡审批问题。
然后我有一个包含我的商品的 ListView,并在每个商品上打开一个 AlertDialog,邀请他们购买该商品。当他们点击某个项目时,我会这样做:
private class BuyButton implements DialogInterface.OnClickListener {
private BillingItem item = null;
private String developerPayload;
public BuyButton(BillingItem item, String developerPayload) {
this.item = item;
this.developerPayload = developerPayload;
}
@Override
public void onClick(DialogInterface dialog, int which) {
if (GeneralHelper.isOnline(getApplicationContext())){
//I track the buy here with GA SDK.
mBillingService.requestPurchase(this.item.getSku(), this.developerPayload);
} else {
Toast.makeText(getApplicationContext(), R.string.msg_not_online, Toast.LENGTH_SHORT).show();
}
}
}
好的,您应该看到市场打开并且用户完成或取消购买。
那么重要的是我的 PurChase Observer,它处理市场发送的所有事件。这是它的精简版本,但您应该明白要点(请参阅我在整个代码中的评论):
private class BillingPurchaseObserver extends PurchaseObserver {
public BillingPurchaseObserver(Handler handler) {
super(Pro.this, handler);
}
@Override
public void onBillingSupported(boolean supported) {
if (supported) {
//Enable buy functions. Not required, but you can do stuff here. The market first checks if billing is supported. Maybe your country is not supported, for example.
} else {
Toast.makeText(getApplicationContext(), R.string.billing_not_supported, Toast.LENGTH_LONG).show();
}
}
@Override
public void onPurchaseStateChange(PurchaseState purchaseState, String itemId,
int quantity, long purchaseTime, String developerPayload) {
//This is the method that is called when the buy is completed or refunded I believe.
// Here you can do something with the developerPayload. Its basically a Tag you can use to follow your transactions. i dont use it.
BillingItem item = BillingItem.getBySku(getApplicationContext(), itemId);
if (purchaseState == PurchaseState.PURCHASED) {
if (item != null){
//This is my own implementation that sets the item purchased in my database. BillingHelper is a class with methods I use to check if the user bought an option and update the UI. You should also check for refunded. You can see the Consts class to find what you need to check for.
boolean resu = item.makePurchased(getApplicationContext());
if (resu){
Toast.makeText(getApplicationContext(), R.string.billing_item_purchased, Toast.LENGTH_LONG).show();
}
}
}
}
private void trackPurchase(BillingItem item, long purchaseTime) {
//My code to track the purchase in GA
}
@Override
public void onRequestPurchaseResponse(RequestPurchase request,
ResponseCode responseCode) {
//This is the callback that happens when you sent the request. It doesnt mean you bought something. Just that the Market received it.
if (responseCode == ResponseCode.RESULT_OK) {
Toast.makeText(getApplicationContext(), R.string.billing_item_request_sent, Toast.LENGTH_SHORT).show();
} else if (responseCode == ResponseCode.RESULT_USER_CANCELED) {
//The user canceled the item.
} else {
//If it got here, the Market had an unexpected problem.
}
}
@Override
public void onRestoreTransactionsResponse(RestoreTransactions request,
ResponseCode responseCode) {
if (responseCode == ResponseCode.RESULT_OK) {
//Restore transactions should only be run once in the lifecycle of your application unless you reinstalled the app or wipe the data.
SharedPreferences.Editor edit = PreferencesHelper.getInstance().getDefaultSettings(getApplicationContext()).edit();
edit.putBoolean(Consts.DB_INITIALIZED, true);
edit.commit();
} else {
//Something went wrong
}
}
}
我相信您不需要编辑其他任何内容。其余代码“有效”。
您可以首先在自己的项目“android.test.purchased”中尝试使用示例 SKU。到目前为止,我已经对此进行了测试并且它有效,但是我仍然需要涵盖诸如退款状态之类的所有内容。在这种情况下,我让用户保留这些功能,但我想在修改它之前确保它完美运行。
我希望它对您和其他人有所帮助。