Autore Topic: [medio] In-App Billing per ricevere donazioni od attivare funzionalità extra  (Letto 19109 volte)

Offline denper

  • Utente normale
  • ***
  • Post: 290
  • Respect: +60
    • Mostra profilo
    • Anddenper
  • Dispositivo Android:
    Moto G
  • Play Store ID:
    denper
  • Sistema operativo:
    Window 7, Windows XP
Livello di difficoltà: medio
Target SDK: 4 o superiore
Min SDK: 4
Link al file compresso del progetto eclipse: file in allegato
Prerequisiti:  Applicazione Android Market 2.3.4 (o superiore) , Libreria AndroidBillingLibrary scaricabile da qui  https://github.com/robotmedia/AndroidBillingLibrary


Per semplificare l’utilizzo delle funzionalità di In-App Billing di Google utilizzare la libreria AndroidBillingLibrary. Questa libreria permette di astrarre la parte di back end  e comunicazione tra l’applicazione e il market, rendendo la stesura del codice molto più semplice.

Detto questo cominciamo!

1. Preparare la vostra applicazione all'utilizzo della funzionalità di In-App Billing

Prima di tutto è necessario impostare la vostra applicazione per poter includere dei prodotti in-app. Perché la vostra app sia in grado di gestire prodotti in-app dovete aggiungere nel file AndroidManifest.xml il seguente permesso.

Codice (XML): [Seleziona]
<uses-permission android:name="com.android.vending.BILLING" />
Senza questo permesso nel momento in cui provate ad aggiungere per la vostra app un prodotto in-app nel market riceverete il seguente errore:

Non è possibile aggiungere nuovi prodotti in-app perché la versione corrente dell'applicazione non utilizza l'autorizzazione FATTURAZIONE.

Ovviamente se avete già pubblicato la vostra applicazione nel market vi chiederete: come faccio ad aggiungere un prodotto in-app per la mia app già pubblicata che non ha ancora il premesso per la fatturazione all’interno del file AndroidManifest.xml? Come faccio a fare delle prove? Beh, aggiungete alla vostra app il permesso in questione, aggiornate il version code, fate l’upload del vostro apk e lasciatelo in versione Draft (non attivarlo).  Ora se andate sulla console e provate ad aggiungere alla vostra app un prodotto in-app, vedrete che potrete farlo.
Una precisazione durante la creazione di un prodotto in-app. Un prodotto in-app può essere di due tipi Gestito in base ad account utente o Non gestito. Se il prodotto è gestito significa che il market tiene traccia se un utente ha già acquistato o meno il prodotto e permette l’acquisto una sola volta; non gestito al contrario può essere acquistato più volte e non crea nessuna correlazione tra utente e prodotto acquistato. Altra cosa importante: se il prodotto è gestito è possibile sapere sempre quali prodotti un utente ha acquistato, ottenere quindi una lista dei prodotti acquistati e del loro stato in base all’utente. Questo, come vedremo in seguito, permette di gestire un corretto funzionamento dell’app anche quando questa viene aggiornata o reinstallata.

Altra cosa da aggiungere al file AndroidManifest.xml sono il seguenti service e receiver:

Codice (XML): [Seleziona]
<!-- Robotmedia AndroidBillingLibrary -->
        <service android:name="net.robotmedia.billing.BillingService" />

        <receiver android:name="net.robotmedia.billing.BillingReceiver" >
            <intent-filter >
                <action android:name="com.android.vending.billing.IN_APP_NOTIFY" />
                <action android:name="com.android.vending.billing.RESPONSE_CODE" />
                <action android:name="com.android.vending.billing.PURCHASE_STATE_CHANGED" />
            </intent-filter>
        </receiver>

2. Aggiungiamo un’po’ di codice. Di seguito vengono illustrate le classi principali utilizzate per la gestione dei prodotti in-app

Inizializziamo il servizio di In-app Billing. Questa inizializzazione è meglio farla a livello di Application. Creiamo perciò la nostra classe InAppBillingApplication.java che estende android.app.Application.

Codice (Java): [Seleziona]
package com.denper.example;

import net.robotmedia.billing.BillingController;
import android.app.Application;
import android.content.Context;

public class InAppBillingApplication extends Application {

        private static Context context;
        public static final String TAG = "InAppBillingApplication";

        @Override
        public void onCreate() {
                super.onCreate();
                InAppBillingApplication.context = this;

                BillingController.setDebug(true);
                BillingController.setConfiguration(new BillingController.IConfiguration() {

                        @Override
                        public byte[] getObfuscationSalt() {
                                return new byte[] { 34, -91, -100, -43, 64, -53, 121, -100, -106, -51, -57, 37, 116, 15, 20, 80, 67, 110, 99, -10 };
                        }

                        @Override
                        public String getPublicKey() {
                                return "Inserire Chiave pubblica. Console Android Market-> Modifica profilo-> Chiave pubblica";
                        }
                });

        }

        public static Context getStaticContext() {
                return context;
        }

}


Inserire nel metodo getPublicKey() la vostra chiave pubblica disponibile nella vostra console di sviluppo. Modificate anche il Salt per offuscare le informazioni durante la comunicazione. Per il momento lasciate il debug attivo per vedere nel log le richieste e le risposte effettuate e ricevute dal server. Ricordatevi al momento del rilascio della vostra app di disabilitare il debug.

Creiamo una classe DonationEntry.java  per la gestione delle donazioni.

Codice (Java): [Seleziona]
package com.denper.example;

import java.util.ArrayList;
import java.util.List;

public class DonationEntry {

