Autore Topic: [Medio] Inserire il controllo di licenza nella propria applicazione  (Letto 17095 volte)

Offline Gambanera

  • Nuovo arrivato
  • *
  • Post: 27
  • Respect: +11
    • Mostra profilo
  • Dispositivo Android:
    Vodafone ideos
  • Play Store ID:
    Gambanera
  • Sistema operativo:
    Ubuntu 10.10 / Windows 7
Livello di difficoltà: medio
Target SDK: 3
Min SDK: 3
Link al file compresso del progetto eclipse: file in allegato

Utilizzare il sistema di licenze fornito da google per tutelare le nostre applicazioni a pagamento.
Tramite l'Android Market Licensing, le app possono interrogare il market e ottenere lo stato della licenza per l'utente corrente, permettendo o meno l'esecuzione a seconda dei casi.

1 - Scaricare il "Market licensig package"

Per prima cosa è necessario accertarsi di aver installato le "License Verification Library" ( da questo momento in poi LVL ), un insieme di classi di supporto che semplificano notevolmente l'implementazione per il controllo della licenza.
Nel caso in cui non siano state installate, lanciate l'SDK Manager quindi nella sezione "Available Packages" selezionate il componente "Market licensig package", come mostrato nella figura seguente. Accettate i termini e fate clic su "Install" per avviare il download.



2 - Creare un nuovo "LVL library project"

Adesso è necessario creare un nuovo progetto libreria che includa le classi appena installate. Per far ciò recatevi nella directory dov'è presente l'sdk e fate una copia della cartella "google-market_licensing".
Aprite eclipse e create un nuovo progetto android. Nel wizard selezionate la voce "Create project from existing sources" e selezionate la cartella "library" presente nella copia di backup precedentemente creata. Per quanto riguarda il target di  compilazione, selezionate Android 1.5 (API level 3) o superiore quindi cliccate sul tasto "Finish". Adesso nella finestra "Packages Explorer" è visibile il progetto che avete importato.

3 - Includere la libreria "LVL library project" nella vostra applicazione


E' il momento di includere la libreria nel vostro progetto. Per fare ciò, nella finestra "Packages Explorer", cliccate con il tasto destro sulla cartella della vostra app e selezionate la voce "Propriertis" dal menu a tendina. Selezionate la voce "Android" e aggiungete la libreria creata nel passo precedente cliccando sul bottone "Add" nella sezione "Library", come mostrato in figura.



4 - Creare la classe Utils.java

La classe Utils.java ha come compito quello di fornire un identificativo univoco associato al telefono.

Create una nuova classe Utils.java ed incollate il seguente codice:
Codice (Java): [Seleziona]
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;

public class Utils {

        public static String getId(Context c) {

                StringBuffer b = new StringBuffer();

                b.append(Settings.Secure.getString(c.getContentResolver(),
                                Settings.Secure.ANDROID_ID));
                b.append(Build.BRAND);
                b.append(Build.DEVICE);
                b.append(Build.VERSION.RELEASE);
                b.append(Build.BOARD);
                b.append(Build.ID);

                return md5sum(b.toString());
        }

        public static String md5sum(String s) {

                try {

                        MessageDigest md = java.security.MessageDigest.getInstance("MD5");
                        md.update(s.getBytes());

                        byte resultSum[] = md.digest();

                        StringBuffer hexString = new StringBuffer();

                        for (int i = 0; i < resultSum.length; i++) {
                                String h = Integer.toHexString(0xFF & resultSum[i]);

                                while (h.length() < 2)
                                        h = "0" + h;

                                hexString.append(h);
                        }

                        return hexString.toString();

                } catch (NoSuchAlgorithmException e) {
                        e.printStackTrace();
                }

                return null;
        }
}

Oltre all "ANDROID_ID" ho inserito altre informazione come la marca e il modello del device per poi farne il checksum, il tutto per avere un id il più robusto possibile.

Qui potete apportare le modiche che meglio credete, aggiungendo altre variabile alla stringa oppure cambiando l'algoritmo di checksum.

5 - Creare l'activity di verifica della licenza Main.java


