Comment implémenter la facturation In-App dans une application Android?


Il semble qu'il soit assez compliqué d'implémenter la facturation In-App dans une application Android. Comment pourrais-je faire cela? L'exemple d'application du SDK n'a qu'une seule activité, ce qui la simplifie un peu plus pour une application comme la mienne qui a plusieurs activités.

Author: Tunaki, 2012-01-05

6 answers

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 la demande. J'ai pensé qu'il devrait être préférable de commencer par un exemple simple, mais il est beaucoup plus difficile de séparer le code en petits morceaux et de ne pas savoir si vous cassez quoi que ce soit. 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ù viennent tous mes achats. Il est appelé Pro.

Tout d'abord, vous devez mettre à jour la variable base64EncodedPublicKey dans votre classe de sécurité avec votre clé de développeur public Market 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 sur la même instant mais non. Vous envoyez la demande et l'achat peut venir quelques minutes ou quelques heures plus tard. Je pense que c'est principalement à 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 obtenir le point (voir mes commentaires à travers 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 crois que vous ne devriez pas avoir besoin de modifier autre chose. Le reste du code "fonctionne". Vous pouvez essayer d'utiliser l'échantillon SKU au début dans vos propres articles "android.test.acheter". Jusqu'à présent, j'ai testé cela et cela fonctionne, mais je dois encore tout couvrir comme l'état remboursé. Dans ce cas, je laisse l'utilisateur conserver les fonctionnalités mais je veux m'assurer qu'il fonctionne parfaitement avant de portées il.

J'espère que cela vous aidera, vous et les autres.

 36
Author: sfratini, 2012-02-22 08:53:41

V3: voici un tutoriel pour un démarrage rapide.. Il utilise les classes d'assistance de l'exemple Google (Trivial Drive) ... Bon comme premier "Bonjour facturation"..

Http://www.techotopia.com/index.php/Integrating_Google_Play_In-app_Billing_into_an_Android_Application_%E2%80%93_A_Tutorial

 11
Author: Alexander Pfeif, 2013-07-26 14:27:21

Pour la facturation in-app v3, j'ai trouvé cela vraiment utile.
http://blog.blundellapps.com/simple-inapp-billing-payment-v3/

 8
Author: unlimit, 2017-08-01 08:39:45

Si vous souhaitez utiliser une bibliothèque facile à publier sur Google Play et Amazon Appstore, vous pouvez utiliser 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.

 4
Author: Christopher Perry, 2016-11-24 18:43:29

Il y a un exemple complet de Android In-App Billing v3 étape par étape est donnée ici avec capture d'écran. Veuillez consulter le tutoriel: Android In-App Billing v3 en utilisant la classe ServiceConnection

J'espère que cela vous aidera.

Pour plus de précisions, parcourez ce tutoriel: Implémentation de la facturation In-app dans l'API Version 3

Étapes à suivre pour intégrer la bibliothèque de facturation In-app dans notre projet

Mettez à jour votre AndroidManifest.XML fichier.

Créez une ServiceConnection et liez-la à IInAppBillingService.

Envoyez des demandes de facturation intégrées depuis votre application à IInAppBillingService.

Gérer les réponses de facturation dans l'application de Google Play.

Mise à jour AndroidManifest.xml

<uses-permission android:name="com.android.vending.BILLING" />

Ajoutez les autorisations dans le manifeste.fichier xml

Ajout du fichier AIDL à votre projet

Créez votre application. Vous devriez voir un fichier généré nommé IInAppBillingService.java dans le répertoire / gen de votre projet.

Mettre à jour les dépendances dans la construction.fichier gradle

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 les utilisateurs de notre application auront la possibilité de faire des achats intégrés. Dans le fichier de mise en page, nous donnerons à l'utilisateur la possibilité de faire des achats dans différents dénomination.

InAppPurchaseActivity.java

Remarque: Les méthodes getAllUserPurchase() et itemPurchaseAvailability() doivent être appelées dans un 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 paquets d'aide

Créez un nouveau dossier de package et nommez-le helpers. Dans le package, créez un nouvel assistant de fichier java.Java.

Aide.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();
    }
}