        /**
         * Each product in the catalog is either MANAGED or UNMANAGED. MANAGED means
         * that the product can be purchased only once per user (such as a new level
         * in a game). The purchase is remembered by Android Market and can be
         * restored if this application is uninstalled and then re-installed.
         * UNMANAGED is used for products that can be used up and purchased multiple
         * times (such as poker chips). It is up to the application to keep track of
         * UNMANAGED products for the user.
         */

        public enum Managed {
                MANAGED, UNMANAGED
        }

        public String sku;
        public int nameId;
        public Managed managed;

        public DonationEntry(String sku, int nameId, Managed managed) {
                this.sku = sku;
                this.nameId = nameId;
                this.managed = managed;
        }

        public static List<String> getDonatinsList() {
                List<String> list = new ArrayList<String>();
                for (DonationEntry element : DONATIONS_LIST) {
                        list.add(InAppBillingApplication.getStaticContext().getString(element.nameId));
                }
                return list;

        }

        /** An array of product list entries for the products that can be purchased. */
        public static final DonationEntry[] DONATIONS_LIST = new DonationEntry[] { new DonationEntry("donate.dummy", R.string.donate_dummy, Managed.UNMANAGED),
                        new DonationEntry("donate.small", R.string.donate_small, Managed.MANAGED), new DonationEntry("donate.medium", R.string.donate_medium, Managed.MANAGED),
                        new DonationEntry("donate.large", R.string.donate_large, Managed.MANAGED), new DonationEntry("android.test.purchased", R.string.android_test_purchased, Managed.UNMANAGED),
                        new DonationEntry("android.test.canceled", R.string.android_test_canceled, Managed.UNMANAGED),
                        new DonationEntry("android.test.refunded", R.string.android_test_refunded, Managed.UNMANAGED),
                        new DonationEntry("android.test.item_unavailable", R.string.android_test_item_unavailable, Managed.UNMANAGED) };

}


Quando si crea una DonationEntry tramite il costruttore

Codice (Java): [Seleziona]
new DonationEntry("donate.small", R.string.donate_small, Managed.MANAGED)

il primo parametro "donate.small" corrispondere all’ ID prodotto in-app creato nel Market.



Gli ultimi 4 prodotti con id "android.test.*" sono prodotti riservati utili ai fini di test. Maggiori informazioni sono disponibili qui Testing In-app Billing | Android Developers.

Ora scriviamo la classe principale DonationManager.java per la gestione dei prodotti in-app.

Codice (Java): [Seleziona]
package com.denper.example;

import java.util.ArrayList;
import java.util.List;

import net.robotmedia.billing.BillingController;
import net.robotmedia.billing.BillingController.BillingStatus;
import net.robotmedia.billing.BillingRequest.ResponseCode;
import net.robotmedia.billing.helper.AbstractBillingObserver;
import net.robotmedia.billing.model.Transaction;
import net.robotmedia.billing.model.Transaction.PurchaseState;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.AdapterView.OnItemSelectedListener;

public class DonationManager {

        private static final int DIALOG_DONATE_ID = 1;
        private static final int DIALOG_BILLING_NOT_SUPPORTED_ID = 2;

        private static Activity mContext;
        private static AbstractBillingObserver mBillingObserver;
        private static DonationListAdapter mDonationListAdapter;

        private static DonationManagerListener mListener;

        private static Dialog donateDialog;
        private static Dialog billingNotSupportedDialog;
        private static String mSku;

        private static boolean hasDonate = false;

        public interface DonationManagerListener {
                public void onHasDonate(boolean donate);
        }

        static private void setupInAppBilling() {
                mBillingObserver = new AbstractBillingObserver(mContext) {

                        @Override
                        public void onBillingChecked(boolean supported) {

                                if (supported) {
                                        restoreTransactions();
                                } else {
                                        showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
                                }

                        }

                        @Override
                        public void onPurchaseStateChanged(String itemId, PurchaseState state) {
                                Log.i(InAppBillingApplication.TAG, "onPurchaseStateChanged() itemId: " + itemId);
                                updateMadeDonations();
                        }

                        @Override
                        public void onRequestPurchaseResponse(String itemId, ResponseCode response) {
                        }
                };

                mDonationListAdapter = new DonationListAdapter(mContext, DonationEntry.DONATIONS_LIST);
        }

        /**
         * Restores previous transactions, if any. This happens if the application
         * has just been installed or the user wiped data. We do not want to do this
         * on every startup, rather, we want to do only when the database needs to
         * be initialized.
         */

        private static void restoreTransactions() {
                if (!mBillingObserver.isTransactionsRestored()) {
                        BillingController.restoreTransactions(mContext);
                } else {
                        updateMadeDonations();
                }
        }

        private static Dialog createDialogBillingNotSupported() {
                AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
                builder.setTitle(R.string.billing_not_supported_title).setIcon(android.R.drawable.stat_sys_warning).setMessage(R.string.billing_not_supported_message).setCancelable(false).setPositiveButton(
                                android.R.string.ok, null);
                return builder.create();
        }

