web-dev-qa-db-fra.com

Utilisation du nouveau Android adnonceur id à l'intérieur d'un SDK

Cela donne beaucoup de sens que Android adks utilisera l'identifiant annonceur d'Android.

Il semble que vous ne puissiez obtenir que l'identifiant en utilisant le SDK Google Services, comme mentionné ici: http://developer.android.com/google/play-services/id.html .

En utilisant le SDK Google Play Services, nécessite de référencer le projet Google-Play-Services_LIB, qui provoque plusieurs problèmes:

  1. Beaucoup de SDK sont des pots, ce qui signifie qu'ils ne peuvent pas utiliser Google-Play-Services_Lib telle est (car ils ne peuvent pas inclure les ressources).
  2. Si je veux seulement que l'identifiant de l'annonceur, je dois ajouter Google-Play-Services_Lib à mon projet, ce qui pèse près de 1 Mo.

Y a-t-il un moyen de recevoir uniquement l'identifiant de l'annonceur, sans utiliser de ressources?

23
dors

J'ai couru dans le même problème, si vous avez juste besoin de l'annonceur, vous pouvez interagir avec le service Google Play directement à l'aide d'une intention. Exemple de classe personnalisée:

import Java.io.IOException;
import Java.util.concurrent.LinkedBlockingQueue;
import Android.content.ComponentName;
import Android.content.Context;
import Android.content.Intent;
import Android.content.ServiceConnection;
import Android.content.pm.PackageManager;
import Android.os.IBinder;
import Android.os.IInterface;
import Android.os.Looper;
import Android.os.Parcel;
import Android.os.RemoteException;

public final class AdvertisingIdClient {

public static final class AdInfo {
    private final String advertisingId;
    private final boolean limitAdTrackingEnabled;

    AdInfo(String advertisingId, boolean limitAdTrackingEnabled) {
        this.advertisingId = advertisingId;
        this.limitAdTrackingEnabled = limitAdTrackingEnabled;
    }

    public String getId() {
        return this.advertisingId;
    }

    public boolean isLimitAdTrackingEnabled() {
        return this.limitAdTrackingEnabled;
    }
}

public static AdInfo getAdvertisingIdInfo(Context context) throws Exception {
    if(Looper.myLooper() == Looper.getMainLooper()) throw new IllegalStateException("Cannot be called from the main thread");

    try { PackageManager pm = context.getPackageManager(); pm.getPackageInfo("com.Android.vending", 0); }  
    catch (Exception e) { throw e; }

    AdvertisingConnection connection = new AdvertisingConnection();
    Intent intent = new Intent("com.google.Android.gms.ads.identifier.service.START");
    intent.setPackage("com.google.Android.gms");
    if(context.bindService(intent, connection, Context.BIND_AUTO_CREATE)) {
        try {
            AdvertisingInterface adInterface = new AdvertisingInterface(connection.getBinder());
            AdInfo adInfo = new AdInfo(adInterface.getId(), adInterface.isLimitAdTrackingEnabled(true));
            return adInfo;
        } catch (Exception exception) {
            throw exception;
        } finally {
            context.unbindService(connection);
        }
    }       
    throw new IOException("Google Play connection failed");     
}

private static final class AdvertisingConnection implements ServiceConnection {
    boolean retrieved = false;
    private final LinkedBlockingQueue<IBinder> queue = new LinkedBlockingQueue<IBinder>(1);

    public void onServiceConnected(ComponentName name, IBinder service) {
        try { this.queue.put(service); }
        catch (InterruptedException localInterruptedException){}
    }

    public void onServiceDisconnected(ComponentName name){}

    public IBinder getBinder() throws InterruptedException {
        if (this.retrieved) throw new IllegalStateException();
        this.retrieved = true;
        return (IBinder)this.queue.take();
    }
}

private static final class AdvertisingInterface implements IInterface {
    private IBinder binder;

    public AdvertisingInterface(IBinder pBinder) {
        binder = pBinder;
    }

    public IBinder asBinder() {
        return binder;
    }

    public String getId() throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        String id;
        try {
            data.writeInterfaceToken("com.google.Android.gms.ads.identifier.internal.IAdvertisingIdService");
            binder.transact(1, data, reply, 0);
            reply.readException();
            id = reply.readString();
        } finally {
            reply.recycle();
            data.recycle();
        }
        return id;
    }

    public boolean isLimitAdTrackingEnabled(boolean paramBoolean) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        boolean limitAdTracking;
        try {
            data.writeInterfaceToken("com.google.Android.gms.ads.identifier.internal.IAdvertisingIdService");
            data.writeInt(paramBoolean ? 1 : 0);
            binder.transact(2, data, reply, 0);
            reply.readException();
            limitAdTracking = 0 != reply.readInt();
        } finally {
            reply.recycle();
            data.recycle();
        }
        return limitAdTracking;
    }
}
}

Assurez-vous de ne pas l'appeler à partir du fil principal de l'UI. Par exemple, utilisez quelque chose comme:

new Thread(new Runnable() {        
    public void run() {
        try {
            AdInfo adInfo = AdvertisingIdClient.getAdvertisingIdInfo(context);
            advertisingId = adInfo.getId();
            optOutEnabled = adInfo.isLimitAdTrackingEnabled();
        } catch (Exception e) {
            e.printStackTrace();                            
        }                       
    }
}).start();
41
Adrian

La solution d'Adrian est excellente et je l'utilise moi-même.