Main.java è una activity che ha come responsabilità verificare la licenza d'acquisto.

Aggiungete al file "res/values/strings.xml" queste stringhe ( che verranno richiamate nell'activity ):
Codice (XML): [Seleziona]
<!-- Unlicensed dialog messages -->
        <string name="application_error">Errore applicazione:</string>
        <string name="unlicensed_dialog_title">Acquisto applicazione non verificato</string>
        <string name="unlicensed_dialog_body">"Questa copia dell'applicazione risulta non acquistata legalmente"</string>
        <string name="buy_button">"Compra l'app"</string>
        <string name="quit_button">Esci</string>


Nel vostro progetto create una nuova classe java con il nome Main.java ed incollate il seguente testo:
Codice (Java): [Seleziona]
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.Toast;

import com.android.vending.licensing.AESObfuscator;
import com.android.vending.licensing.LicenseChecker;
import com.android.vending.licensing.LicenseCheckerCallback;
import com.android.vending.licensing.ServerManagedPolicy;

public class Main extends Activity {

        private class MyLicenseCheckerCallback implements LicenseCheckerCallback {
                @Override
                public void allow() {

                        Log.i("License", "Allow");

                        if (isFinishing()) {
                                return;
                        }

                        String id = Utils.getId(getApplicationContext());
                        Log.i("MyLicenseCheckerCallback:allow", id);

                        SharedPreferences.Editor editor = PreferenceManager
                                        .getDefaultSharedPreferences(getBaseContext()).edit();
                        editor.putString("deviceId", id);
                        editor.commit();

                        /* Should allow user access */
                        startMainActivity();

                }

                @Override
                public void applicationError(ApplicationErrorCode errorCode) {

                        Log.i("License", "Error: " + errorCode);

                        if (isFinishing()) {
                                return;
                        }

                        toast(getString(R.string.application_error) + errorCode.name());
                        // startMainActivity();

                }

                @Override
                public void dontAllow() {

                        Log.i("License", "DontAllow");

                        if (isFinishing()) {
                                return;
                        }

                        showDialog(0);
                }
        }

        private LicenseChecker mChecker;
        private LicenseCheckerCallback mLicenseCheckerCallback;

        private static final String BASE64_PUBLIC_KEY = "PLACE YOUR BASE KEY FROM GOOGLE HERE";

         // REPLACE WITH YOUR OWN SALT , THIS IS FROM EXAMPLE
    private static final byte[] SALT = new byte[] {
            -46, 65, 30, -128, -103, -57, 74, -64, 51, 88,
            -95, -45, 77, -117, -36, -113, -11, 32, -64, 89
    };

        @Override
        public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);

                SharedPreferences preferences = PreferenceManager
                                .getDefaultSharedPreferences(getBaseContext());

                String deviceId = Utils.getId(getApplicationContext());
                Log.i("Main:onCreate", deviceId);

                if (deviceId.equals(preferences.getString("deviceId", ""))) {
                        Log.i("Main:onCreate", "checked license");
                        startMainActivity();
                }

                /* Library calls this when it's done */
                mLicenseCheckerCallback = new MyLicenseCheckerCallback();

                /* Construct the LicenseChecker with a policy */
                mChecker = new LicenseChecker(this, new ServerManagedPolicy(this,
                                new AESObfuscator(SALT, getPackageName(), deviceId)),
                                BASE64_PUBLIC_KEY);

                doCheck();

        }

        private void doCheck() {
                mChecker.checkAccess(mLicenseCheckerCallback);
        }

        protected Dialog onCreateDialog(int id) {

                return new AlertDialog.Builder(this)
                                .setTitle(R.string.unlicensed_dialog_title)
                                .setMessage(R.string.unlicensed_dialog_body)
                                .setPositiveButton(R.string.buy_button,
                                                new DialogInterface.OnClickListener() {
                                                        public void onClick(DialogInterface dialog,
                                                                        int which) {
                                                                Intent marketIntent = new Intent(
                                                                                Intent.ACTION_VIEW,
                                                                                Uri.parse("http://market.android.com/details?id="
                                                                                                + getPackageName()));
                                                                startActivity(marketIntent);
                                                                finish();
                                                        }
                                                })
                                .setNegativeButton(R.string.quit_button,
                                                new DialogInterface.OnClickListener() {
                                                        public void onClick(DialogInterface dialog,
                                                                        int which) {
                                                                finish();
                                                        }
                                                })

                                .setCancelable(false)
                                .setOnKeyListener(new DialogInterface.OnKeyListener() {
                                        public boolean onKey(DialogInterface dialogInterface,
                                                        int i, KeyEvent keyEvent) {
                                                Log.i("License", "Key Listener");
                                                finish();
                                                return true;
                                        }
                                }).create();

        }

        @Override
        protected void onDestroy() {
                super.onDestroy();
                if (mChecker != null) {
                        Log.i("License", "Destroy Checker");
                        mChecker.onDestroy();
                }

        }

        private void startMainActivity() {
               
                //REPLACE MainActivity.class WITH YOUR APPS ORIGINAL LAUNCH ACTIVITY
                startActivity(new Intent(this, MainActivity.class));
                finish();
        }

        public void toast(String string) {
                Toast.makeText(this, string, Toast.LENGTH_SHORT).show();
        }

}