        private static Dialog createDialogDonate() {

                donateDialog = new Dialog(mContext);
                donateDialog.setContentView(R.layout.donate_dialog);

                donateDialog.setTitle(mContext.getString(R.string.donation_dialog_title));

                final Spinner mSelectDonationSpinner = (Spinner) donateDialog.findViewById(R.id.donate_dialog_spinner_donation);

                mSelectDonationSpinner.setAdapter(mDonationListAdapter);
                mDonationListAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
                mSelectDonationSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {

                        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                                if (position == 0)
                                        mSku = null;
                                else
                                        mSku = DonationEntry.DONATIONS_LIST[position].sku;
                        }

                        public void onNothingSelected(AdapterView<?> arg0) {
                        }

                });

                Button buttonDonate = (Button) donateDialog.findViewById(R.id.donate_dialog_btn_donate);
                Button buttonCancel = (Button) donateDialog.findViewById(R.id.donate_dialog_btn_cancel);
                buttonDonate.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View arg0) {
                                if (mSku != null) {
                                        BillingController.requestPurchase(mContext, mSku, true /* confirm */);
                                        donateDialog.dismiss();
                                }
                                mSelectDonationSpinner.setSelection(0);

                        }
                });
                buttonCancel.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View arg0) {
                                donateDialog.dismiss();
                                mSelectDonationSpinner.setSelection(0);

                        }
                });

                donateDialog.setOnCancelListener(new OnCancelListener() {

                        @Override
                        public void onCancel(DialogInterface dialog) {
                                mSelectDonationSpinner.setSelection(0);
                        }
                });

                return donateDialog;
        }

        private static void showDialog(int id) {
                switch (id) {
                case DIALOG_BILLING_NOT_SUPPORTED_ID:
                        if (billingNotSupportedDialog == null) {
                                billingNotSupportedDialog = createDialogBillingNotSupported();
                        }
                        billingNotSupportedDialog.show();

                case DIALOG_DONATE_ID:
                        if (donateDialog == null) {
                                donateDialog = createDialogDonate();
                        }
                        donateDialog.show();
                default:
                }
        }

        static public void showDonateDialog() {
                showDialog(DIALOG_DONATE_ID);
        }

        static public void dismissDonateDialog() {
                if (donateDialog != null) {
                        if (donateDialog.isShowing())
                                donateDialog.dismiss();
                }
        }

        private static void updateMadeDonations() {

                hasDonate = false;
                List<Transaction> transactions = BillingController.getTransactions(mContext);
                final ArrayList<String> madeDonations = new ArrayList<String>();
                for (Transaction t : transactions) {
                        if (t.purchaseState == PurchaseState.PURCHASED) {
                                madeDonations.add(t.productId);
                        }
                }
                if (madeDonations.size() > 0)
                        hasDonate = true;

                mDonationListAdapter.setMadeDonations(madeDonations);

                mListener.onHasDonate(hasDonate);

        }

        static public void init(Activity activity) {
                mContext = activity;
                mListener = (DonationManagerListener) activity;
                setupInAppBilling();
                BillingController.registerObserver(mBillingObserver);
                BillingStatus status = BillingController.checkBillingSupported(mContext);
        }

        static public void stop() {
                BillingController.unregisterObserver(mBillingObserver);
        }

}


Aggiungiamo l’adapter DonationListAdapter.java per lo spinner presente nella popup per le donazioni.

Codice (Java): [Seleziona]
package com.denper.example;

import java.util.ArrayList;
import java.util.List;

import com.denper.example.DonationEntry.Managed;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;

/**
 * An adapter used for displaying a catalog of products. If a product is managed
 * by Android Market and already purchased, then it will be "grayed-out" in the
 * list and not selectable.
 */

public class DonationListAdapter extends ArrayAdapter<String> {

        private DonationEntry[] mDonationList;
        private List<String> mMadeDonations = new ArrayList<String>();

        public DonationListAdapter(Context context, DonationEntry[] donationList) {
                super(context, android.R.layout.simple_spinner_item);
                mDonationList = donationList;
                for (DonationEntry element : donationList) {
                        add(context.getString(element.nameId));
                }
                setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        }

        @Override
        public boolean areAllItemsEnabled() {
                // Return false to have the adapter call isEnabled()
                return false;
        }

        @Override
        public View getDropDownView(int position, View convertView, ViewGroup parent) {
                // If the item at the given list position is not purchasable, then
                // "gray out" the list item.
                View view = super.getDropDownView(position, convertView, parent);
                view.setEnabled(isEnabled(position));
                return view;
        }

        public boolean isPurchased(String sku) {
                for (int i = 0; i < mMadeDonations.size(); i++) {
                        if (sku.equals(mMadeDonations.get(i))) {
                                return true;
                        }
                }
                return false;
        }

        @Override
        public boolean isEnabled(int position) {
                // If the item at the given list position is not purchasable,
                // then prevent the list item from being selected.
                DonationEntry entry = mDonationList[position];
                if (entry.managed == Managed.MANAGED && isPurchased(entry.sku)) {
                        return false;
                }
                return true;
        }

        public void setMadeDonations(List<String> madeDonations) {
                mMadeDonations = madeDonations;
                notifyDataSetChanged();
        }

        public List<String> getMadeDonations() {
                return mMadeDonations;
        }

}


Infine creiamo l’activity principale InAppBillingActivity.java per testare il tutto. Questa classe deve implementare DonationManagerListener per ricevere le callback da DonationEntry.java.

Codice (Java): [Seleziona]
package com.denper.example;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

import com.denper.example.DonationManager.DonationManagerListener;

public class InAppBillingActivity extends Activity implements DonationManagerListener {
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.main);

                DonationManager.init(this);

                Button buttonTest = (Button) findViewById(R.id.button_test);
                buttonTest.setOnClickListener(new OnClickListener() {

                        @Override
                        public void onClick(View arg0) {
                                DonationManager.showDonateDialog();

                        }
                });
        }

        @Override
        protected void onDestroy() {
                DonationManager.stop();
                super.onDestroy();
        }

        @Override
        protected void onPause() {
                DonationManager.dismissDonateDialog();
                super.onPause();
        }

        @Override
        public void onHasDonate(boolean donate) {
                // Aggiungere qui il codice di gestione per la vostra applicazione
                if(donate)
                        Toast.makeText(this, "Donation ok", Toast.LENGTH_LONG).show();
                else
                        Toast.makeText(this, "No donations", Toast.LENGTH_LONG).show();
                       
                       
        }
}