Tester l'achat de Facturation dans l'application

  1. Créer un Google+ compte (ne pas utiliser le compte principal)
  2. Ajoutez les utilisateurs qui testeront l'application dans votre groupe ou votre communauté.

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 le crédit va à Inducesmile son tutoriel

Android Developer Blog recommande également un cours de formation sur La vente Dans l'application des Produits. Pour voir une implémentation complète et apprendre à tester l'application, veuillez consulter ce tutoriel: Vendre des produits intégrés à l'application

 4
Author: SkyWalker, 2017-05-23 12:18:14

Ok 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 ceci (avec des captures d'écran), ici sur le Millibit. Sans plus tarder,

Première Étape: Autorisations C'est le moyen le plus simple. Accédez à votre manifeste.fichier XML et ajoutez la ligne suivante sous votre balise:

<uses-permission android:name="com.android.vending.BILLING" />

Cela donnera votre app les autorisations pour accéder à la facturation In-App. Si vous ciblez des versions au-dessus de l'API 22, vous devrez vous assurer que cette autorisation est accordée lors de l'exécution.

Deuxième étape: Console de lecture Vous devez maintenant 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 VERSION BÊTA, ce qui nous permettra de tester les achats intégrés. La raison pour laquelle nous devons le faire est que Google a besoin d'en avoir version de votre APK téléchargée pour que les processus de facturation fonctionnent réellement.

  1. Aller à https://play.google.com/apps/publish/

  2. Créer l'Application

  3. Suivez les étapes pour configurer votre application

  4. Accéder à l'Application des Communiqués de

  5. Accédez à la Bêta

  6. Créez un APK de votre application dans Android studio et téléchargez-le dans la production bêta du jeu Console

(avant de publier, assurez-vous que vous avez déjà rempli la Liste du Magasin, la Note du Contenu, les Prix et la distribution)

  1. Appuyez sur le bouton magique (publier!)

Troisième étape: Projet d'installation Ok c'est la partie où vous devez copier et coller un tas de fichiers.

Tout d'abord, prenez ce fichier, téléchargez-le et placez-le sous src/main Il devrait se construire dans un dossier Ensuite, prenez tout ce util dossier et collez-le dans src/java folder. Puis reconstruisez votre projet pour résoudre les erreurs. Le Dossier Util Contient Les Classes Suivantes:

  • IabBroadcastReceiver
  • IabException
  • IabHelper
  • IabResult
  • Inventaire
  • Achat
  • Sécurité
  • SkuDetails

Quatrième étape: Créer des produits

  1. Créer un produit géré

  2. Cliquez sur Enregistrer et créer un "modèle de tarification"

Ici, vous allez sélectionner 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:

  1. Assurez-vous que le produit intégré à l'application est activé et lié à l'application correcte dans la console une dernière fois.

Enfin, notez l'ID de votre produit. Nous utiliserons cet ID dans les prochaines étapes.

  1. Obtenez votre Base64EncodedString

Dirigez-vous vers "Services & APIs" et récupérez votre Base64EncodedString. Copiez et collez ceci dans un bloc-notes quelque part afin que vous y ayez accès. Ne partagez cela avec personne, ils pourront faire des choses malveillantes avec.

Cinquième étape: Enfin! On peut commencer à coder: Nous allons d'abord nous lier à la bibliothèque de facturation intégrée à l'application et interroger ce que l'utilisateur a/n'a pas acheté. Ensuite, nous achèterons le produit que nous avons mis en place plus tôt.

Premier, importez tout ce que nous avons mis en place plus tôt:

import util.*;

Maintenant, nous allons 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, laissez-moi expliquer ce qui se passe ici. Fondamentalement, nous appelons " startSetup "pour initialiser notre"IabHelper". Si la configuration réussit, nous interrogeons les achats que 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, c'est juste vérifie 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 leur 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 ce qui suit:

 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, attribuons à 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, le rendre à nouveau disponible à l'achat, vous pouvez le faire facilement. Un exemple de ceci est si un utilisateur a acheté de l'essence pour une voiture virtuelle et qu'elle s'est épuisée. Ils doivent acheter le même produit à nouveau, et vous pouvez le faire 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 tout! 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 post original ici . Faites - moi savoir dans les commentaires si vous avez d'autres questions.

 1
Author: Ruchir Baronia, 2018-07-13 22:45:14