在SDK中使用新的Android广告商ID

dor*_*ors 23 android ads uniqueidentifier google-play-services

Android广告SDK将使用Android的新广告客户ID非常有意义.

您似乎只能通过使用google服务sdk来获取ID,如下所述:http: //developer.android.com/google/play-services/id.html.

使用google play服务sdk,需要引用google-play-services_lib项目,这会导致一些问题:

  1. 很多SDK都是jar,这意味着它们不能按原样使用google-play-services_lib(因为它们不能包含资源).
  2. 如果我只想要广告客户ID,我需要将google-play-services_lib添加到我的项目中,该项目的权重接近1 MB.

有没有办法只获取广告客户ID,而不使用资源?

Adr*_*ian 40

我遇到了同样的问题,如果您只需要广告客户,您可以直接使用Intent与Google Play服务进行互动.自定义类的示例:

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;
    }
}
}
Run Code Online (Sandbox Code Playgroud)

确保您没有从主UI线程调用它.例如,使用以下内容:

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();
Run Code Online (Sandbox Code Playgroud)


Avi*_*Avi 7

Adrian的解决方案很棒,我自己也用它.

但是,今天我发现当设备上没有安装Google Play服务时,它有一个错误.ServiceConnection当您的活动/服务停止时,您将收到有关泄漏信息的消息.这实际上是一个错误Context.bindService:当绑定到服务失败时(在这种情况下,因为没有安装Google Play服务),Context.bindService返回false,但它不会清除对该引用的引用ServiceConnection,并且Context.unbindService即使服务没有,也希望您调用不存在!

解决方法是更改​​这样的代码getAdvertisingIdInfo:

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");
}
Run Code Online (Sandbox Code Playgroud)

Context.unbindService即使Context.bindService返回,也会调用这种方式false.


And*_*psa 6

注意:我的答案已过时Gradle,因为现在您可以选择要包含在项目中的GooglePlayServices库的哪些部分

当我正在进行的项目达到65k dex限制时,我最近遇到了同样的问题.

这是我如何解决它:

  • 转到https://code.google.com/p/jarjar/downloads/list并以.jar格式下载最新的Jar jar链接.将文件放在工作文件夹中.对于这个例子,我将使用桌面.

  • 转到[Android SDK路径]\extras\google\google_play_services\libproject\google-play-services_lib\libs并将google-play-services.jar复制到同一工作文件夹.

  • 在同一文件夹中创建一个名为rules.txt的文本文件(名称并不重要).

  • 在rules.txt里面粘贴文本(不带引号):

"keep com.google.android.gms.ads.identifier.AdvertisingIdClient"

  • 如果您想要保留其他课程,可以在此处添加.

  • 打开命令提示符文件并更改工作文件夹的路径.在Windows上使用[cd]命令.

  • 编写以下命令:

java -jar [jarjar archive] process [rulesFile] [inJar] [outJar]

java -jar jarjar-1.4.jar process rules.txt google-play-services.jar google-play-services-lite.jar

  • 执行命令.

它能做什么:

  • 该命令将在工作文件夹中生成一个新的java归档文件(*.jar),该文件夹仅包含获取广告客户ID及其依赖项所需的类.因此,google-play-services.jar将从2.2 Mb下降到~50kb

如何使用它:

  • 像往常一样将sdk中的google play服务导入到项目中,请务必将其复制到工作区中.在libs文件夹中,将google-play-services.jar替换为您之前生成的jar.

  • 如果你在那里,你也可以删除资源,以释放另一个0.5 MB.确保保留values/common_strings.xml和values/version.xml.

  • 不要忘记为Google Play服务添加清单元数据.

这有助于我减少超过2.5 MB的项目规模,并在能够访问Google广告客户ID的同时保持在65k dex类和方法限制之下.

希望它也能帮到你.