ATTENZIONE

Vi ricordo che per testare l’applicazione è necessario generare l’apk e firmarlo con la vostra chiave. Non è possibile testare l’applicazione sull’emulatore, bisogna testarla su un device fisico dove è presente l’applicazione Android Market. Altra cosa importante: per potere testare realmente la vostra app è necessario creare un nuovo account di test, non è possibile infatti acquistare i propri prodotti in-app con il proprio account, il Market vi da errore. Qui tutte le informazioni per come impostare un account di test Testing In-app Billing | Android Developers


Ho scritto questo tutorial molto velocemente, spero sia sufficientemente esaustivo. L'obbiettivo è quello di delineare a macrolivello le attività principali per poter utilizzare il servizio In-App Billing di Google.

Saluti
denper
« Ultima modifica: 14 Marzo 2012, 15:47:04 CET da denper »
Tutti sanno che una cosa è impossibile da realizzare, finché arriva uno sprovveduto che non lo sa e la inventa. [A.Einstein]

Proteggi la tua privacy! Utilizza GhostPhone! https://play.google.com/store/apps/details?id=com.denper.gp
Giochi a Winforlife e Superenalotto e sei stanco di controllare le tue schedine manualmente? Prova Checkwin: https://play.google.com/store/apps/details?id=com.denper.checkwintrial

Offline alepio

  • Utente normale
  • ***
  • Post: 163
  • Respect: +3
    • Google+
    • 107850838
    • Mostra profilo
  • Dispositivo Android:
    SAMSUNG ACE
  • Play Store ID:
    Alessandro Piola
  • Sistema operativo:
    WIN 7
Re:[medio] In-App Billing per ricevere donazioni od attivare funzionalità extra
« Risposta #1 il: 29 Febbraio 2012, 09:19:11 CET »
0
proprio quello che cercavo.
Vediamo subito come funziona l'integrazione nella mia APP

sfrutto l'occasione per una domanda.
Non capisco che tipologia di prodotti posso essere venduti.
Nell'esempio viene venduta una donazione, quindi nulla.
Ma se io volessi vendere una foto come dovrebbe avvenire la cosa?
« Ultima modifica: 29 Febbraio 2012, 09:25:42 CET da alepio »
-----------------------------------------------------
Con RISPARMIO BATTERIA - Battery Saver puoi anche dimenticarti a casa il carica batteria. Inoltre con gli EXTRAS puoi configurare la navigazione e disattivare i banner pubblicitari. Battery Saver controlla in automatico lo stato dello schermo.Se è spento disattiva WIFI e NAVIGAZIONE MOBILE, per poi riaccenderle a schermo attivo.
[APP] BatterySaver - Android Developers Italia
--------

Offline denper

  • Utente normale
  • ***
  • Post: 290
  • Respect: +60
    • Mostra profilo
    • Anddenper
  • Dispositivo Android:
    Moto G
  • Play Store ID:
    denper
  • Sistema operativo:
    Window 7, Windows XP
Re:[medio] In-App Billing per ricevere donazioni od attivare funzionalità extra
« Risposta #2 il: 29 Febbraio 2012, 09:49:27 CET »
0
Ciao,
ti dico già che il testing è un'pò un casino se hai bisogno sono qui.

Altra cosa importante per i test è di aggiungere tra i prodotti selezionabili dallo spinner anche i seguenti items:

Codice (Java): [Seleziona]
new DonationEntry("android.test.purchased", R.string.android_test_purchased, Managed.UNMANAGED),
new DonationEntry("android.test.canceled", R.string.android_test_canceled, Managed.UNMANAGED),
new DonationEntry("android.test.refunded", R.string.android_test_refunded, Managed.UNMANAGED),
new DonationEntry("android.test.item_unavailable", R.string.android_test_item_unavailable, Managed.UNMANAGED)

Questi ID prodotto sono riservati e servono per facilitare i test della vostra appicazione. La documentazione ufficiale la potete trovare qui Testing In-app Billing | Android Developers.

Ho aggiornato anche il codice allegato al tutorial con queste modifiche.

denper
Tutti sanno che una cosa è impossibile da realizzare, finché arriva uno sprovveduto che non lo sa e la inventa. [A.Einstein]

Proteggi la tua privacy! Utilizza GhostPhone! https://play.google.com/store/apps/details?id=com.denper.gp
Giochi a Winforlife e Superenalotto e sei stanco di controllare le tue schedine manualmente? Prova Checkwin: https://play.google.com/store/apps/details?id=com.denper.checkwintrial

Offline denper

  • Utente normale
  • ***
  • Post: 290
  • Respect: +60
    • Mostra profilo
    • Anddenper
  • Dispositivo Android:
    Moto G
  • Play Store ID:
    denper
  • Sistema operativo:
    Window 7, Windows XP
Re:[medio] In-App Billing per ricevere donazioni od attivare funzionalità extra
« Risposta #3 il: 29 Febbraio 2012, 10:35:45 CET »
0
proprio quello che cercavo.
Vediamo subito come funziona l'integrazione nella mia APP

sfrutto l'occasione per una domanda.
Non capisco che tipologia di prodotti posso essere venduti.
Nell'esempio viene venduta una donazione, quindi nulla.
Ma se io volessi vendere una foto come dovrebbe avvenire la cosa?

Ciao,
come descritto nelle documentazione ufficiale (In-app Billing Overview | Android Developers) nella sezione In-app Billing Requirements and Limitations c'è scritto:

Citazione
- You can use in-app billing to sell only digital content. You cannot use in-app billing to sell physical goods, personal services, or anything that requires physical delivery.
- Android Market does not provide any form of content delivery. You are responsible for delivering the digital content that you sell in your applications.

