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

时间:2013-11-20 13:38:47

标签: android uniqueidentifier google-play-services advertising

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

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

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

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

5 个答案:

答案 0 :(得分:38)

我遇到了同样的问题,如果您只是需要广告客户,您可以直接使用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;
    }
}
}

确保您没有从主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();

答案 1 :(得分: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内部粘贴文本(不带引号):

  

&#34;保留com.google.android.gms.ads.identifier.AdvertisingIdClient&#34;

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

  • 打开命令提示符文件并更改工作文件夹的路径。在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百万的项目规模,并且能够访问Google广告客户ID,并保持在65k dex类和方法限制之下。

希望它也会帮助你。

答案 2 :(得分:6)

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

但是,今天我发现当设备上没有安装Google Play服务时,它有一个错误。当您的活动/服务停止时,您将收到有关泄露ServiceConnection的消息。这实际上是Context.bindService中的一个错误:当绑定到服务失败时(在这种情况下,因为未安装Google Play服务),Context.bindService返回false,但它不会清除对{的引用{1}},即使该服务不存在,也希望您拨打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"); } 返回Context.unbindService,也会调用Context.bindService

答案 3 :(得分:1)

MoPub和其他一些大型玩家未将GPS纳入他们的SDK。从MoPub的帮助页面:

  

MoPub SDK不需要Google Play服务。如果您已安装,我们将自动使用新的Google广告ID。如果您不安装Google Play服务,我们会继续传递旧的Android ID。请注意,所有发布商都需要在8月1日之前在其应用中使用GPS,以防止他们的应用被Google Play商店拒绝

查看此链接以获取更多详细信息:

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

希望这有帮助。

答案 4 :(得分:-1)

唯一受支持的访问广告ID的方法是直接链接到Play服务SDK并通过这些API访问广告ID。 Google不建议或支持任何避免直接访问Play服务API的解决方法,因为它会破坏面向用户的功能(例如,如果设备上的Play服务应用已过时,则会出现错误处理),并且其行为将无法预测服务发布。

Google Play Developer Program Policies要求您仅以授权方式访问Google Play API。