La classe va modificata in 3 punti:

- String BASE64_PUBLIC_KEY -> inserendo la vostra chiave pubblica
- final byte[] SALT -> sostituendo i 20 interi
- MainActivity.class -> sostituendola con l'activity principale della vostra app

L'activity contatta il server e in caso di risposta positiva memorizza l'id in uno sharedPreference in modo tale da riverificare la licenza solo nel caso in cui quest'ultimo cambi.

6 -  Modifica del Manifest

Adesso non rimane che modificare il manifet, aggiungento l'activity creata nel punto precedente
Codice (XML): [Seleziona]
<!-- Old Launch Activity Here -->
<activity android:label="@string/app_name" android:name=".MainActivity" />
<!-- New License Launch Activity with all intent filters from your previous main activity -->
<!-- Translucent.NoTitleBar is so that this activity is never shown to the user -->            
<activity android:label="@string/app_name" android:name=".Main"
                        android:theme="@android:style/Theme.Translucent.NoTitleBar">
                        <intent-filter>
                                <action android:name="android.intent.action.MAIN" />
                                <category android:name="android.intent.category.LAUNCHER" />
                        </intent-filter></activity>

ed inserendo i permessi per la verifica della licenza
Codice (XML): [Seleziona]
  </application><uses-permission android:name="com.android.vending.CHECK_LICENSE" />
Assicuratevi di aver sostituito la vecchia activity, utilizzata come launcher, con la nuova ".Main"

7 - Verifica

Una volta terminata la vostra app e generato il file .apk ( firmato e preparato a dovere ) installete l'app su un dispositivo di prova e poi fatene l'upload sul vostro profilo nel market. Caricate le vostra applicazione e inserite tutte le informazioni di contorno necessarie ( foto, descrizione, prezzo ecc... ) e poi salvate il tutto tramite il tasto "Save" in fondo alla pagina.
Cliccate sul link "Edit Profile" ed inserite nel campo "Test Accounts" l'indirizzo gmail collegato al device. A questo punto non rimane che testare le varie risposte del server, come mostrato in figura.


Spero di essere stato il più esaustivo possibile :)


Bibliografia:
« Ultima modifica: 17 Marzo 2011, 16:58:45 CET da Gambanera »

Offline Ricky`

  • Amministratore
  • Utente storico
  • *****
  • Post: 3489
  • Respect: +506
    • Github
    • Google+
    • rciovati
    • Mostra profilo
Re:[Medio] Inserire il controllo di licenza nella propria applicazione
« Risposta #1 il: 05 Marzo 2011, 19:10:18 CET »
0
Ottima guida.
Io direi che ognuno che usa questo tutorial dovrebbe però appendere una stringa che solo lui conosce alla generazione del device id.
E ovviamente offuscare il codice :)

PS: il primo link è rotto
« Ultima modifica: 05 Marzo 2011, 19:12:20 CET da Ricky` »