quindi l'archittettura di In-App Billing ti mette a disposizione tutto quanto riguarda il pagamento, la security e gli eventuali prodotti in-app acquistati dal singolo utente. Sta a te poi inviare i contenuti acquistati.

Per esempio se tu vendi una foto, dovresti inserire il prodotto come prodotto in-app nella tua applicazione, quando l'utente lo acquista, la tua app riceve questa informazione dal market e quindi dovrebbe scatenare l'evento di download dell'immagine da un tuo server.

Giusto per darti un'idea io farei cosi. Partendo dal codice che ho postato farei le seguenti modifiche:

Aggiungerei il prodotto "mia.foto" alla classe DonationEntry.java

Codice (Java): [Seleziona]
new DonationEntry("mia.foto", R.string.mia_foto, Managed.MANAGED)

modificherei l'interfaccia DonationManagerListener della classe DonationManagerListener.java in questo modo


Codice (Java): [Seleziona]
public interface DonationManagerListener {
                public void onHasDonate(boolean donate);
                // Callback per segnalare l'acquisto del prodotto itemId
                public void onBuyItem(String itemId);
        }


modificherei il metodo updateMadeDonations della classe DonationManagerListener.java in questo modo

Codice (Java): [Seleziona]
private static void updateMadeDonations() {

                hasDonate = false;
                List<Transaction> transactions = BillingController.getTransactions(mContext);
                final ArrayList<String> madeDonations = new ArrayList<String>();
                for (Transaction t : transactions) {
                        if (t.purchaseState == PurchaseState.PURCHASED) {
                                madeDonations.add(t.productId);
                                // Notifica di acquisto prodotto
                                mListener.onBuyItem(t.productId);
                        }
                }
                if (madeDonations.size() > 0)
                        hasDonate = true;

                mDonationListAdapter.setMadeDonations(madeDonations);

                mListener.onHasDonate(hasDonate);

        }

Nella classe principale InAppBillingActivity.java farei la seguente modifica

Codice (Java): [Seleziona]
@Override
        public void onBuyItem(String itemId) {
                if (itemId.equalsIgnoreCase("mia.foto")) {
                        // Inserire qui il codice per eseguire il download
                        // dell'immagine mia.foto
                }

        }

Ovviamente il mio esempio era legato alle donazioni per cui nel tuo caso i nomi delle classi e dei metodi andrebbero rinominati.
Un altro esempio lo puoi trovare qui https://github.com/robotmedia/AndroidBillingLibrary/tree/master/DungeonsRedux.

Tutti sanno che una cosa è impossibile da realizzare, finché arriva uno sprovveduto che non lo sa e la inventa. [A.Einstein]

Proteggi la tua privacy! Utilizza GhostPhone! https://play.google.com/store/apps/details?id=com.denper.gp
Giochi a Winforlife e Superenalotto e sei stanco di controllare le tue schedine manualmente? Prova Checkwin: https://play.google.com/store/apps/details?id=com.denper.checkwintrial

Offline alepio

  • Utente normale
  • ***
  • Post: 163
  • Respect: +3
    • Google+
    • 107850838
    • Mostra profilo
  • Dispositivo Android:
    SAMSUNG ACE
  • Play Store ID:
    Alessandro Piola
  • Sistema operativo:
    WIN 7
Re:[medio] In-App Billing per ricevere donazioni od attivare funzionalità extra
« Risposta #4 il: 29 Febbraio 2012, 14:51:26 CET »
0
ho completato il lavoro e lo sto testando ma non funziona.
E non capisco dove sbaglio.

ecco il log

02-29 13:49:31.026: W/ActivityManager(200): Unable to start service Intent { act=it.alessandropiola.gestioneritirorifiutiFREE.REQUEST_PURCHASE cmp=it.alessandropiola.gestioneritirorifiutiFREE/net.robotmedia.billing.BillingService (has extras) }: not found

ho cambiato utente, ma non mi elenca i prodotti.
Mi aggiunge solo quelli di test e se premo acquista non fa nulla
-----------------------------------------------------
Con RISPARMIO BATTERIA - Battery Saver puoi anche dimenticarti a casa il carica batteria. Inoltre con gli EXTRAS puoi configurare la navigazione e disattivare i banner pubblicitari. Battery Saver controlla in automatico lo stato dello schermo.Se è spento disattiva WIFI e NAVIGAZIONE MOBILE, per poi riaccenderle a schermo attivo.
[APP] BatterySaver - Android Developers Italia
--------

Offline denper

  • Utente normale
  • ***
  • Post: 290
  • Respect: +60
    • Mostra profilo
    • Anddenper
  • Dispositivo Android:
    Moto G
  • Play Store ID:
    denper
  • Sistema operativo:
    Window 7, Windows XP
Re:[medio] In-App Billing per ricevere donazioni od attivare funzionalità extra
« Risposta #5 il: 29 Febbraio 2012, 15:21:13 CET »
0
Dove lo stai testando? Ho generato l'apk e firmato con la tua chiave? Hai aggiunto i prodotti in-app nella tua applicazione sul Market? Hai fatto l'upload della tua app (in versione Draft) con la giusta versione sul market?
Tutti sanno che una cosa è impossibile da realizzare, finché arriva uno sprovveduto che non lo sa e la inventa. [A.Einstein]

Proteggi la tua privacy! Utilizza GhostPhone! https://play.google.com/store/apps/details?id=com.denper.gp
Giochi a Winforlife e Superenalotto e sei stanco di controllare le tue schedine manualmente? Prova Checkwin: https://play.google.com/store/apps/details?id=com.denper.checkwintrial