Cependant, aujourd'hui, j'ai découvert qu'il a un bogue lorsque Google Play Services n'est pas installé sur l'appareil. Vous recevrez un message sur la fuite d'un ServiceConnection lorsque votre activité/service est arrêté. C'est en fait un bogue dans Context.bindService: lorsque la liaison au service échoue (dans ce cas, car Google Play Services n'est pas installé), Context.bindService retourne faux, mais cela n'efface pas la référence au ServiceConnection et vous attend que vous appelez Context.unbindService Même si le service n'existe pas!

La solution de contournement doit changer le code de getAdvertisingIdInfo comme ceci:

public static AdInfo getAdvertisingIdInfo(Context context) throws Exception {
    if(Looper.myLooper() == Looper.getMainLooper())
        throw new IllegalStateException("Cannot be called from the main thread");

    try {
        PackageManager pm = context.getPackageManager();
        pm.getPackageInfo("com.Android.vending", 0);
    } catch(Exception e) {
        throw e;
    }

    AdvertisingConnection connection = new AdvertisingConnection();
    Intent intent = new Intent("com.google.Android.gms.ads.identifier.service.START");
    intent.setPackage("com.google.Android.gms");
    try {
        if(context.bindService(intent, connection, Context.BIND_AUTO_CREATE)) {
            AdvertisingInterface adInterface = new AdvertisingInterface(connection.getBinder());
            AdInfo adInfo = new AdInfo(adInterface.getId(), adInterface.isLimitAdTrackingEnabled(true));
            return adInfo;
        }
    } catch(Exception exception) {
        throw exception;
    } finally {
        context.unbindService(connection);
    }
    throw new IOException("Google Play connection failed");
}

De cette façon Context.unbindService sera appelé même si Context.bindService retourne false.

7
Avi

Remarque: ma réponse est obsolète pour Gradle depuis maintenant que vous pouvez choisir les parties de la bibliothèque GooglePlayServices que vous souhaitez inclure dans votre projet.

J'ai rencontré le même problème récemment lorsque le projet que je travaillais sur la limite de 65k Dex.

Voici comment j'ai résolu ce problème:

  • Allez à https://code.google.com/p/jarjar/downloads/list et téléchargez les derniers liens JAR JAR dans le format .jar. Placez le fichier dans un dossier de travail. Pour cet exemple, je vais utiliser le bureau.

  • Allez sur [PATHIER SDK Android]\Extras\Google\Google_play_services\libproject\google-play-services_lib\libs et copiez Google-play-services.jar dans le même dossier de travail.

  • Dans le même dossier, effectuez un fichier texte nommé Règles.txt (le nom n'a pas d'importance).

  • À l'intérieur des règles.txt coller le texte (sans les citations):

"Garder com.google.android.gms.ads.idIdidIdidIdidIdidIdidIdidingSiClient"

  • Si vous souhaitez que d'autres classes vous voulez conserver, vous pouvez les ajouter ici.

  • Ouvrez un fichier d'invite de commande et modifiez le chemin d'accès à votre dossier de travail. Sous Windows, utilisez la commande [CD].

  • Écrivez la commande suivante:

Java -Jar [Archives Jarjar] Processus [Rulesfile] [Injur] [Outjar]

  • Vous trouverez plus de détails sur les commandes et les règles de Jarjar Links ici: https://code.google.com/p/jarjar/wiki/commandLinedocs

  • Juste pour donner un exemple, la commande que je devais écrire ressemblait à ceci (changez la vôtre en fonction de vos noms de fichiers):

Java -Jar Jarjar-1.4.jar Règles de processus.txt google-play-services.jar google-play-services-lite.jar

  • Exécuter la commande.

CE QU'IL FAIT:

  • La commande générera un nouveau Java archive (* .jar) dans le dossier de travail qui ne contiendra que la classe nécessaire pour obtenir votre identifiant d'annonceur et ses dépendances. Ainsi, les services Google-Play-Services. .jar va descendre de 2,2 Mo à ~ 50kb

COMMENT L'UTILISER:

  • Importez Google Play Services à partir du SDK dans votre projet comme d'habitude, assurez-vous de la copier dans votre espace de travail. Dans le dossier Libs, remplacez le google-play-services.jar avec le pot que vous avez généré précédemment.

  • Si vous êtes présent, vous pouvez aussi supprimer les ressources pour libérer une autre 0,5 Mo. Assurez-vous de garder les valeurs/common_strings.xml et valeurs/version.xml.

  • N'oubliez pas d'ajouter des métadonnées manifestes pour Google Play Services.

Cela m'a aidé à réduire la taille du projet avec plus de 2,5 Mo et de rester sous les classes de 65k Dex et la limite de méthodes tout en pouvant accéder à l'ID Google Annonceur.

J'espère que ça va vous aider aussi.

6
Andrei Lupsa

Mopub et quelques autres gros joueurs ne comprennent pas GPS dans leurs SDK. De la page d'aide de Mopub:

le MOPUB SDK n'exige pas Google Play Services. Si vous l'avez installé, nous utiliserons automatiquement le nouvel identifiant de publicité Google. Si vous n'installez pas Google Play Services, nous continuerons à passer l'ancien Android ID. Notez que tous les éditeurs doivent utiliser GPS dans leur application avant le 1er août pour empêcher que leurs applications ne soient rejetées par Le google Play Store

Vérifiez ce lien pour beaucoup plus de détails:

http://help.mopub.com/customer/portal/articles/1523610-google-advertining-id-faqs

J'espère que cela t'aides.

1
ankit