Offline Gambanera

  • Nuovo arrivato
  • *
  • Post: 27
  • Respect: +11
    • Mostra profilo
  • Dispositivo Android:
    Vodafone ideos
  • Play Store ID:
    Gambanera
  • Sistema operativo:
    Ubuntu 10.10 / Windows 7
Re:[Medio] Inserire il controllo di licenza nella propria applicazione
« Risposta #2 il: 05 Marzo 2011, 19:30:30 CET »
0
Ottima guida.
Io direi che ognuno che usa questo tutorial dovrebbe però appendere una stringa che solo lui conosce alla generazione del device id.
E ovviamente offuscare il codice :)

PS: il primo link è rotto

Si infatti l'ho specificato,il mio è soltanto un esempio
Per quanto riguarda l'offuscamento del codice, appena ho un po di tempo preparo uno snippet :)


Link corretto!

Offline mimmog

  • Utente senior
  • ****
  • Post: 731
  • Respect: +11
    • MisterX_Dev
    • Mostra profilo
  • Dispositivo Android:
    Galaxy Note e Galaxy Nexus
  • Play Store ID:
    MisterX_Dev
  • Sistema operativo:
    Windows 7
Re:[Medio] Inserire il controllo di licenza nella propria applicazione
« Risposta #3 il: 10 Aprile 2011, 14:25:04 CEST »
0
A me questo codice non funge, mi restituisce sempre true anche se nel developer account ho settato l'email di test e metto le varie opzioni LICENSID, NOT LICENSID la risposta è sempre uguale ovvero effettua il cek e dal metodo cekAccess mi ritorna sempre true....ho provao a mettere un numero di public key sbagliato ma la risposta è sempre la stessa dopo qualche secondo che clicco l'icona, l'applicazione si apre normalmente...

Offline mimmog

  • Utente senior
  • ****
  • Post: 731
  • Respect: +11
    • MisterX_Dev
    • Mostra profilo
  • Dispositivo Android:
    Galaxy Note e Galaxy Nexus
  • Play Store ID:
    MisterX_Dev
  • Sistema operativo:
    Windows 7
Re: [Medio] Inserire il controllo di licenza nella propria applicazione
« Risposta #4 il: 11 Aprile 2011, 07:57:20 CEST »
0
Scusate avrei due domande:
1) Con questo codice se la prima volta che sia apre l'applicazione non c'è collegamento ad internet comunque esce il popup che il software è illegale?se si è normale ?
2) Se dopo  aver implementato il certificato volessi regalare questa applicazione a qualcuno garantendogli anche di poter dcaricare dal market tutti gli aggiornamenti che saranno pubblicati proprio come se l'app fosse stata comprata, come si fa? Devo regalare una copia dell'applicazione senza il controllo della licenza?

Sent from my GT-I9000 using Tapatalk

Offline mimmog

  • Utente senior
  • ****
  • Post: 731
  • Respect: +11
    • MisterX_Dev
    • Mostra profilo
  • Dispositivo Android:
    Galaxy Note e Galaxy Nexus
  • Play Store ID:
    MisterX_Dev
  • Sistema operativo:
    Windows 7