Offline alepio

  • Utente normale
  • ***
  • Post: 163
  • Respect: +3
    • Google+
    • 107850838
    • Mostra profilo
  • Dispositivo Android:
    SAMSUNG ACE
  • Play Store ID:
    Alessandro Piola
  • Sistema operativo:
    WIN 7
Re:[medio] In-App Billing per ricevere donazioni od attivare funzionalità extra
« Risposta #6 il: 29 Febbraio 2012, 15:58:08 CET »
0
ti riassumo quello che sto facendo.
ho fatto l'upload dell'app sul market attivandola anche (giusto per essere sicuri).
ho creato un prodotto "immagine_grazie" ed ho modificato il codice in questo modo:
(ho inserito la mia chiave pubblica da sviluppatore)

Codice (Java): [Seleziona]
public static final DonationEntry[] DONATIONS_LIST = new DonationEntry[] {
                        new     DonationEntry("immagine_grazie", R.string.donate_dummy, Managed.UNMANAGED),
                        new DonationEntry("android.test.purchased", R.string.android_test_purchased, Managed.UNMANAGED),
                        new DonationEntry("android.test.canceled", R.string.android_test_canceled, Managed.UNMANAGED),
                        new DonationEntry("android.test.refunded", R.string.android_test_refunded, Managed.UNMANAGED),
                        new DonationEntry("android.test.item_unavailable", R.string.android_test_item_unavailable, Managed.UNMANAGED)};

ho fatto poi lo scarico dell'app dal market ma non mi visualizza mai il prodotto
immagine_grazie
mi visualizza solo quelli test.
poi ho recuperato dal log quella riga
02-29 13:49:31.026: W/ActivityManager(200): Unable to start service Intent { act=it.alessandropiola.gestioneritirorifiutiFREE.REQUEST_PURCHASE cmp=it.alessandropiola.gestioneritirorifiutiFREE/net.robotmedia.billing.BillingService (has extras) }: not found

e ripeto che anche premendo i prodotti test non mi si apre mai il market.

Altra cosa strana non mi da nessun errore, cioè l'app non va mai in crash.
-----------------------------------------------------
Con RISPARMIO BATTERIA - Battery Saver puoi anche dimenticarti a casa il carica batteria. Inoltre con gli EXTRAS puoi configurare la navigazione e disattivare i banner pubblicitari. Battery Saver controlla in automatico lo stato dello schermo.Se è spento disattiva WIFI e NAVIGAZIONE MOBILE, per poi riaccenderle a schermo attivo.
[APP] BatterySaver - Android Developers Italia
--------

Offline denper

  • Utente normale
  • ***
  • Post: 290
  • Respect: +60
    • Mostra profilo
    • Anddenper
  • Dispositivo Android:
    Moto G
  • Play Store ID:
    denper
  • Sistema operativo:
    Window 7, Windows XP
Re:[medio] In-App Billing per ricevere donazioni od attivare funzionalità extra
« Risposta #7 il: 29 Febbraio 2012, 16:23:17 CET »
0
Ciao,
prima cosa: non vedi il tuo item perchè ha come descrizione la stringa donate_dummy presente nel file string.xml. In ogni caso devi lasciare come primo elemento nello spinner quello dummy "donate.dummy" che ha lo scopo di presentare la descrizione Scegli donazione. Nel tuo caso potresti modificare la descrizione in Scegli immagine per esempio.

La tua lista prodotti dovrebbe essere così:

Codice (Java): [Seleziona]
/** An array of product list entries for the products that can be purchased. */
        public static final DonationEntry[] DONATIONS_LIST = new DonationEntry[] { new DonationEntry("donate.dummy", R.string.donate_dummy, Managed.UNMANAGED),
                        new DonationEntry("immagine_grazie", R.string.immagine_grazie, Managed.MANAGED), new DonationEntry("android.test.purchased", R.string.android_test_purchased, Managed.UNMANAGED),
                        new DonationEntry("android.test.canceled", R.string.android_test_canceled, Managed.UNMANAGED),
                        new DonationEntry("android.test.refunded", R.string.android_test_refunded, Managed.UNMANAGED),
                        new DonationEntry("android.test.item_unavailable", R.string.android_test_item_unavailable, Managed.UNMANAGED) };


Ovviamente devi aggiungere nel tuo file string.xml la voce immagine_grazie con la relativa descrizione.

Seconda cosa: il fatto che non si apra il Market è molto strano sei sicuro di avere la versione del market corretta? Da documentazione ufficiale:

Citazione
- If your device is running Android 3.0, in-app billing requires version 5.0.12 (or higher) of the MyApps application. If your device is running any other version of Android, in-app billing requires version 2.3.4 (or higher) of the Android Market application.
- An application can use in-app billing only if the device is running Android 1.6 (API level 4) or higher.

Prova a verificare e fammi sapere.
Tutti sanno che una cosa è impossibile da realizzare, finché arriva uno sprovveduto che non lo sa e la inventa. [A.Einstein]

Proteggi la tua privacy! Utilizza GhostPhone! https://play.google.com/store/apps/details?id=com.denper.gp
Giochi a Winforlife e Superenalotto e sei stanco di controllare le tue schedine manualmente? Prova Checkwin: https://play.google.com/store/apps/details?id=com.denper.checkwintrial

Offline alepio

  • Utente normale
  • ***
  • Post: 163
  • Respect: +3
    • Google+
    • 107850838
    • Mostra profilo
  • Dispositivo Android:
    SAMSUNG ACE
  • Play Store ID:
    Alessandro Piola
  • Sistema operativo:
    WIN 7
Re:[medio] In-App Billing per ricevere donazioni od attivare funzionalità extra
« Risposta #8 il: 29 Febbraio 2012, 17:27:45 CET »
0
il tutto si ferma qui.

