21

Android 광고 SDK는 Android의 새 광고주 ID를 사용하는 것이 합리적입니다.SDK 안의 새로운 Android 광고주 ID 사용

여기에 언급 된 것처럼 Google 서비스 SDK를 사용하여 ID를 얻을 수있는 것 같습니다 : http://developer.android.com/google/play-services/id.html. 구글 플레이 서비스 SDK를 사용

, 여러 가지 문제를 야기 구글 플레이-services_lib 프로젝트를 참조 할 필요 :

  1. 의 SDK의 많은 사람들이 구글 플레이-services_lib을 사용할 수 없습니다 의미 항아리입니다 (자원을 포함 할 수 없으므로) 그대로입니다.
  2. 광고주 ID 만 있으면 Google 프로젝트에 google-play-services_lib를 추가해야합니다.이 프로젝트의 가중치는 거의 1MB입니다.

리소스를 사용하지 않고 광고주 ID 만 얻을 수있는 방법이 있습니까?

답변

34

동일한 문제가 발생했습니다. 광고주 ID가 필요한 경우 의도를 사용하여 직접 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 스레드에서 호출하지 않아야합니다. 직접 플레이 서비스 SDK에 연결하고 해당 API를 통해 광고 ID에 액세스하여 광고 ID에 액세스

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

사용하는 것이 위험합니다. 어디서나 문서화 된 것입니까? – Javanator

+0

위험한 이유는 무엇입니까? https://developer.android.com/google/play-services/id.html – sirvon

+0

com.google.android.gms.ads.identifier.AdvertisingIdClient.getAdvertisingIdInfo에서 다음 오류가 발생합니다. ** java.lang.NoSuchFieldError : android.content.pm.PackageInfo.signatures ** 어떻게해야합니까? – mdavid

-1

지원되는 유일한 방법입니다 : 예를 들어, 같은 것을 사용합니다. Play Services API가 사용자 인터페이스 (예 : 기기의 Play 서비스 앱이 오래되어 발생하는 경우 오류 처리)를 위반하고 이후 Play에서 해당 동작을 예측할 수 없으므로 Play 서비스 API에 직접 액세스하지 못하도록하는 방법을 Google에서 권장하거나 지원하지 않습니다 서비스 릴리스.

Google Play Developer Program Policies은 인증 된 방식으로 만 Google Play API에 액세스해야합니다.

+0

감사합니다. 에릭, 알아두면 좋을 것 같습니다. 그러나 당신의 응답은 @dors와 우리 대부분이 가진 두 가지 문제에 대한 해결책을 제공하지 않습니다. 더 나은 접근 방법이 있다면 알려주십시오. – Adrian

1

MoPub 및 다른 몇몇 대형 플레이어는 GPS를 SDK에 포함하지 않습니다.

the MoPub SDK does not require Google Play Services. If you have it installed, we will automatically use the new Google Advertising ID. If you do NOT install Google Play Services, we will continue to pass the old Android ID. Note that all publishers need to use GPS in their app by August 1 to prevent their apps from being rejected by the Google Play Store

확인 더 많은 세부 사항에 대한 링크 :이 도움이

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

희망 MoPub에서의 도움말 페이지에서.

6

참고 : 내 대답은 당신이 당신의 프로젝트에 포함 할 이는 GooglePlayServices 라이브러리의 일부를 선택할 수 있습니다 지금부터 Gradle을위한 오래된

내가 작업 한 프로젝트가 도착했을 때 나는 최근에 같은 문제로 실행

65k dex 한도.

여기에 내가 그것을 해결 방법은 다음과 같습니다 https://code.google.com/p/jarjar/downloads/list

  • 이동과의 .jar 형식의 최신 항아리 항아리 링크를 다운로드합니다. 파일을 작업 폴더에 넣습니다. 이 예제에서는 데스크탑을 사용합니다.

  • [Android SDK 경로] \ extras \ google \ google_play_services \ libproject \ google-play-services_lib \ libs로 이동하여 google-play-services.jar을 동일한 작업 폴더로 복사하십시오.

  • 같은 폴더에 rules.txt라는 텍스트 파일을 만듭니다 (이 이름은 별 의미가 없습니다). 규칙 .txt (따옴표없이) 텍스트를 붙여 내부

  • : 유지하려는 다른 클래스를 원하는 경우에

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

  • , 당신은 여기에 추가 할 수 있습니다.

  • 명령 프롬프트 파일을 열고 작업 폴더의 경로를 변경하십시오. Windows에서는 [cd] 명령을 사용하십시오. 당신은 JarJar 링크 명령을 여기에 규칙에 대한 자세한 내용은 찾을 수 있습니다

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

  • 명령을 실행합니다.

IT가하는 일 :

  • 명령은 새로운 자바 아카이브를 생성합니다 (*의 .jar) 광고주 ID와의 종속성을 얻기 위해 필요한 경우에만 클래스를 포함 할 작업 폴더입니다. 그래서, 구글 플레이-services.jar는

는 사용 방법에 50KB ~ 2.2 메가에서 아래로 이동합니다 :

  • 가져 오기 구글 플레이 서비스를 SDK에서 프로젝트에 평소와 같이, 그것을 작업 공간으로 복사하십시오. libs 폴더에서 이전에 생성 한 jar로 google-play-services.jar를 대체하십시오.

  • 거기에 계시다면 리소스를 삭제하여 0.5MB를 더 확보하십시오. 값/common_strings.xml 및 values ​​/ version.xml을 유지해야합니다.

  • Google Play 서비스의 매니페스트 메타 데이터를 추가하는 것을 잊지 마세요.

은 구글의 광고주 ID에 액세스 할 수있는 동안 나 이상 2.5 MB의 프로젝트 크기를 줄일 수와 65K 덱스 클래스와 메소드에서 머물 제한 도왔다.

희망도 도움이 될 것입니다.

3

애드리안 솔루션이 우수하며 직접 사용합니다.

그러나 Google Play 서비스가 기기에 설치되어 있지 않으면 버그가 있음을 발견했습니다. 활동/서비스가 중단 될 때 ServiceConnection의 누설에 관한 메시지가 표시됩니다. 실제로 Context.bindService의 버그입니다. 서비스에 바인딩하지 못했을 때 (이 경우 Google Play 서비스가 설치되지 않았기 때문에) Context.bindService은 false를 반환하지만 ServiceConnection에 대한 참조를 지우지 않으며 Context.unbindService으로 전화 할 것으로 예상됩니다. 서비스는 존재하지 않지만!

해결 방법은 다음과 같이 getAdvertisingIdInfo의 코드를 변경하는 것입니다 Context.unbindService이 경우에도 Context.bindService 반환 false 호출됩니다

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

그런 식으로.