Re:[Medio] Inserire il controllo di licenza nella propria applicazione
« Risposta #5 il: 11 Aprile 2011, 20:40:21 CEST »
0
Me la date una risposta a queste 2 domande o mi spostate la domanda in un posto dove qualcuno la possa leggere ? :(

Grazie

Offline Nicola_D

  • Utente storico
  • *****
  • Post: 2479
  • SBAGLIATO!
  • Respect: +323
    • Github
    • Google+
    • nicoladorigatti
    • Mostra profilo
  • Dispositivo Android:
    Nexus 6p, Nexus 4, Nexus S, Nexus 7(2012)
  • Sistema operativo:
    Windows 7
Re:[Medio] Inserire il controllo di licenza nella propria applicazione
« Risposta #6 il: 11 Aprile 2011, 21:07:25 CEST »
0
Me la date una risposta a queste 2 domande o mi spostate la domanda in un posto dove qualcuno la possa leggere ? :(

Grazie
se nessuno ti risponde, evidentemente è perchè nessuno ha la risposta o non c'è nessuno con sufficiente esperienza in quello che chiedi... qui credo che nessuno sviluppa su android per lavoro 24h su 24 tutti i giorni e conosce il framework al 100... per dirti, io non ho neanche mai implementato un service...
IMPORTANTE:NON RISPONDO A PROBLEMI VIA MESSAGGIO PRIVATO
LOGCAT: Non sai cos'è? -> Android Debug Bridge | Android Developers
               Dov'è in Eclipse? -> Window -> Open Prospective -> DDMS e guarda in basso!
[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO) - Android Developers Italia

Offline mimmog

  • Utente senior
  • ****
  • Post: 731
  • Respect: +11
    • MisterX_Dev
    • Mostra profilo
  • Dispositivo Android:
    Galaxy Note e Galaxy Nexus
  • Play Store ID:
    MisterX_Dev
  • Sistema operativo:
    Windows 7
Re:[Medio] Inserire il controllo di licenza nella propria applicazione
« Risposta #7 il: 11 Aprile 2011, 21:29:46 CEST »
0
Ma va nicola !!! ma se siete tutti bravissimi, tu, marco, ricky e gli altri siete i miei pilastri di android :)

Offline 7h38ugg3r

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1200
  • Respect: +133
    • riccardofischetti
    • th38ugg3r
    • @7h38ugg3r
    • Mostra profilo
  • Dispositivo Android:
    Galaxy-S GT I-9000/ ASUS Eee Pad Transformer
  • Play Store ID:
    Riccardo Fischetti
  • Sistema operativo:
    OS X Lion / Linux Mint 11 (Katya)
Re:[Medio] Inserire il controllo di licenza nella propria applicazione
« Risposta #8 il: 12 Aprile 2011, 09:06:46 CEST »
0
beh, ma è tutta una parvenza.....è solo fumo.... 8-)
7h38ugg3r<=>thebugger
Non conosci Java? Allora sei nel posto sbagliato!

http://www.androidpatterns.com/

Offline mimmog

  • Utente senior
  • ****
  • Post: 731
  • Respect: +11
    • MisterX_Dev
    • Mostra profilo
  • Dispositivo Android:
    Galaxy Note e Galaxy Nexus
  • Play Store ID:
    MisterX_Dev
  • Sistema operativo:
    Windows 7
Re:[Medio] Inserire il controllo di licenza nella propria applicazione
« Risposta #9 il: 12 Aprile 2011, 11:27:53 CEST »
0
beh, ma è tutta una parvenza.....è solo fumo.... 8-)

Non credo proprio...  :D
Ma poi, nessuno ha mai pubblicato un applicazione a pagamento sul market ?

Io non l'ho mai scaricata un'applicazione a pagamento quindi non sò nemmeno come si comporta se al primo accesso all'applicazione  la connessione è disabilitata... :(

Offline Nicola_D

  • Utente storico
  • *****
  • Post: 2479
  • SBAGLIATO!
  • Respect: +323
    • Github
    • Google+
    • nicoladorigatti
    • Mostra profilo
  • Dispositivo Android:
    Nexus 6p, Nexus 4, Nexus S, Nexus 7(2012)
  • Sistema operativo:
    Windows 7
Re:[Medio] Inserire il controllo di licenza nella propria applicazione
« Risposta #10 il: 12 Aprile 2011, 12:14:48 CEST »
0
Non credo proprio...  :D
Ma poi, nessuno ha mai pubblicato un applicazione a pagamento sul market ?