BillingController.requestPurchase(mContext, mSku, true /* confirm */);
dove mSku è l'ID dell'oggetto nel mio caso immagine.grazie
e subito dopo ritorna l'errore:
Codice: [Seleziona]
02-29 17:23:02.249: W/ActivityManager(162): Unable to start service Intent { act=it.alessandropiola.gestioneritirorifiutiFREE.REQUEST_PURCHASE cmp=it.alessandropiola.gestioneritirorifiutiFREE/net.robotmedia.billing.BillingService (has extras) }: not found

ammetto di aver molto mal di testa. :-)
-----------------------------------------------------
Con RISPARMIO BATTERIA - Battery Saver puoi anche dimenticarti a casa il carica batteria. Inoltre con gli EXTRAS puoi configurare la navigazione e disattivare i banner pubblicitari. Battery Saver controlla in automatico lo stato dello schermo.Se è spento disattiva WIFI e NAVIGAZIONE MOBILE, per poi riaccenderle a schermo attivo.
[APP] BatterySaver - Android Developers Italia
--------

Offline Luigi.Arena

  • Utente senior
  • ****
  • Post: 616
  • DACIA DUSTER 4X4 SUPER
  • Respect: +56
    • Mostra profilo
    • ArenaWebTest
  • Dispositivo Android:
    epad m009
  • Play Store ID:
    Luigi Arena
  • Sistema operativo:
    Windows 7
0
Bravo per il tutorial, ora non ho tempo ma appena posso provo ad imlementarlo.
Un bel + 1
È stata trovata una soluzione al tuo problema?Evidenzia il post più utile premendo . È un ottimo modo per ringraziare chi ti ha aiutato .

Offline alepio

  • Utente normale
  • ***
  • Post: 163
  • Respect: +3
    • Google+
    • 107850838
    • Mostra profilo
  • Dispositivo Android:
    SAMSUNG ACE
  • Play Store ID:
    Alessandro Piola
  • Sistema operativo:
    WIN 7
0
Ecco la lista di quello che non mi va:
Ora il market mi dice : Questa versione dell'applicazione non è configurata per la fatturazione. (Non sto usando il mio utente).
e poi se riapro l'app dopo aver provato ad acquistare un prodotto mi dice:
Codice (Java): [Seleziona]
03-02 17:28:37.179: E/AndroidRuntime(766): FATAL EXCEPTION: main
03-02 17:28:37.179: E/AndroidRuntime(766): java.lang.IllegalStateException: Could not execute method of the activity
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.view.View$1.onClick(View.java:2144)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.view.View.performClick(View.java:2485)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.view.View$PerformClick.run(View.java:9080)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.os.Handler.handleCallback(Handler.java:587)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.os.Handler.dispatchMessage(Handler.java:92)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.os.Looper.loop(Looper.java:130)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.app.ActivityThread.main(ActivityThread.java:3687)
03-02 17:28:37.179: E/AndroidRuntime(766):      at java.lang.reflect.Method.invokeNative(Native Method)
03-02 17:28:37.179: E/AndroidRuntime(766):      at java.lang.reflect.Method.invoke(Method.java:507)
03-02 17:28:37.179: E/AndroidRuntime(766):      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
03-02 17:28:37.179: E/AndroidRuntime(766):      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
03-02 17:28:37.179: E/AndroidRuntime(766):      at dalvik.system.NativeStart.main(Native Method)
03-02 17:28:37.179: E/AndroidRuntime(766): Caused by: java.lang.reflect.InvocationTargetException
03-02 17:28:37.179: E/AndroidRuntime(766):      at java.lang.reflect.Method.invokeNative(Native Method)
03-02 17:28:37.179: E/AndroidRuntime(766):      at java.lang.reflect.Method.invoke(Method.java:507)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.view.View$1.onClick(View.java:2139)
03-02 17:28:37.179: E/AndroidRuntime(766):      ... 11 more
03-02 17:28:37.179: E/AndroidRuntime(766): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@405548c8 is not valid; is your activity running?
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.view.ViewRoot.setView(ViewRoot.java:532)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.view.Window$LocalWindowManager.addView(Window.java:424)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.app.Dialog.show(Dialog.java:241)
03-02 17:28:37.179: E/AndroidRuntime(766):      at it.alessandropiola.gestioneritirorifiutiFREE.DonationManager.showDialog(DonationManager.java:161)
03-02 17:28:37.179: E/AndroidRuntime(766):      at it.alessandropiola.gestioneritirorifiutiFREE.DonationManager.showDonateDialog(DonationManager.java:167)
03-02 17:28:37.179: E/AndroidRuntime(766):      at it.alessandropiola.gestioneritirorifiutiFREE.inizio.acq(inizio.java:217)
03-02 17:28:37.179: E/AndroidRuntime(766):      ... 14 more
-----------------------------------------------------
Con RISPARMIO BATTERIA - Battery Saver puoi anche dimenticarti a casa il carica batteria. Inoltre con gli EXTRAS puoi configurare la navigazione e disattivare i banner pubblicitari. Battery Saver controlla in automatico lo stato dello schermo.Se è spento disattiva WIFI e NAVIGAZIONE MOBILE, per poi riaccenderle a schermo attivo.
[APP] BatterySaver - Android Developers Italia
--------

Offline alepio

  • Utente normale
  • ***
  • Post: 163
  • Respect: +3
    • Google+
    • 107850838
    • Mostra profilo
  • Dispositivo Android:
    SAMSUNG ACE
  • Play Store ID:
    Alessandro Piola
  • Sistema operativo:
    WIN 7
