Il semble qu'il soit assez compliqué d'implémenter la facturation via l'application dans une application Android. Comment pourrais-je faire cela? L'exemple d'application du SDK n'a qu'une seule activité, ce qui simplifie de manière excessive pour une application comme la mienne qui a plusieurs activités.
Eh bien, je vais essayer d'expliquer ce que j'ai vécu. Je ne me considère pas comme un expert en la matière, mais je me suis cassé la tête plusieurs jours.
Pour commencer, j'ai eu un très mauvais moment à essayer de comprendre le flux de travail de l'exemple et de l'application. J'ai pensé qu'il valait mieux commencer par un exemple simple, mais il est très difficile de séparer le code en petits morceaux et de ne pas savoir si vous cassez quelque chose. Je vais vous dire ce que j'ai et ce que j'ai changé de l'exemple pour le faire fonctionner.
J'ai une seule activité d'où proviennent tous mes achats. Ça s'appelle Pro.
Tout d'abord, vous devez mettre à jour la variable base64EncodedPublicKey dans votre classe de sécurité avec votre clé de développeur Market publique ou vous verrez une belle exception.
Eh bien, je lie mon activité à mon BillingService comme ceci:
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();
}
De cette façon, tous les achats parlent à ce service, qui enverra ensuite les demandes JSON au marché. Vous pourriez penser que les achats sont effectués au même instant mais non. Vous envoyez la demande et l'achat peut arriver quelques minutes ou heures plus tard. Je pense que cela est principalement dû à la surcharge du serveur et à l'approbation des cartes de crédit.
Ensuite, j'ai un ListView avec mes articles, et j'ouvre un AlertDialog sur chacun d'eux, les invitant à acheter l'article. Quand ils cliquent sur un élément, je fais ceci:
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();
}
}
}
D'accord, vous devriez voir que le marché s'ouvre et que l'utilisateur termine ou annule l'achat.
Ce qui est alors important est mon PurChaseObserver, qui gère tous les événements que le marché envoie. Ceci est une version dépouillée de celui-ci, mais vous devriez comprendre (voir mes commentaires dans le code):
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
}
}
}
Et je pense que vous ne devriez pas avoir besoin de modifier quoi que ce soit d'autre. Le reste du code "fonctionne". Vous pouvez essayer d'utiliser l'exemple de SKU dans vos propres articles "Android.test.purchased". Jusqu'à présent, j'ai testé cela et cela fonctionne, mais j'ai encore besoin de couvrir tout comme l'état remboursé. Dans ce cas, je laisse l'utilisateur conserver les fonctionnalités mais je veux m'assurer que cela fonctionne parfaitement avant de le modifier.
J'espère que cela vous aide, vous et les autres.
V3: voici un tutoriel pour un démarrage rapide .. Il utilise les classes d'assistance de l'exemple google (Trivial Drive) ... Bon comme premier "Hello Billing" ..
Pour la facturation in-app v3, j'ai trouvé cela très utile.
http://blog.blundellapps.com/simple-inapp-billing-payment-v3/
Il y a un exemple complet de Android In-App Billing v3 étape par étape est donné ici avec capture d'écran. Veuillez consulter le didacticiel: Android In-App Billing v3 utilisant ServiceConnection Class
J'espère que cela vous aidera.
Pour plus de précisions, suivez ce didacticiel: Implémentation de la facturation via l'application dans l'API version
Étapes à suivre pour intégrer la bibliothèque de facturation intégrée à notre projet
Mettez à jour votre fichier AndroidManifest.xml.
Créez un ServiceConnection et liez-le à IInAppBillingService.
Envoyez des demandes de facturation via l'application à partir de votre application à IInAppBillingService.
Gérez les réponses de facturation via l'application depuis Google Play.
Mettre à jour AndroidManifest.xml
<uses-permission Android:name="com.Android.vending.BILLING" />
Ajoutez les autorisations dans le fichier Manifest.xml
Créez votre application. Vous devriez voir un fichier généré nommé IInAppBillingService.Java dans le répertoire/gen de votre projet.
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'
}
InAppPurchaseActivity.Java et activity_in_app_purchase.xml
C'est là que nos utilisateurs d'applications auront la possibilité de faire des achats via l'application. Dans le fichier de mise en page, nous donnerons à l'utilisateur la possibilité de faire des achats dans différentes dénominations.
InAppPurchaseActivity.Java
Remarque: les méthodes getAllUserPurchase () et itemPurchaseAvailability () doivent être appelées dans le thread non UI pour éviter le plantage de l'application.
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);
}
}
}
Créer un répertoire de packages d'assistance
Créez un nouveau dossier de packages et nommez-le helpers. À l'intérieur du package, créez un nouveau fichier 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();
}
}
Test de la facturation via l'application
Erreurs que vous pourriez rencontrer lors des tests d'achat intégrés
l'article que vous avez demandé n'est pas disponible à l'achat
Solution - selon AndreiBogdan dans Stackoverflow ,
Tout crédit revient à Inducesmile pour son tutoriel
Le blog des développeurs Android recommande également un cours de formation sur la vente de produits intégrés à l'application. Pour voir une implémentation complète et apprendre à tester l'application, veuillez consulter ce tutoriel: Vente de produits intégrés à l'application
Si vous souhaitez utiliser une bibliothèque facile à publier sur Google Play et l'Appstore Amazon, vous pouvez choisir RoboBillingLibrary . Il résume les détails des deux dans une bibliothèque facile à utiliser. Des instructions détaillées sont sur la page Github.
D'accord, c'est une de ces choses qui n'a pas beaucoup de documentation disponible en ligne, donc je vais faire de mon mieux pour tout expliquer étape par étape. Tiré de mon article de blog, qui est une version plus détaillée de cela (avec des captures d'écran), ici sur The Millibit . Sans plus tarder,
Première étape: Autorisations C'est l'étape la plus simple. Accédez à votre fichier manifest.xml et ajoutez la ligne suivante sous votre balise:
<uses-permission Android:name="com.Android.vending.BILLING" />
Cela donnera à votre application les autorisations d'accès à la facturation via l'application. Si vous ciblez des versions supérieures à l'API 22, vous devrez vous assurer que cette autorisation est accordée au moment de l'exécution.
Deuxième étape: Play Console Maintenant, vous devez télécharger votre application sur la console Google Play. Nous ne publions pas encore notre application au public (ne vous inquiétez pas), nous la téléchargeons simplement dans la section BETA RELEASE, qui nous permettra de tester les achats intégrés. La raison pour laquelle nous devons le faire est que Google doit télécharger une version de votre APK pour que les processus de facturation fonctionnent réellement.
Accédez à https://play.google.com/apps/publish/
Créer l'application
Suivez les étapes pour configurer votre application
Accédez aux versions des applications
Accédez à la version bêta
Créez un fichier APK de votre application dans Android studio et téléchargez-le dans la production bêta de la console Play
(avant de publier, assurez-vous que vous avez déjà rempli la fiche Play Store, la classification du contenu et les prix et la distribution)
Troisième étape: Projet d'installation D'accord, c'est la partie où vous devez copier et coller un tas de fichiers.
Tout d'abord, prenez le fichier this , téléchargez-le et placez-le sous src/main
Il devrait se construire dans un dossier Ensuite, saisissez dans son intégralité dossier util et collez-le dans src/Java folder.
Reconstruisez ensuite votre projet pour résoudre les erreurs. Le dossier Util contient les classes suivantes:
Quatrième étape: Créer des produits
Créer un produit géré
Cliquez sur enregistrer et créez un "modèle de tarification"
Ici, vous sélectionnez le prix de ce produit. Vous pouvez choisir le prix pour différents pays, ou le faire ajuster automatiquement si vous sélectionnez simplement tous les pays sous votre prix:
Enfin, notez l'ID de votre produit. Nous utiliserons cet ID dans les prochaines étapes.
Rendez-vous sur "Services et API" et récupérez votre Base64EncodedString. Copiez-collez-le dans un bloc-notes quelque part pour y avoir accès. Ne partagez cela avec personne, il pourra faire des choses malveillantes avec lui.
Cinquième étape: Enfin! Nous pouvons commencer à coder: nous allons d'abord nous lier à la bibliothèque de facturation intégrée à l'application, puis rechercher ce que l'utilisateur a/n'a pas acheté. Ensuite, nous achèterons le produit que nous avons mis en place plus tôt.
Tout d'abord, importez tout ce que nous avons configuré précédemment:
import util.*;
Nous allons maintenant utiliser un objet IabHelper appelé mHelper, et nous ferons tout avec cela.
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();
}
}
}
});
D'accord, permettez-moi de vous expliquer ce qui se passe ici. Fondamentalement, nous appelons "startSetup" pour initialiser notre "IabHelper". Si la configuration réussit, nous demandons quels achats l'utilisateur a déjà et stockons les réponses dans mGotInventoryListener
, que nous coderons ensuite:
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");
}
}
}
};
Le code ci-dessus est assez explicite. Fondamentalement, il vérifie simplement quels achats l'utilisateur a déjà. Maintenant que nous savons si l'utilisateur a déjà acheté notre produit, nous savons s'il faut ou non lui demander d'acheter notre article! S'ils n'ont jamais acheté notre produit auparavant, commençons une demande d'achat:
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;
}
}
};
Ici, nous achetons l'article (avec l'ID que nous avons généré dans la console de jeu plus tôt) avec les éléments suivants:
mHelper.launchPurchaseFlow(this, "premium_version", 9, mPurchaseFinishedListener, "SECURITYSTRING"); //Making purchase request and attaching listener
Notez que nous avons passé mPurchaseFinishedListener
dans les paramètres. Cela signifie que le résultat de l'achat sera retourné à cet auditeur. Ensuite, nous vérifions simplement si l'achat est nul, et sinon, accordons à l'utilisateur la fonctionnalité qu'il a achetée.
Ne laissez pas les auditeurs fuir! Nous devons les détruire lorsque l'application détruit.
@Override
public void onDestroy() {
super.onDestroy();
if (mHelper != null)
try {
mHelper.dispose();
mHelper = null;
} catch (IabHelper.IabAsyncInProgressException e) {
e.printStackTrace();
}
}
Enfin, si vous souhaitez consommer votre achat et le rendre à nouveau disponible à l'achat, vous pouvez le faire facilement. Un exemple de cela est si un utilisateur a acheté de l'essence pour une voiture virtuelle et qu'il s'est épuisé. Ils doivent acheter à nouveau le même produit, et vous pouvez le rendre disponible pour un deuxième achat en le consommant:
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();
}
}
C'est ça! Vous pouvez maintenant commencer à gagner de l'argent. C’est vraiment aussi simple que cela!
Encore une fois, si vous voulez une version plus détaillée de ce tutoriel, avec des captures d'écran et des images, visitez le article d'origine ici . Faites-moi savoir dans les commentaires si vous avez d'autres questions.