问题描述
编辑***
仍在寻找原始问题的答案。为什么Android不会看到之前购买的商品而不是让用户再次付款?设置SharedPreferences是一个不错的主意,但如果用户卸载该怎么办?他们将不得不再次购买。我不希望这个用户。谢谢。
Edit***still looking for an answer to my original question. Why won't Android see the item has been bought previously instead of making the user pay again? Setting SharedPreferences is an OK idea, but what if the user uninstalls? They would have to buy again. I do not want this for the users. Thank you.
我试图找出应用程序没有正确库存的原因,我从TrivialDrive中获取并尝试将其设为我自己的。我相信我删除了所有的消费,我只有一件商品可以购买;高级升级。这应该只买一次,从不收取两次。当我在平板电脑上编译并运行应用程序时,我通过购买流程确定并且一切顺利,直到我使用任务管理器关闭应用程序并重新打开它。一旦重新打开,它就会要求再次购买溢价,而不是通过并执行高级功能。
I tried to figure out why the app does not inventory correctly, I took this from TrivialDrive and tried to make it my own. I believe I removed all the consume and I only have one item to purchase; a premium upgrade. This should be bought only once and never charged twice. When I compile and run the app on my tablet I pass the purchase process OK and all seems well, until I use the task manager to close the app and re-open it. Once it's re-opened it asks to purchase premium again instead of passing that and performing the premium function.
以下是代码:
public class myClass extends SherlockActivity {
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private ActionBarDrawerToggle mDrawerToggle;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
private String[] mPlanetTitles;
public static final int DIALOG_DOWNLOAD_PROGRESS = 0;
ProgressBar pd = null;
private ProgressDialog mProgressDialog;
Spinner spLoadFrom;
WebView wv;
private LinearLayout container;
private Button nextButton, closeButton;
private EditText findBox;
private static final String TAG = "Web";
IabHelper mHelper;
static boolean mIsPremium = false;
boolean mIsUserPremium = false;
boolean searchAllowed = false;
static final String PREM_SKU = "prem";
private ArrayAdapter<CharSequence> spinnerArrayAdapter;
String name_free[] = { };
String displayName_free[] = { };
String name_premium[] = { };
String displayName_premium[] = {};
/** Called when the activity is first created. */
@SuppressLint("NewApi")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mylayout);
mTitle = mDrawerTitle = getTitle();
mPlanetTitles = getResources().getStringArray(
R.array.fMenu);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.left_drawer);
// set a custom shadow that overlays the main content when the drawer
// opens
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow,
GravityCompat.START);
// set up the drawer's list view with items and click listener
mDrawerList.setAdapter(new ArrayAdapter<String>(this,
R.layout.drawer_list_item, mPlanetTitles));
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
// enable ActionBar app icon to behave as action to toggle nav drawer
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
// ActionBarDrawerToggle ties together the the proper interactions
// between the sliding drawer and the action bar app icon
mDrawerToggle = new ActionBarDrawerToggle(this, /* host Activity */
mDrawerLayout, /* DrawerLayout object */
R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
R.string.drawer_open, /* "open drawer" description for accessibility */
R.string.drawer_close /* "close drawer" description for accessibility */
) {
public void onDrawerClosed(View view) {
getSupportActionBar().setTitle(mTitle);
supportInvalidateOptionsMenu(); // creates call to
// onPrepareOptionsMenu()
}
public void onDrawerOpened(View drawerView) {
getSupportActionBar().setTitle(mDrawerTitle);
supportInvalidateOptionsMenu(); // creates call to
// onPrepareOptionsMenu()
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
if (savedInstanceState == null) {
selectItem(0);
}
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setIndeterminate(false);
mProgressDialog.setMax(100);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
wv = (WebView) findViewById(R.id.webview);
pd = (ProgressBar) findViewById(R.id.pBar);
spLoadFrom = (Spinner) findViewById(R.id.Spinner02);
if (mIsPremium == true) {
spinnerArrayAdapter = new ArrayAdapter<CharSequence>(this,
android.R.layout.simple_spinner_item, displayName_premium);
} else {
spinnerArrayAdapter = new ArrayAdapter<CharSequence>(this,
android.R.layout.simple_spinner_item, displayName_free);
}
spinnerArrayAdapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spLoadFrom.setAdapter(spinnerArrayAdapter);
SpinnerListener spListener = new SpinnerListener();
spLoadFrom.setOnItemSelectedListener(spListener);
String base64EncodedPublicKey = "hidden";
mHelper = new IabHelper(this, base64EncodedPublicKey);
Log.d(TAG, "Starting setup.");
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
@Override
public void onIabSetupFinished(IabResult result) {
Log.d(TAG, "Setup finished.");
if (!result.isSuccess()) {
// Oh noes, there was a problem.
complain("Problem setting up in-app billing: " + result);
return;
}
// Hooray, IAB is fully set up. Now, let's get an inventory of
// stuff we own.
Log.d(TAG, "Setup successful. Querying inventory.");
mHelper.queryInventoryAsync(mGotInventoryListener);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getSupportMenuInflater().inflate(R.menu.menu3, menu);
return super.onCreateOptionsMenu(menu);
}
/* Called whenever we call invalidateOptionsMenu() */
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// If the nav drawer is open, hide action items related to the content
// view
boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(getMenuItem(item))) {
return true;
}
int itemId = item.getItemId();
if (itemId == R.id.search) {
if (searchAllowed == false) {
} else if (itemId == R.id.contact) {
emailme();
} else if (itemId == R.id.rate) {
Uri uri = Uri.parse("market://details?id=" + getPackageName());
Intent myAppLinkToMarket = new Intent(Intent.ACTION_VIEW, uri);
try {
startActivity(myAppLinkToMarket);
} catch (ActivityNotFoundException e) {
Toast.makeText(this, "Unable to find Play Market",
Toast.LENGTH_SHORT).show();
}
}
return super.onOptionsItemSelected(item);
}
public void buyPrem() {
Log.d(TAG,
"Upgrade button clicked; launching purchase flow for upgrade.");
/*
* TODO: for security, generate your payload here for verification. See
* the comments on verifyDeveloperPayload() for more info. Since this is
* a SAMPLE, we just use an empty string, but on a production app you
* should carefully generate this.
*/
String payload = "";
mHelper.launchPurchaseFlow(this, PREM_SKU, 10001,
mPurchaseFinishedListener, payload);
}
@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)) {
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
} else {
Log.d(TAG, "onActivityResult handled by IABUtil.");
}
}
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
@Override
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.d(TAG, "Purchase finished: " + result + ", purchase: "
+ purchase);
if (result.isFailure()) {
complain("Error purchasing: " + result);
// Handle error
return;
}
if (!verifyDeveloperPayload(purchase)) {
complain("Error purchasing. Authenticity verification failed.");
return;
}
Log.d(TAG, "Purchase successful.");
if (purchase.getSku().equals(PREM_SKU)) {
// bought the premium upgrade!
Log.d(TAG, "Purchase is premium upgrade. Congratulating user.");
alert("Thank you for upgrading to premium!");
mIsPremium = true;
mIsUserPremium = true;
searchAllowed = true;
}
}
};
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
@Override
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
Log.d(TAG, "Query inventory finished.");
if (result.isFailure()) {
complain("Failed to query inventory: " + result);
return;
}
/*if (inventory.hasPurchase(PREM_SKU)) {
mHelper.consumeAsync(inventory.getPurchase(PREM_SKU), null);
}*/
Log.d(TAG, "Query inventory was successful.");
Purchase premiumPurchase = inventory.getPurchase(PREM_SKU);
mIsPremium = (premiumPurchase != null && verifyDeveloperPayload(premiumPurchase));
Log.d(TAG, "User is " + (mIsPremium ? "PREMIUM" : "NOT PREMIUM"));
if (mIsPremium) {
searchAllowed = true;
mIsUserPremium = true;
Log.d(TAG, "Should be premium by now...");
}
Log.d(TAG, "Initial inventory query finished; enabling main UI.");
}
};
boolean verifyDeveloperPayload(Purchase p) {
String payload = p.getDeveloperPayload();
/*
* TODO: verify that the developer payload of the purchase is correct.
* It will be the same one that you sent when initiating the purchase.
*
* WARNING: Locally generating a random string when starting a purchase
* and verifying it here might seem like a good approach, but this will
* fail in the case where the user purchases an item on one device and
* then uses your app on a different device, because on the other device
* you will not have access to the random string you originally
* generated.
*
* So a good developer payload has these characteristics:
*
* 1. If two different users purchase an item, the payload is different
* between them, so that one user's purchase can't be replayed to
* another user.
*
* 2. The payload must be such that you can verify it even when the app
* wasn't the one who initiated the purchase flow (so that items
* purchased by the user on one device work on other devices owned by
* the user).
*
* Using your own server to store and verify developer payloads across
* app installations is recommended.
*/
return true;
}
/*public void consumeItem() {
mHelper.queryInventoryAsync(mReceivedInventoryListener);
}*/
IabHelper.QueryInventoryFinishedListener mReceivedInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
@Override
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
if (result.isFailure()) {
// Handle failure
} else {
searchAllowed = false;
//mHelper.consumeAsync(inventory.getPurchase(PREM_SKU),
// mConsumeFinishedListener);
}
}
};
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
@Override
public void onConsumeFinished(Purchase purchase, IabResult result) {
if (result.isSuccess()) {
} else {
// handle error
}
}
};
@Override
public void onDestroy() {
super.onDestroy();
if (mHelper != null)
mHelper.dispose();
mHelper = null;
}
void complain(String message) {
Log.e(TAG, "**** TrivialDrive Error: " + message);
alert("Error: " + message);
}
void alert(String message) {
AlertDialog.Builder bld = new AlertDialog.Builder(this);
bld.setMessage(message);
bld.setNeutralButton("OK", null);
Log.d(TAG, "Showing alert dialog: " + message);
bld.create().show();
}
private android.view.MenuItem getMenuItem(final MenuItem item) {
return new android.view.MenuItem() {
@Override
public int getItemId() {
return item.getItemId();
}
public boolean isEnabled() {
return true;
}
@Override
public boolean collapseActionView() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean expandActionView() {
// TODO Auto-generated method stub
return false;
}
@Override
public ActionProvider getActionProvider() {
// TODO Auto-generated method stub
return null;
}
@Override
public View getActionView() {
// TODO Auto-generated method stub
return null;
}
@Override
public char getAlphabeticShortcut() {
// TODO Auto-generated method stub
return 0;
}
@Override
public int getGroupId() {
// TODO Auto-generated method stub
return 0;
}
@Override
public Drawable getIcon() {
// TODO Auto-generated method stub
return null;
}
@Override
public Intent getIntent() {
// TODO Auto-generated method stub
return null;
}
@Override
public ContextMenuInfo getMenuInfo() {
// TODO Auto-generated method stub
return null;
}
@Override
public char getNumericShortcut() {
// TODO Auto-generated method stub
return 0;
}
@Override
public int getOrder() {
// TODO Auto-generated method stub
return 0;
}
@Override
public SubMenu getSubMenu() {
// TODO Auto-generated method stub
return null;
}
@Override
public CharSequence getTitle() {
// TODO Auto-generated method stub
return null;
}
@Override
public CharSequence getTitleCondensed() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean hasSubMenu() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isActionViewExpanded() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isCheckable() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isChecked() {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isVisible() {
// TODO Auto-generated method stub
return false;
}
@Override
public android.view.MenuItem setActionProvider(
ActionProvider actionProvider) {
// TODO Auto-generated method stub
return null;
}
@Override
public android.view.MenuItem setActionView(View view) {
// TODO Auto-generated method stub
return null;
}
@Override
public android.view.MenuItem setActionView(int resId) {
// TODO Auto-generated method stub
return null;
}
@Override
public android.view.MenuItem setAlphabeticShortcut(char alphaChar) {
// TODO Auto-generated method stub
return null;
}
@Override
public android.view.MenuItem setCheckable(boolean checkable) {
// TODO Auto-generated method stub
return null;
}
@Override
public android.view.MenuItem setChecked(boolean checked) {
// TODO Auto-generated method stub
return null;
}
@Override
public android.view.MenuItem setEnabled(boolean enabled) {
// TODO Auto-generated method stub
return null;
}
@Override
public android.view.MenuItem setIcon(Drawable icon) {
// TODO Auto-generated method stub
return null;
}
@Override
public android.view.MenuItem setIcon(int iconRes) {
// TODO Auto-generated method stub
return null;
}
@Override
public android.view.MenuItem setIntent(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public android.view.MenuItem setNumericShortcut(char numericChar) {
// TODO Auto-generated method stub
return null;
}
@Override
public android.view.MenuItem setOnActionExpandListener(
OnActionExpandListener listener) {
// TODO Auto-generated method stub
return null;
}
@Override
public android.view.MenuItem setOnMenuItemClickListener(
OnMenuItemClickListener menuItemClickListener) {
// TODO Auto-generated method stub
return null;
}
@Override
public android.view.MenuItem setShortcut(char numericChar,
char alphaChar) {
// TODO Auto-generated method stub
return null;
}
@Override
public void setShowAsAction(int actionEnum) {
// TODO Auto-generated method stub
}
@Override
public android.view.MenuItem setShowAsActionFlags(int actionEnum) {
// TODO Auto-generated method stub
return null;
}
@Override
public android.view.MenuItem setTitle(CharSequence title) {
// TODO Auto-generated method stub
return null;
}
@Override
public android.view.MenuItem setTitle(int title) {
// TODO Auto-generated method stub
return null;
}
@Override
public android.view.MenuItem setTitleCondensed(CharSequence title) {
// TODO Auto-generated method stub
return null;
}
@Override
public android.view.MenuItem setVisible(boolean visible) {
// TODO Auto-generated method stub
return null;
}
};
}
private class DrawerItemClickListener implements
ListView.OnItemClickListener {
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
switch (position) {
case 0:
mDrawerLayout.closeDrawer(mDrawerList);
break;
case 1:
Intent c1 = new Intent(getBaseContext(), 1.class);
startActivity(c1);
break;
case 2:
Intent c2 = new Intent(getBaseContext(), 5.class);
startActivity(c2);
break;
case 3:
Intent c3 = new Intent(getBaseContext(), 3.class);
startActivity(c3);
break;
case 4:
Intent c4 = new Intent(getBaseContext(), 4.class);
startActivity(c4);
break;
default:
}
}
}
public void selectItem(int position) {
switch (position) {
case 0:
break;
case 1:
setContentView(R.layout.1);
break;
case 2:
setContentView(R.layout.2);
break;
case 3:
setContentView(R.layout.3);
break;
case 4:
setContentView(R.layout.4);
break;
default:
}
}
@Override
public void setTitle(CharSequence title) {
mTitle = title;
getSupportActionBar().setTitle(mTitle);
}
/**
* When using the ActionBarDrawerToggle, you must call it during
* onPostCreate() and onConfigurationChanged()...
*/
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Pass any configuration change to the drawer toggls
mDrawerToggle.onConfigurationChanged(newConfig);
}
}
推荐答案
关闭应用程序,删除所有变量,包括mIsPremium。
By closing your application you delete all variables, including mIsPremium.
因此,您需要在某处保存mIsPremium的值,并在再次打开应用程序时加载它。
Therefor you need to save the value of mIsPremium somewhere and load it when you again open the application.
我建议您使用。
您可以这样做:
在 IabHelper.OnIabPurchaseFinishedListener 您需要保存您的偏好:
In the IabHelper.OnIabPurchaseFinishedListener you need to save your preference:
if (purchase.getSku().equals(PREM_SKU)) {
// bought the premium upgrade!
Log.d(TAG, "Purchase is premium upgrade. Congratulating user.");
alert("Thank you for upgrading to premium!");
mIsPremium = true;
mIsUserPremium = true;
searchAllowed = true;
SharedPreferences prefs = this.getBaseContext().getSharedPreferences(
"com.example.yourapp", 0);
prefs.edit().putBoolean("premium", true).apply;
}
在此您将高级状态true保存到共享首选项premium用户成功购买保费后。
Here you save the premium state "true" to the shared preference "premium" after the user has sucessfully purchased premium.
在 onCreate()方法中,您需要加载首选项:
In the onCreate() method you need to load the preference:
SharedPreferences prefs = this.getBaseContext().getSharedPreferences(
"com.example.yourapp", 0);
mIsPremium = prefs.getBoolean("premium", false);
在这里加载首选项premium,如果此偏好尚不存在,则需要 falseals默认值。
Here you load the preference "premium", if this prefernce does not exist yet, it will take "false" als default value.
这篇关于应用内结算:广告资源不正确;让用户再次购买的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!