Использование нового идентификатора рекламодателя Android внутри SDK

Имеет большой смысл, что в Android SDK для рекламы будет использоваться новый идентификатор рекламодателя Android.

Кажется, что вы можете получить идентификатор только с помощью службы Google SDK, как упомянуто здесь: http://developer.android.com/google/play-services/id.html.

Использование SDK Google Play Services требует ссылки на проект Google-Play-Services_lib, что вызывает несколько проблем:

  1. Многие SDK являются банками, то есть они не могут использовать google-play-services_lib как есть (потому что они не могут включать ресурсы).
  2. Если мне нужен только идентификатор рекламодателя, мне нужно добавить google-play-services_lib в мой проект, который весит почти 1 МБ.

Есть ли способ получить только идентификатор рекламодателя, не используя ресурсы?

5 ответов

Решение

Я столкнулся с той же проблемой: если вам нужен рекламодатель, вы можете напрямую взаимодействовать со службой Google Play с помощью Intent. Пример пользовательского класса:

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;
    }
}
}

Убедитесь, что вы не вызываете это из основного потока пользовательского интерфейса. Например, используйте что-то вроде:

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();

Решение Адриана превосходно, и я использую его сам.

Однако сегодня я обнаружил, что в нем есть ошибка, когда на устройстве не установлены Google Play Services. Вы получите сообщение об утечке 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");
}

Сюда Context.unbindService будет называться, даже если Context.bindService возвращается false,

ПРИМЕЧАНИЕ. Мой ответ для Gradle устарел, поскольку теперь вы можете выбирать, какие части библиотеки GooglePlayServices вы хотите включить в свой проект

В последнее время я столкнулся с той же проблемой, когда проект, над которым я работал, достиг предела в 65 тысяч декс.

Вот как я это решил:

  • Перейдите на 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] процесс [rulesFile] [inJar] [outJar]

  • Вы можете найти более подробную информацию о командах и правилах JarJar Links здесь: https://code.google.com/p/jarjar/wiki/CommandLineDocs

  • Просто, чтобы привести пример, команда, которую я должен был написать, выглядела так (измените свою согласно вашим именам файлов):

java -jar jarjar-1.4.jar обработать rules.txt google-play-services.jar google-play-services-lite.jar

  • Выполните команду.

ЧТО ОНО ДЕЛАЕТ:

  • Команда создаст новый архив Java (*.jar) в рабочей папке, который будет содержать только класс, необходимый для получения идентификатора вашего рекламодателя и его зависимостей. Итак, google-play-services.jar снизится с 2,2 Мб до ~50 Кб

КАК ЭТО ИСПОЛЬЗОВАТЬ:

  • Импортируйте сервисы Google Play из SDK в свой проект, как обычно, обязательно скопируйте его в свою рабочую область. В папке libs замените google-play-services.jar на созданный ранее jar-файл.

  • Если вы там, вы можете удалить ресурсы, чтобы освободить еще 0,5 МБ. Обязательно сохраните values ​​/ common_strings.xml и values ​​/ version.xml.

  • Не забудьте добавить метаданные манифеста для сервисов Google Play.

Это помогло мне уменьшить размер проекта более чем на 2,5 мегабайта и не превысить ограничение на классы и методы dex в 65 тыс., В то же время имея возможность доступа к идентификатору рекламодателя Google.

Надеюсь, это тебе тоже поможет.

MoPub и несколько других крупных игроков не включают GPS в свои SDK. Со страницы помощи MoPub:

MoPub SDK не требует Google Play Services. Если он у вас установлен, мы автоматически будем использовать новый идентификатор Google Advertising ID. Если вы НЕ устанавливаете Сервисы Google Play, мы продолжим передавать старый идентификатор Android. Обратите внимание, что все издатели должны использовать GPS в своем приложении к 1 августа, чтобы предотвратить отклонение их приложений в Google Play Store.

Проверьте эту ссылку для более подробной информации:

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

Надеюсь это поможет.

Единственный поддерживаемый метод доступа к Рекламному идентификатору - прямая ссылка на SDK Play Services и доступ к Рекламному идентификатору через эти API. Google не рекомендует и не поддерживает какие-либо обходные пути, позволяющие избежать прямого доступа к API-интерфейсам Play Services, поскольку он нарушает функциональность, с которой сталкиваются пользователи (например, обработку ошибок в случаях, когда приложение Play Services на устройстве устарело), ​​и его поведение будет непредсказуемым в будущем Play Сервисы релизов.

Правила программы Google Play для разработчиков требуют, чтобы вы получали доступ к API Google Play только авторизованным способом.

Другие вопросы по тегам