Android 应用内结算:制作应用内广告时不会删除广告
Android In-App Billing: Ads are not removing when In-App is made
我在 Activity
中实施了应用内结算
这是我的onIabPurchaseFinished()
方法:
@Override
public void onIabPurchaseFinished(IabResult result, Purchase info) {
if (!verifyDeveloperPayload(info)) {
Toast.makeText(this, R.string.error_purchasing, Toast.LENGTH_LONG).show();
}
Toast.makeText(this, R.string.premium_bought, Toast.LENGTH_LONG).show();
if (info.getSku().equals("chords_premium")) {
/** salva isPremium tra SharedPreferences */
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString("status", "purchased");
editor.apply();
}
}
如您所见,我将字符串 "status"
保存到 SharedPreferences
,这样我就可以从任何地方访问它,即使在应用程序关闭后也可以保存它。
然后在我实施广告的其他活动中,我这样写:
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
final String status = prefs.getString("status", "free");
/** gestisce le pubblicita */
if (status.equals("free")) {
MobileAds.initialize(getApplicationContext(), "ca-app-pub-6723047396589178/2654753246");
AdView listBanner = (AdView) findViewById(R.id.chords_list_banner);
AdRequest adRequest = new AdRequest.Builder().build();
listBanner.loadAd(adRequest);
/** carica Ad a tutto schermo */
chordsListAd = new InterstitialAd(this);
chordsListAd.setAdUnitId("ca-app-pub-6723047396589178/7447672046");
requestNewInterstitial();
chordsListAd.setAdListener(new AdListener() {
@Override
public void onAdClosed() {
requestNewInterstitial();
}
});
}
正如您在此处看到的那样,广告被 if statement
包围,该 if statement
检查 "status"
String 是否设置为空闲。
问题是当我购买 Premium 时,广告仍然显示。我该如何解决?
检查是否进行了应用内购买:
//*************************************checking in app purchase has been made********************************//
void testInApp()
{
if (!blnBind) return;
if (mService == null) return;
int result;
try {
result = mService.isBillingSupported(3, getPackageName(), "inapp");
//Toast.makeText(context, "isBillingSupported() - success : return " + String.valueOf(result), Toast.LENGTH_SHORT).show();
Log.i(tag, "isBillingSupported() - success : return " + String.valueOf(result));
} catch (RemoteException e) {
e.printStackTrace();
//Toast.makeText(context, "isBillingSupported() - fail!", Toast.LENGTH_SHORT).show();
Log.w(tag, "isBillingSupported() - fail!");
return;
}
}
void checkInApp()
{
if (!blnBind) return;
if (mService == null) return;
Bundle ownedItems;
try {
ownedItems = mService.getPurchases(3, getPackageName(), "inapp", null);
//Toast.makeText(context, "getPurchases() - success return Bundle", Toast.LENGTH_SHORT).show();
Log.i(tag, "getPurchases() - success return Bundle");
} catch (RemoteException e) {
e.printStackTrace();
//Toast.makeText(context, "getPurchases - fail!", Toast.LENGTH_SHORT).show();
Log.w(tag, "getPurchases() - fail!");
return;
}
int response = ownedItems.getInt("RESPONSE_CODE");
//Toast.makeText(context, "getPurchases() - \"RESPONSE_CODE\" return " + String.valueOf(response), Toast.LENGTH_SHORT).show();
Log.i(tag, "getPurchases() - \"RESPONSE_CODE\" return " + String.valueOf(response));
if (response != 0) return;
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");
String continuationToken = ownedItems.getString("INAPP_CONTINUATION_TOKEN");
Log.i(tag, "getPurchases() - \"INAPP_PURCHASE_ITEM_LIST\" return " + ownedSkus.toString());
Log.i(tag, "getPurchases() - \"INAPP_PURCHASE_DATA_LIST\" return " + purchaseDataList.toString());
Log.i(tag, "getPurchases() - \"INAPP_DATA_SIGNATURE\" return " + (signatureList != null ? signatureList.toString() : "null"));
Log.i(tag, "getPurchases() - \"INAPP_CONTINUATION_TOKEN\" return " + (continuationToken != null ? continuationToken : "null"));
// TODO: management owned purchase
try {
if(purchaseDataList.size()>0){
jinapp=new JSONArray(purchaseDataList.toString());
JSONObject c = jinapp.getJSONObject(0);
String productid=c.getString("productId");
if(productid!=null){
SharedPreferences.Editor editor = prefpurchase.edit();
editor.putBoolean(Constants.APP_IS_PURCHASED,true);
editor.commit();
}
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO: management owned purchase
}
在启动画面中写入代码
现在,在您展示广告的 activity/fragment 中,编写以下代码:
//*******************to check purchase has been made.If yes disable ads and no then show ads******************//
prefpurchase = this.getSharedPreferences(Constants.GET_IN_APP_STATE, Context.MODE_PRIVATE);
//Toast.makeText(context, "bindService - return " + String.valueOf(blnBind), Toast.LENGTH_SHORT).show();
//In App Purchase
ispurchased=prefpurchase.getBoolean(Constants.APP_IS_PURCHASED,false);
System.out.println("ispurchased-->"+ispurchased);
if(ispurchased)
{
setContentView(R.layout.activity_home_noads);
}else{
System.out.println("Getting ad");
setContentView(R.layout.activity_home);
//Locate the Banner Ad in activity_main.xml
AdView adView = (AdView) this.findViewById(R.id.adView);
AdRequest adRequest = new AdRequest.Builder()
// Add a test device to show Test Ads
//.addTestDevice(AdRequest.DEVICE_ID_EMULATOR)
//.addTestDevice("B2D63***************************")
.build();
// Load ads into Banner Ads
adView.loadAd(adRequest);
}
//*******************************************************************************************************//
逻辑很简单,您正在创建两个版本的布局,一个有广告,另一个没有广告。
根据 sharedpreference 的值加载正确的布局。
m服务:
在 onCreate() 之前在 splashscreen 中全局写入此代码:
private IInAppBillingService mService;
private 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);
}
};
blnBind
全局声明 blnBind:
boolean blnBind;
在 SplashActivity 的 onCreate() 中写入:
// Bind Service
blnBind = bindService(new Intent(
"com.android.vending.billing.InAppBillingService.BIND"),
mServiceConn, Context.BIND_AUTO_CREATE);
//Toast.makeText(context, "bindService - return " + String.valueOf(blnBind), Toast.LENGTH_SHORT).show();
Log.i(tag, "bindService - return " + String.valueOf(blnBind));
//In App Purchase
GET_IN_APP_STATE 或 APP_IS_PURCHASED 是为共享首选项创建的,它充当首选项值的键。
//Preferences to check in app purchase
final static public String GET_IN_APP_STATE = "prefinapp";
public static final String APP_IS_PURCHASED ="AppIsPurchased";
无论何时进行购买,都不要忘记将共享偏好值设置为 true。
这是因为您将数据保存在 Base Context 中并试图在当前 Activity context 中使用(这个).
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
到
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
此外,更推荐的查询应用内购买项目的方法是查询应用内库存,而不是存储在 sharedprefs 中。
如 Google 文档中所述
查询已购买商品
购买成功后,Google Play 的应用内结算服务会在本地缓存用户的购买数据。经常查询用户购买的应用内结算服务是一个很好的做法,例如在应用启动或恢复时,这样用户当前的应用内商品所有权信息始终反映在您的应用中。
要从您的应用中检索用户的购买,请在您的 IabHelper 实例上调用 queryInventoryAsync(QueryInventoryFinishedListener)。 QueryInventoryFinishedListener 参数指定一个侦听器,该侦听器在查询操作完成时收到通知并处理查询响应。从您的主线程进行此调用是安全的。
mHelper.queryInventoryAsync(mGotInventoryListener); //mHelper is IabHelper instance
如果查询成功,查询结果将存储在一个 Inventory 对象中,该对象将传递回侦听器。应用内结算服务 returns 仅限当前登录设备的用户帐户进行的购买。
IabHelper.QueryInventoryFinishedListener mGotInventoryListener
= new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
if (result.isFailure()) {
// handle error here
}
else {
// does the user have the premium upgrade?
mIsPremium = inventory.hasPurchase(SKU_PREMIUM);
// update UI accordingly
}
}
};
我在 Activity
中实施了应用内结算这是我的onIabPurchaseFinished()
方法:
@Override
public void onIabPurchaseFinished(IabResult result, Purchase info) {
if (!verifyDeveloperPayload(info)) {
Toast.makeText(this, R.string.error_purchasing, Toast.LENGTH_LONG).show();
}
Toast.makeText(this, R.string.premium_bought, Toast.LENGTH_LONG).show();
if (info.getSku().equals("chords_premium")) {
/** salva isPremium tra SharedPreferences */
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString("status", "purchased");
editor.apply();
}
}
如您所见,我将字符串 "status"
保存到 SharedPreferences
,这样我就可以从任何地方访问它,即使在应用程序关闭后也可以保存它。
然后在我实施广告的其他活动中,我这样写:
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
final String status = prefs.getString("status", "free");
/** gestisce le pubblicita */
if (status.equals("free")) {
MobileAds.initialize(getApplicationContext(), "ca-app-pub-6723047396589178/2654753246");
AdView listBanner = (AdView) findViewById(R.id.chords_list_banner);
AdRequest adRequest = new AdRequest.Builder().build();
listBanner.loadAd(adRequest);
/** carica Ad a tutto schermo */
chordsListAd = new InterstitialAd(this);
chordsListAd.setAdUnitId("ca-app-pub-6723047396589178/7447672046");
requestNewInterstitial();
chordsListAd.setAdListener(new AdListener() {
@Override
public void onAdClosed() {
requestNewInterstitial();
}
});
}
正如您在此处看到的那样,广告被 if statement
包围,该 if statement
检查 "status"
String 是否设置为空闲。
问题是当我购买 Premium 时,广告仍然显示。我该如何解决?
检查是否进行了应用内购买:
//*************************************checking in app purchase has been made********************************//
void testInApp()
{
if (!blnBind) return;
if (mService == null) return;
int result;
try {
result = mService.isBillingSupported(3, getPackageName(), "inapp");
//Toast.makeText(context, "isBillingSupported() - success : return " + String.valueOf(result), Toast.LENGTH_SHORT).show();
Log.i(tag, "isBillingSupported() - success : return " + String.valueOf(result));
} catch (RemoteException e) {
e.printStackTrace();
//Toast.makeText(context, "isBillingSupported() - fail!", Toast.LENGTH_SHORT).show();
Log.w(tag, "isBillingSupported() - fail!");
return;
}
}
void checkInApp()
{
if (!blnBind) return;
if (mService == null) return;
Bundle ownedItems;
try {
ownedItems = mService.getPurchases(3, getPackageName(), "inapp", null);
//Toast.makeText(context, "getPurchases() - success return Bundle", Toast.LENGTH_SHORT).show();
Log.i(tag, "getPurchases() - success return Bundle");
} catch (RemoteException e) {
e.printStackTrace();
//Toast.makeText(context, "getPurchases - fail!", Toast.LENGTH_SHORT).show();
Log.w(tag, "getPurchases() - fail!");
return;
}
int response = ownedItems.getInt("RESPONSE_CODE");
//Toast.makeText(context, "getPurchases() - \"RESPONSE_CODE\" return " + String.valueOf(response), Toast.LENGTH_SHORT).show();
Log.i(tag, "getPurchases() - \"RESPONSE_CODE\" return " + String.valueOf(response));
if (response != 0) return;
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");
String continuationToken = ownedItems.getString("INAPP_CONTINUATION_TOKEN");
Log.i(tag, "getPurchases() - \"INAPP_PURCHASE_ITEM_LIST\" return " + ownedSkus.toString());
Log.i(tag, "getPurchases() - \"INAPP_PURCHASE_DATA_LIST\" return " + purchaseDataList.toString());
Log.i(tag, "getPurchases() - \"INAPP_DATA_SIGNATURE\" return " + (signatureList != null ? signatureList.toString() : "null"));
Log.i(tag, "getPurchases() - \"INAPP_CONTINUATION_TOKEN\" return " + (continuationToken != null ? continuationToken : "null"));
// TODO: management owned purchase
try {
if(purchaseDataList.size()>0){
jinapp=new JSONArray(purchaseDataList.toString());
JSONObject c = jinapp.getJSONObject(0);
String productid=c.getString("productId");
if(productid!=null){
SharedPreferences.Editor editor = prefpurchase.edit();
editor.putBoolean(Constants.APP_IS_PURCHASED,true);
editor.commit();
}
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO: management owned purchase
}
在启动画面中写入代码
现在,在您展示广告的 activity/fragment 中,编写以下代码:
//*******************to check purchase has been made.If yes disable ads and no then show ads******************//
prefpurchase = this.getSharedPreferences(Constants.GET_IN_APP_STATE, Context.MODE_PRIVATE);
//Toast.makeText(context, "bindService - return " + String.valueOf(blnBind), Toast.LENGTH_SHORT).show();
//In App Purchase
ispurchased=prefpurchase.getBoolean(Constants.APP_IS_PURCHASED,false);
System.out.println("ispurchased-->"+ispurchased);
if(ispurchased)
{
setContentView(R.layout.activity_home_noads);
}else{
System.out.println("Getting ad");
setContentView(R.layout.activity_home);
//Locate the Banner Ad in activity_main.xml
AdView adView = (AdView) this.findViewById(R.id.adView);
AdRequest adRequest = new AdRequest.Builder()
// Add a test device to show Test Ads
//.addTestDevice(AdRequest.DEVICE_ID_EMULATOR)
//.addTestDevice("B2D63***************************")
.build();
// Load ads into Banner Ads
adView.loadAd(adRequest);
}
//*******************************************************************************************************//
逻辑很简单,您正在创建两个版本的布局,一个有广告,另一个没有广告。
根据 sharedpreference 的值加载正确的布局。
m服务:
在 onCreate() 之前在 splashscreen 中全局写入此代码:
private IInAppBillingService mService;
private 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);
}
};
blnBind
全局声明 blnBind:
boolean blnBind;
在 SplashActivity 的 onCreate() 中写入:
// Bind Service
blnBind = bindService(new Intent(
"com.android.vending.billing.InAppBillingService.BIND"),
mServiceConn, Context.BIND_AUTO_CREATE);
//Toast.makeText(context, "bindService - return " + String.valueOf(blnBind), Toast.LENGTH_SHORT).show();
Log.i(tag, "bindService - return " + String.valueOf(blnBind));
//In App Purchase
GET_IN_APP_STATE 或 APP_IS_PURCHASED 是为共享首选项创建的,它充当首选项值的键。
//Preferences to check in app purchase
final static public String GET_IN_APP_STATE = "prefinapp";
public static final String APP_IS_PURCHASED ="AppIsPurchased";
无论何时进行购买,都不要忘记将共享偏好值设置为 true。
这是因为您将数据保存在 Base Context 中并试图在当前 Activity context 中使用(这个).
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
到
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
此外,更推荐的查询应用内购买项目的方法是查询应用内库存,而不是存储在 sharedprefs 中。
如 Google 文档中所述
查询已购买商品
购买成功后,Google Play 的应用内结算服务会在本地缓存用户的购买数据。经常查询用户购买的应用内结算服务是一个很好的做法,例如在应用启动或恢复时,这样用户当前的应用内商品所有权信息始终反映在您的应用中。
要从您的应用中检索用户的购买,请在您的 IabHelper 实例上调用 queryInventoryAsync(QueryInventoryFinishedListener)。 QueryInventoryFinishedListener 参数指定一个侦听器,该侦听器在查询操作完成时收到通知并处理查询响应。从您的主线程进行此调用是安全的。
mHelper.queryInventoryAsync(mGotInventoryListener); //mHelper is IabHelper instance
如果查询成功,查询结果将存储在一个 Inventory 对象中,该对象将传递回侦听器。应用内结算服务 returns 仅限当前登录设备的用户帐户进行的购买。
IabHelper.QueryInventoryFinishedListener mGotInventoryListener
= new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
if (result.isFailure()) {
// handle error here
}
else {
// does the user have the premium upgrade?
mIsPremium = inventory.hasPurchase(SKU_PREMIUM);
// update UI accordingly
}
}
};