web-dev-qa-db-fra.com

Comment implémenter la facturation via l'application dans une application Android?

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.

69
SZH

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.

41
sfratini

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" ..

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

12

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

9
unlimit

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

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 le fichier build.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 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

  1. Créez un compte Google+ (n'utilisez pas le compte principal)
  2. Ajoutez les utilisateurs qui testeront l'application dans votre groupe ou 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 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

6
SkyWalker

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.

5
Christopher Perry

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.

  1. Accédez à https://play.google.com/apps/publish/

  2. Créer l'application

  3. Suivez les étapes pour configurer votre application

  4. Accédez aux versions des applications

  5. Accédez à la version bêta

  6. 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)

  1. Appuyez sur le bouton magique (publier!)

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/mainIl 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:

  • 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é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:

  1. Assurez-vous que le produit intégré à l'application est activé et lié à la bonne application 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

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.

4
Ruchir Baronia