0
Ho sistemato tutto
era un mio errore
ora tutto funziona
Ecco la lista di quello che non mi va:
Ora il market mi dice : Questa versione dell'applicazione non è configurata per la fatturazione. (Non sto usando il mio utente).
e poi se riapro l'app dopo aver provato ad acquistare un prodotto mi dice:
Codice (Java): [Seleziona]
03-02 17:28:37.179: E/AndroidRuntime(766): FATAL EXCEPTION: main
03-02 17:28:37.179: E/AndroidRuntime(766): java.lang.IllegalStateException: Could not execute method of the activity
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.view.View$1.onClick(View.java:2144)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.view.View.performClick(View.java:2485)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.view.View$PerformClick.run(View.java:9080)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.os.Handler.handleCallback(Handler.java:587)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.os.Handler.dispatchMessage(Handler.java:92)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.os.Looper.loop(Looper.java:130)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.app.ActivityThread.main(ActivityThread.java:3687)
03-02 17:28:37.179: E/AndroidRuntime(766):      at java.lang.reflect.Method.invokeNative(Native Method)
03-02 17:28:37.179: E/AndroidRuntime(766):      at java.lang.reflect.Method.invoke(Method.java:507)
03-02 17:28:37.179: E/AndroidRuntime(766):      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
03-02 17:28:37.179: E/AndroidRuntime(766):      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
03-02 17:28:37.179: E/AndroidRuntime(766):      at dalvik.system.NativeStart.main(Native Method)
03-02 17:28:37.179: E/AndroidRuntime(766): Caused by: java.lang.reflect.InvocationTargetException
03-02 17:28:37.179: E/AndroidRuntime(766):      at java.lang.reflect.Method.invokeNative(Native Method)
03-02 17:28:37.179: E/AndroidRuntime(766):      at java.lang.reflect.Method.invoke(Method.java:507)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.view.View$1.onClick(View.java:2139)
03-02 17:28:37.179: E/AndroidRuntime(766):      ... 11 more
03-02 17:28:37.179: E/AndroidRuntime(766): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@405548c8 is not valid; is your activity running?
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.view.ViewRoot.setView(ViewRoot.java:532)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.view.Window$LocalWindowManager.addView(Window.java:424)
03-02 17:28:37.179: E/AndroidRuntime(766):      at android.app.Dialog.show(Dialog.java:241)
03-02 17:28:37.179: E/AndroidRuntime(766):      at it.alessandropiola.gestioneritirorifiutiFREE.DonationManager.showDialog(DonationManager.java:161)
03-02 17:28:37.179: E/AndroidRuntime(766):      at it.alessandropiola.gestioneritirorifiutiFREE.DonationManager.showDonateDialog(DonationManager.java:167)
03-02 17:28:37.179: E/AndroidRuntime(766):      at it.alessandropiola.gestioneritirorifiutiFREE.inizio.acq(inizio.java:217)
03-02 17:28:37.179: E/AndroidRuntime(766):      ... 14 more
-----------------------------------------------------
Con RISPARMIO BATTERIA - Battery Saver puoi anche dimenticarti a casa il carica batteria. Inoltre con gli EXTRAS puoi configurare la navigazione e disattivare i banner pubblicitari. Battery Saver controlla in automatico lo stato dello schermo.Se è spento disattiva WIFI e NAVIGAZIONE MOBILE, per poi riaccenderle a schermo attivo.
[APP] BatterySaver - Android Developers Italia
--------

Offline denper

  • Utente normale
  • ***
  • Post: 290
  • Respect: +60
    • Mostra profilo
    • Anddenper
  • Dispositivo Android:
    Moto G
  • Play Store ID:
    denper
  • Sistema operativo:
    Window 7, Windows XP
0
Ciao,
bene bene sono contento!
Magari posta anche dove stava il problema, così se qualche altro utente si trova nella stessa situazione, può capire come risolvere.
Tutti sanno che una cosa è impossibile da realizzare, finché arriva uno sprovveduto che non lo sa e la inventa. [A.Einstein]

Proteggi la tua privacy! Utilizza GhostPhone! https://play.google.com/store/apps/details?id=com.denper.gp
Giochi a Winforlife e Superenalotto e sei stanco di controllare le tue schedine manualmente? Prova Checkwin: https://play.google.com/store/apps/details?id=com.denper.checkwintrial

Offline alepio

  • Utente normale
  • ***
  • Post: 163
  • Respect: +3
    • Google+
    • 107850838
    • Mostra profilo
  • Dispositivo Android:
    SAMSUNG ACE
  • Play Store ID:
    Alessandro Piola
  • Sistema operativo:
    WIN 7
0
Allora.....
 il problema del
Questa versione dell'applicazione non è configurata per la fatturazione
è dovuto all'utente (ne ho 2 molto simili ed ho sbagliato la configurazione del cell), il messaggio appare quando si cerca di comprare le proprie app.
Il secondo uno stupidissimo errore di sintassi.
Ciao e grazie ancora.
Ciao,
bene bene sono contento!
Magari posta anche dove stava il problema, così se qualche altro utente si trova nella stessa situazione, può capire come risolvere.
-----------------------------------------------------
Con RISPARMIO BATTERIA - Battery Saver puoi anche dimenticarti a casa il carica batteria. Inoltre con gli EXTRAS puoi configurare la navigazione e disattivare i banner pubblicitari. Battery Saver controlla in automatico lo stato dello schermo.Se è spento disattiva WIFI e NAVIGAZIONE MOBILE, per poi riaccenderle a schermo attivo.
[APP] BatterySaver - Android Developers Italia
--------

Offline r1si

  • Utente junior
  • **
  • Post: 73
  • Respect: +1
    • Mostra profilo
  • Dispositivo Android:
    lg 2x
  • Play Store ID:
    r1si
  • Sistema operativo:
    ubuntu 11.10
0
grazie mille per la guida :)