Io non l'ho mai scaricata un'applicazione a pagamento quindi non sò nemmeno come si comporta se al primo accesso all'applicazione  la connessione è disabilitata... :(
io avevo provato air control.
Se eri connesso, verificava e si salvava la info. Altrimenti, ti lasciava giocare.
Invece altri giochi tipo Hyper Jump, se non sei connesso dopo 10 minuti ti dice che il controllo è fallito e sei fregato. Per me l'app dovrebbe verificare una volta solo, e poi salvarsi il valore nelle sharedPrefs. Se il valore non c'è,verifichi la connessione e la licenza,altrimenti, ti fidi dell'utente. Ricordati che è l'utente che deve avere feeling con l'app, non tu!
IMPORTANTE:NON RISPONDO A PROBLEMI VIA MESSAGGIO PRIVATO
LOGCAT: Non sai cos'è? -> Android Debug Bridge | Android Developers
               Dov'è in Eclipse? -> Window -> Open Prospective -> DDMS e guarda in basso!
[Obbligatorio] Logcat, questo sconosciuto! (Gruppo AndDev.it LOGTFO) - Android Developers Italia

Offline mimmog

  • Utente senior
  • ****
  • Post: 731
  • Respect: +11
    • MisterX_Dev
    • Mostra profilo
  • Dispositivo Android:
    Galaxy Note e Galaxy Nexus
  • Play Store ID:
    MisterX_Dev
  • Sistema operativo:
    Windows 7
Re:[Medio] Inserire il controllo di licenza nella propria applicazione
« Risposta #11 il: 12 Aprile 2011, 13:46:14 CEST »
0
In effetti questo codice fa quello che dici...se non c'è connessione dice che il prodotto non è licenziato altrimenti, se c'è  connessione, memorizza i dati nelle preferences. L'unica cosa che non mi piace di questo codice è che, se non c'è connessione, dice all'utente (che magari ha comprato realmente l'applicazione) che la copia è stata scaricata illegalmente. Ho cambiato il messaggio aggiungendo che,  qualora non vi fosse un connettività, il problema potrebbe essere quello e di riprovare

Offline mimmog

  • Utente senior
  • ****
  • Post: 731
  • Respect: +11
    • MisterX_Dev
    • Mostra profilo
  • Dispositivo Android:
    Galaxy Note e Galaxy Nexus
  • Play Store ID:
    MisterX_Dev
  • Sistema operativo:
    Windows 7
Re:[Medio] Inserire il controllo di licenza nella propria applicazione
« Risposta #12 il: 12 Aprile 2011, 16:04:59 CEST »
0
Però dimenticavo l'ultima domanda !!! secondo voi se dovessi regalare l'applicazione a qualcuno gli dovrei togliere il controllo sul certificato ? (però poi quando aggiorna dal market ?) oppure dovrei aggiungere la sua email nell'area dei tester ?  :-\ :-\

Offline mimmog

  • Utente senior
  • ****
  • Post: 731
  • Respect: +11
    • MisterX_Dev
    • Mostra profilo
  • Dispositivo Android:
    Galaxy Note e Galaxy Nexus
  • Play Store ID:
    MisterX_Dev
  • Sistema operativo:
    Windows 7
Re:[Medio] Inserire il controllo di licenza nella propria applicazione
« Risposta #13 il: 13 Aprile 2011, 13:13:59 CEST »
+1
Rispondo da solo al mio quesito, per chi avesse lo stesso problema, in pratica quando si vuole regalare l'applicazione a qualcuno la si fa comprare e poi gli si fa un rimborso  8-)

Offline ALEX88-ANDR0!D

  • Utente normale
  • ***
  • Post: 173
  • The Special One
  • Respect: +13
    • Google+
    • droidev88
    • Mostra profilo
  • Dispositivo Android:
    HTC DESIRE HD
  • Sistema operativo:
    WINDOWS 7
Re:[Medio] Inserire il controllo di licenza nella propria applicazione
« Risposta #14 il: 13 Aprile 2011, 16:35:54 CEST »
+1
ottimo tutorial , lo implementerò sicuramente nella mia app ... , un grazie anche a  mimmog , per questioni app in regalo e sopratuto la parte relativa a problemi e relativa soluzione se il dispositivo è offline la prima volta che l'app deve controllare se l'app è stata acquistata o meno . ciao
È stata trovata una soluzione al tuo problema?
Evidenzia il post più utile premendo . È un ottimo modo per ringraziare chi ti ha aiutato ;).
E se hai aperto tu il thread marcalo come risolto cliccando !