SZH*_*SZH 70 java android in-app-billing
在Android应用中实施应用内结算似乎相当复杂.我怎么能这样做?SDK中的示例应用程序只有一个Activity,这对于像我这样有多个Activity的应用程序来说过于简单了.
sfr*_*ini 41
好吧,我会试着解释一下我的经历.我不认为自己是这方面的专家,但我几天都弄坏了头.
对于初学者来说,我在尝试理解示例和应用程序的工作流程时遇到了非常糟糕的时间.我认为从一个简单的例子开始应该会更好,但是很难将代码分成小块并且不知道你是否破坏了任何东西.我会告诉你我有什么以及我从示例中改变了什么来使它工作.
我有一个活动,我的所有购买都来自.它被称为Pro.
首先,您应该使用公共市场开发人员密钥更新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();
}
Run Code Online (Sandbox Code Playgroud)
这样,所有购买都会与此服务通信,然后将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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
好吧,您应该看到市场打开,用户完成或取消购买.
那么重要的是我的PurChaseObserver,它处理市场发送的所有事件.这是它的剥离版本,但你应该明白这一点(通过代码查看我的评论):
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
}
}
}
Run Code Online (Sandbox Code Playgroud)
我相信你不应该编辑其他任何东西.其余代码"有效".您可以先在自己的项目"android.test.purchased"中尝试使用示例SKU.到目前为止,我已经对此进行了测试,但是它仍然有效,但我仍然需要覆盖退款状态等所有内容.在这种情况下,我让用户保留这些功能,但我想确保它在完成之前完美无缺.
我希望它可以帮助你和其他人.
此处提供了完整的Android应用内结算v3的完整示例,并提供了屏幕截图。请查看教程: 使用ServiceConnection类的Android应用内结算v3
希望它会有所帮助。
有关更多说明,请阅读本教程:在第3版API中实现应用内结算
在我们的项目中集成应用内结算库的步骤
更新您的AndroidManifest.xml文件。
创建一个ServiceConnection并将其绑定到IInAppBillingService。
将应用内结算请求从您的应用发送到IInAppBillingService。
处理来自Google Play的应用内结算响应。
更新AndroidManifest.xml
<uses-permission android:name="com.android.vending.BILLING" />
Run Code Online (Sandbox Code Playgroud)
在Manifest.xml文件中添加权限
构建您的应用程序。您应该在项目的/ gen目录中看到一个名为IInAppBillingService.java的生成文件。
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "24.0.0"
defaultConfig {
applicationId "com.inducesmile.androidinapppurchase"
minSdkVersion 14
targetSdkVersion 24
versionCode 2
versionName "1.1"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:24.1.1'
compile 'com.intuit.sdp:sdp-android:1.0.3'
compile 'com.android.support:support-annotations:24.1.1'
compile 'org.jetbrains:annotations-java5:15.0'
}
Run Code Online (Sandbox Code Playgroud)
InAppPurchaseActivity.java和activity_in_app_purchase.xml
在这里,我们的应用程序用户将有机会进行应用程序内购买。在布局文件中,我们将为用户提供以不同面额购买的机会。
InAppPurchaseActivity.java
注意:应该在非UI线程中调用getAllUserPurchase()和itemPurchaseAvailability()方法,以避免应用崩溃。
public class InAppPurchaseActivity extends AppCompatActivity {
private static final String TAG = InAppPurchaseActivity.class.getSimpleName();
private IInAppBillingService mService;
private CustomSharedPreference customSharedPreference;
String[] productIds = new String[]{Helper.ITEM_ONE_ID, Helper.ITEM_TWO_ID, Helper.ITEM_THREE_ID};
private ImageView buyOneButton, buyTwoButton, buyThreeButton;
private static final char[] symbols = new char[36];
static {
for (int idx = 0; idx < 10; ++idx)
symbols[idx] = (char) ('0' + idx);
for (int idx = 10; idx < 36; ++idx)
symbols[idx] = (char) ('a' + idx - 10);
}
private String appPackageName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_in_app_purchase);
appPackageName = this.getPackageName();
Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
serviceIntent.setPackage("com.android.vending");
bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
customSharedPreference = new CustomSharedPreference(InAppPurchaseActivity.this);
buyOneButton = (ImageView)findViewById(R.id.buy_one);
buyOneButton.setVisibility(View.GONE);
assert buyOneButton != null;
buyOneButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(!isBillingSupported()){
Helper.displayMessage(InAppPurchaseActivity.this, getString(R.string.in_app_support));
return;
}
purchaseItem(Helper.ITEM_ONE_ID);
}
});
buyTwoButton = (ImageView)findViewById(R.id.buy_two);
buyTwoButton.setVisibility(View.GONE);
assert buyTwoButton != null;
buyTwoButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(!isBillingSupported()){
Helper.displayMessage(InAppPurchaseActivity.this, getString(R.string.in_app_support));
return;
}
purchaseItem(Helper.ITEM_TWO_ID);
}
});
buyThreeButton = (ImageView)findViewById(R.id.buy_three);
buyThreeButton.setVisibility(View.GONE);
assert buyThreeButton != null;
buyThreeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(!isBillingSupported()){
Helper.displayMessage(InAppPurchaseActivity.this, getString(R.string.in_app_support));
return;
}
purchaseItem(Helper.ITEM_THREE_ID);
}
});
}
ServiceConnection mServiceConn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IInAppBillingService.Stub.asInterface(service);
AvailablePurchaseAsyncTask mAsyncTask = new AvailablePurchaseAsyncTask(appPackageName);
mAsyncTask.execute();
}
};
private void purchaseItem(String sku){
String generatedPayload = getPayLoad();
customSharedPreference.setDeveloperPayLoad(generatedPayload);
try {
Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(), sku, "inapp", generatedPayload);
PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
try {
startIntentSenderForResult(pendingIntent.getIntentSender(), Helper.RESPONSE_CODE, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0));
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == Helper.RESPONSE_CODE) {
int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
if (resultCode == RESULT_OK) {
try {
JSONObject purchaseJsonObject = new JSONObject(purchaseData);
String sku = purchaseJsonObject.getString("productId");
String developerPayload = purchaseJsonObject.getString("developerPayload");
String purchaseToken = purchaseJsonObject.getString("purchaseToken");
//the developerPayload value is better stored in remote database but in this tutorial
//we will use a shared preference
for(int i = 0; i < productIds.length; i++){
if(productIds[i].equals(sku) && developerPayload.equals(customSharedPreference.getDeveloperPayload())){
customSharedPreference.setPurchaseToken(purchaseToken);
//access to private content
Intent contentIntent = new Intent(InAppPurchaseActivity.this, PrivateContentActivity.class);
startActivity(contentIntent);
}
}
}
catch (JSONException e) {
e.printStackTrace();
}
}
}
}
private String getPayLoad(){
RandomString randomString = new RandomString(36);
String payload = randomString.nextString();
return payload;
}
public class RandomString {
private final Random random = new Random();
private final char[] buf;
public RandomString(int length) {
if (length < 1)
throw new IllegalArgumentException("length < 1: " + length);
buf = new char[length];
}
public String nextString() {
for (int idx = 0; idx < buf.length; ++idx)
buf[idx] = symbols[random.nextInt(symbols.length)];
return new String(buf);
}
}
public final class SessionIdentifierGenerator {
private SecureRandom random = new SecureRandom();
public String nextSessionId() {
return new BigInteger(130, random).toString(32);
}
}
private class AvailablePurchaseAsyncTask extends AsyncTask<Void, Void, Bundle> {
String packageName;
public AvailablePurchaseAsyncTask(String packageName){
this.packageName = packageName;
}
@Override
protected Bundle doInBackground(Void... voids) {
ArrayList<String> skuList = new ArrayList<String>();
skuList.add(Helper.ITEM_ONE_ID);
skuList.add(Helper.ITEM_TWO_ID);
skuList.add(Helper.ITEM_THREE_ID);
Bundle query = new Bundle();
query.putStringArrayList(Helper.ITEM_ID_LIST, skuList);
Bundle skuDetails = null;
try {
skuDetails = mService.getSkuDetails(3, packageName, "inapp", query);
} catch (RemoteException e) {
e.printStackTrace();
}
return skuDetails;
}
@Override
protected void onPostExecute(Bundle skuDetails) {
List<AvailablePurchase> canPurchase = new ArrayList<AvailablePurchase>();
int response = skuDetails.getInt("RESPONSE_CODE");
if (response == 0) {
ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST");
if(responseList != null){
for (String thisResponse : responseList) {
JSONObject object = null;
try {
object = new JSONObject(thisResponse);
String sku = object.getString("productId");
String price = object.getString("price");
canPurchase.add(new AvailablePurchase(sku, price));
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
if(checkIfPurchaseIsAvailable(canPurchase, productIds[0])){
buyOneButton.setVisibility(View.VISIBLE);
}else{
buyOneButton.setVisibility(View.GONE);
}
if(checkIfPurchaseIsAvailable(canPurchase, productIds[1])){
buyTwoButton.setVisibility(View.VISIBLE);
}else{
buyTwoButton.setVisibility(View.GONE);
}
if(checkIfPurchaseIsAvailable(canPurchase, productIds[2])){
buyThreeButton.setVisibility(View.VISIBLE);
}else{
buyThreeButton.setVisibility(View.GONE);
}
}
}
@org.jetbrains.annotations.Contract("null, _ -> false")
private boolean checkIfPurchaseIsAvailable(List<AvailablePurchase> all, String productId){
if(all == null){ return false;}
for(int i = 0; i < all.size(); i++){
if(all.get(i).getSku().equals(productId)){
return true;
}
}
return false;
}
public boolean isBillingSupported(){
int response = 1;
try {
response = mService.isBillingSupported(3, getPackageName(), "inapp");
} catch (RemoteException e) {
e.printStackTrace();
}
if(response > 0){
return false;
}
return true;
}
public void consumePurchaseItem(String purchaseToken){
try {
int response = mService.consumePurchase(3, getPackageName(), purchaseToken);
if(response != 0){
return;
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
public Bundle getAllUserPurchase(){
Bundle ownedItems = null;
try {
ownedItems = mService.getPurchases(3, getPackageName(), "inapp", null);
} catch (RemoteException e) {
e.printStackTrace();
}
return ownedItems;
}
public List<UserPurchaseItems> extractAllUserPurchase(Bundle ownedItems){
List<UserPurchaseItems> mUserItems = new ArrayList<UserPurchaseItems>();
int response = ownedItems.getInt("RESPONSE_CODE");
if (response == 0) {
ArrayList<String> ownedSkus = ownedItems.getStringArrayList("INAPP_PURCHASE_ITEM_LIST");
ArrayList<String> purchaseDataList = ownedItems.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
ArrayList<String> signatureList = ownedItems.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
String continuationToken = ownedItems.getString("INAPP_CONTINUATION_TOKEN");
if(purchaseDataList != null){
for (int i = 0; i < purchaseDataList.size(); ++i) {
String purchaseData = purchaseDataList.get(i);
assert signatureList != null;
String signature = signatureList.get(i);
assert ownedSkus != null;
String sku = ownedSkus.get(i);
UserPurchaseItems allItems = new UserPurchaseItems(sku, purchaseData, signature);
mUserItems.add(allItems);
}
}
}
return mUserItems;
}
@Override
public void onDestroy() {
super.onDestroy();
if (mService != null) {
unbindService(mServiceConn);
}
}
}
Run Code Online (Sandbox Code Playgroud)
创建助手包目录
创建一个新的程序包文件夹并将其命名为助手。在包内,创建一个新的Java文件Helper.java。
Helper.java
public class Helper {
public static final String ITEM_ID_LIST = "ITEM_ID_LIST";
public static final String ITEM_ONE_ID = "productone";
public static final String ITEM_TWO_ID = "producttwo";
public static final String ITEM_THREE_ID = "productthree";
public static final int RESPONSE_CODE = 1001;
public static final String SHARED_PREF = "shared_pref";
public static final String DEVELOPER_PAYLOAD = "developer_payload";
public static final String PURCHASE_TOKEN = "purchase_token";
public static void displayMessage(Context context, String message){
Toast.makeText(context.getApplicationContext(), message, Toast.LENGTH_LONG).show();
}
}
Run Code Online (Sandbox Code Playgroud)
测试应用内结算购买
应用内购买测试期间可能会遇到的错误
您要求的商品无法购买
解决方案– 根据Stackoverflow中的AndreiBogdan的说法,
所有的功劳归因于Inducesmile的教程
Android开发者博客还建议提供有关销售应用内商品的培训课程。要查看完整的实现并了解如何测试应用程序,请检查此教程:销售应用内商品
好的,这是网上没有太多可用文档的事情之一,所以我将尽我所能一步一步地解释一切。摘自我的博客文章,这是一个更详细的版本(带有屏幕截图),位于 The Millibit 上。无需再费周折,
第一步:权限 这是最简单的一步。导航到您的 manifest.xml 文件并在您的标签下添加以下行:
<uses-permission android:name="com.android.vending.BILLING" />
Run Code Online (Sandbox Code Playgroud)
这将授予您的应用访问应用内结算的权限。如果您的目标版本高于 API 22,则需要确保在运行时授予此权限。
第二步: Play Console 现在您需要将您的应用上传到 Google Play Console。我们还没有向公众发布我们的应用程序(别担心),我们只是将它上传到 BETA RELEASE 部分,这将允许我们测试应用程序内购买。我们需要这样做的原因是,Google 需要上传您的 APK 的某个版本,以便计费流程真正起作用。
创建应用程序
按照步骤设置您的应用程序
转到应用程序版本
导航到测试版
在 Android Studio 中为您的应用创建一个 APK,然后在 Play 管理中心将其上传到 Beta 版
(在发布之前,请确保您已经填写了商品详情、内容评级和定价和分发)
第三步:设置项目 好的,这是您必须复制和粘贴一堆文件的部分。
首先,获取这个文件,下载它,然后将它放在src/main它应该将自己构建到一个文件夹中接下来,获取整个util 文件夹并将其粘贴到src/java folder.然后重建您的项目以解决错误。Util 文件夹包含以下类:
第四步:创建产品
创建管理产品
单击保存并制作“定价模板”
在这里,您将选择该产品的价格。您可以选择不同国家/地区的价格,或者如果您只选择价格下的所有国家/地区,则它会自动调整:
最后,记下您产品的 ID。我们将在接下来的几个步骤中使用此 ID。
转到“服务和 API”并获取您的 Base64EncodedString。将其复制并粘贴到某个地方的记事本中,以便您可以访问它。不要与任何人分享这个,他们将能够用它做恶意的事情。
第五步:终于!我们可以开始编码:我们将首先绑定到应用内计费库,并查询用户已经/尚未购买的东西。然后,我们将购买我们之前设置的产品。
首先,导入我们之前设置的所有内容:
import util.*;
Run Code Online (Sandbox Code Playgroud)
现在我们将使用一个名为 mHelper 的 IabHelper 对象,我们将用它做所有事情。
base64EncodedPublicKey = ""; //PUT YOUR BASE64KEY HERE
mHelper = new IabHelper(this, base64EncodedPublicKey);
mHelper.enableDebugLogging(false); //set to false in real app
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
if (!result.isSuccess()) {
// Oh no, there was a problem.
if (result.getResponse() == 3) {
new AlertDialog.Builder(MainActivity.this)
.setTitle("In app billing")
.setMessage("This device is not compatible with In App Billing, so" +
" you may not be able to buy the premium version on your phone. ")
.setPositiveButton("Okay", null)
.show();
}
Log.v(TAG, "Problem setting up In-app Billing: " + result);
} else {
Log.v(TAG, "YAY, in app billing set up! " + result);
try {
mHelper.queryInventoryAsync(mGotInventoryListener); //Getting inventory of purchases and assigning listener
} catch (IabHelper.IabAsyncInProgressException e) {
e.printStackTrace();
}
}
}
});
Run Code Online (Sandbox Code Playgroud)
好的,让我分解一下这里发生的事情。基本上,我们正在调用“startSetup”来初始化我们的“IabHelper”。如果设置成功,我们会查询用户已经购买了什么并将响应存储在 中mGotInventoryListener,接下来我们将对其进行编码:
IabHelper.QueryInventoryFinishedListener mGotInventoryListener
= new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
i = inventory;
if (result.isFailure()) {
// handle error here
Log.v(TAG, "failure in checking if user has purchases");
} else {
// does the user have the premium upgrade?
if (inventory.hasPurchase("premium_version")) {
premiumEditor.putBoolean("hasPremium", true);
premiumEditor.commit();
Log.v(TAG, "Has purchase, saving in storage");
} else {
premiumEditor.putBoolean("hasPremium", false);
premiumEditor.commit();
Log.v(TAG, "Doesn't have purchase, saving in storage");
}
}
}
};
Run Code Online (Sandbox Code Playgroud)
上面的代码是不言自明的。基本上,它只是检查用户已经购买了什么。现在我们知道用户是否已经购买了我们的产品,我们知道是否要求他们购买我们的产品!如果他们以前从未购买过我们的产品,让我们开始购买请求:
public void buyPremium() {
try {
mHelper.flagEndAsync();//If any async is going, make sure we have it stop eventually
mHelper.launchPurchaseFlow(this, "premium_version", 9, mPurchaseFinishedListener, "SECURITYSTRING"); //Making purchase request and attaching listener
} catch (Exception e) {
e.printStackTrace();
mHelper.flagEndAsync();//If any async is going, make sure we have it stop eventually
new AlertDialog.Builder(MainActivity.this)
.setTitle("Error")
.setMessage("An error occurred in buying the premium version. Please try again.")
.setPositiveButton("Okay", null)
.show();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
// Pass on the activity result to the helper for handling
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
}
else
Log.d(TAG, "onActivityResult handled by IABUtil.");
}
}
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener
= new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.v(TAG, "purchase finished");
if (purchase != null) {
if (purchase.getSku().equals("premium_version")) {
Toast.makeText(MainActivity.this, "Purchase successful!", Toast.LENGTH_SHORT).show();
premiumEditor.putBoolean("hasPremium", true);
premiumEditor.commit();
}
} else {
return;
}
if (result.isFailure()) {
return;
}
}
};
Run Code Online (Sandbox Code Playgroud)
在这里,我们使用以下内容购买项目(使用我们之前在游戏控制台中生成的 ID):
mHelper.launchPurchaseFlow(this, "premium_version", 9, mPurchaseFinishedListener, "SECURITYSTRING"); //Making purchase request and attaching listener
Run Code Online (Sandbox Code Playgroud)
注意我们传入mPurchaseFinishedListener的参数。这意味着购买的结果将返回给这个监听器。然后,我们简单地检查购买是否为空,如果不是,则用他们购买的任何功能奖励用户。
不要让听众泄漏!当应用程序销毁时,我们必须销毁它们。
@Override
public void onDestroy() {
super.onDestroy();
if (mHelper != null)
try {
mHelper.dispose();
mHelper = null;
} catch (IabHelper.IabAsyncInProgressException e) {
e.printStackTrace();
}
}
Run Code Online (Sandbox Code Playgroud)
最后,如果您想消费您的购买,使其再次可供购买,您可以轻松完成。这方面的一个例子是,如果用户为虚拟汽车购买了汽油,但汽油用完了。他们需要再次购买相同的产品,您可以通过消费它来进行第二次购买:
public void consume(){
//MAKING A QUERY TO GET AN ACCURATE INVENTORY
try {
mHelper.flagEndAsync(); //If any async is going, make sure we have it stop eventually
mHelper.queryInventoryAsync(mGotInventoryListener); //Getting inventory of purchases and assigning listener
if(i.getPurchase("gas")==null){
Toast.makeText(this, "Already consumed!", Toast.LENGTH_SHORT).show();
}
} catch (IabHelper.IabAsyncInProgressException e) {
e.printStackTrace();
Toast.makeText(this, "Error, try again", Toast.LENGTH_SHORT).show();
mHelper.flagEndAsync();//If any async is going, make sure we have it stop eventually
}
//ACTUALLY CONSUMING
try {
mHelper.flagEndAsync();//If any async is going, make sure we have it stop eventually
this.mHelper.consumeAsync(this.i.getPurchase("gas"), new IabHelper.OnConsumeFinishedListener() {
public void onConsumeFinished(Purchase paramAnonymousPurchase, IabResult paramAnonymousIabResult) {
//resell the gas to them
}
});
return;
} catch (IabHelper.IabAsyncInProgressException localIabAsyncInProgressException) {
localIabAsyncInProgressException.printStackTrace();
Toast.makeText(this, "ASYNC IN PROGRESS ALREADY!!!!" +localIabAsyncInProgressException, Toast.LENGTH_LONG).show();
Log.v("myTag", "ASYNC IN PROGRESS ALREADY!!!");
mHelper.flagEndAsync();
}
}
Run Code Online (Sandbox Code Playgroud)
就是这样!你现在可以开始赚钱了。真的就是这么简单!
同样,如果您想要本教程的更详细版本(带有屏幕截图和图片),请访问此处的原始帖子。如果您还有其他问题,请在评论中告诉我。
为了更好地了解如何使用 Google Play 计费库进行应用内计费,请参考以下流程图:
您可以按照我在本文中解释的逐步集成进行操作:
https://medium.com/@surabhichoudhary/in-app-purchasing-with-google-play-billing-library-6a72e289a78e
如果您需要演示,这是项目链接:https : //github.com/surabhi6/InAppPurchaseDemo
如果您想使用一个简单的库在Google Play和Amazon Appstore中发布,则可以使用RoboBillingLibrary。它将两者的详细信息抽象到一个易于使用的库中。详细说明在Github页面上。
| 归档时间: |
|
| 查看次数: |
43260 次 |
| 最近记录: |