15

When implementing AdMob you can define an array of test IDs so that Google knows to serve test ads to these devices, instead of real ads. However, it requires "hashed device IDs". This seems a little vague to me. What ID are they talking about and what hashing method do they expect me to use?

I'm talking about the bit that should go in here:

request.testDevices = @[ @"hashed-device-id" ];
Neeku
  • 3,646
  • 8
  • 33
  • 43
Jasper Kennis
  • 3,225
  • 6
  • 41
  • 74

7 Answers7

35

I figured out how to generate the AdMob device ID: Just compute the MD5 of the advertisingIdentifier.

#import <AdSupport/ASIdentifierManager.h>
#include <CommonCrypto/CommonDigest.h>

- (NSString *) admobDeviceID
{
    NSUUID* adid = [[ASIdentifierManager sharedManager] advertisingIdentifier];
    const char *cStr = [adid.UUIDString UTF8String];
    unsigned char digest[16];
    CC_MD5( cStr, strlen(cStr), digest );

    NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];

    for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
        [output appendFormat:@"%02x", digest[i]];

    return  output;

}
Felix
  • 35,354
  • 13
  • 96
  • 143
  • Ha, that is great! Will give you the 100 bounty, you missed it by less then an hour. – Jasper Kennis Jul 29 '14 at 12:25
  • @phix23 I am trying same thing for FBAudienceNetwork and its not working. Any idea what changes I will have to make? – ibnetariq Nov 17 '15 at 15:30
  • 1
    I had to use `NSString *UDIDString = [[[UIDevice currentDevice] identifierForVendor] UUIDString];` instead of the advertisingIdentifer. At least on my device ad tracking is disabled. – RcoderNY Sep 13 '21 at 17:03
  • I don't know if things have changed, but when I use this for GoogleMobileAds, the SDK prints a different identifier to the console and prompts to use that one... Any ideas? Thanks – Reanimation Jun 08 '22 at 06:56
15

Start the app without setting the test devices and have a look at the debugger output. There you'll find a message like:

<Google> To get test ads on this device, call: request.testDevices = @[ @"49cd348fa9c01223dd293bcce92f1e08" ];

I guess the message is self explaining.

Codo
  • 75,595
  • 17
  • 168
  • 206
  • 1
    Yeah I know that, but then I have to connect the devises of all test users to get their id's, and since some of them are not based in my country, that's posing a problem. So I was looking for a way to generate the hash on the fly. – Jasper Kennis Jul 16 '14 at 07:26
3

I get the device id in such way: Swift 3.0

Don't forget to add #import <CommonCrypto/CommonCrypto.h> to the ObjC-Swift bridging header that Xcode creates.

extension String
{
    var md5: String! {
        let str = self.cString(using: String.Encoding.utf8)
        let strLen = CC_LONG(self.lengthOfBytes(using: String.Encoding.utf8))
        let digestLen = Int(CC_MD5_DIGEST_LENGTH)
        let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)

        CC_MD5(str!, strLen, result)

        let hash = NSMutableString()
        for i in 0..<digestLen {
            hash.appendFormat("%02x", result[i])
        }

        result.deallocate(capacity: digestLen)

        return String(format: hash as String)
    }
}

import AdSupport
...
{
  var uuid: UUID = ASIdentifierManager.shared().advertisingIdentifier
  print("\(uuid.uuidString.md5)")
}

The extension for String class was taken here.

Community
  • 1
  • 1
elbik
  • 1,749
  • 2
  • 16
  • 21
2

Check out ASIdentifierManager. It is created specifically for accessing unique device identifiers to be used for serving ads. You can get a unique identifier for the current device like so:

ASIdentifierManager *manager = [ASIdentifierManagerClass sharedManager];
NSString *uniqueDeviceId = [[manager advertisingIdentifier] UUIDString];

The alternative way to access the unique identifier for a device is:

NSString *uniqueDeviceId = [[UIDevice currentDevice] identifierForVendor];

However, as per Apple's documentation, identifierForVendor is not intended to be used for advertising purposes.

Michael Frederick
  • 16,664
  • 3
  • 43
  • 58
  • Yes, I got that far too. Only it seems that Google hashes this string, because I can't get it to return anything formatted like `49cd348fa9c01223dd293bcce92f1e08`. So I'm especially interested in how to hash it. – Jasper Kennis Jul 28 '14 at 09:57
2

For some reason I was not seeing the "To get test ads..." in the Console. In any case, you might want your beta testers to not have to delve into the darkness to find this and send it to you to hard-code. Here is Felix's (correct, thankyouverymuch) answer in Swift 3 version, using code from http://iosdeveloperzone.com/2014/10/03/using-commoncrypto-in-swift/

Note that you will have to have a bridging header with the following:

#import <CommonCrypto/CommonCrypto.h>

Here's the hash function:

func md5(_ string: String) -> String {
    let context = UnsafeMutablePointer<CC_MD5_CTX>.allocate(capacity: 1)
    var digest = Array<UInt8>(repeating:0, count:Int(CC_MD5_DIGEST_LENGTH))
    CC_MD5_Init(context)
    CC_MD5_Update(context, string, CC_LONG(string.lengthOfBytes(using: String.Encoding.utf8)))
    CC_MD5_Final(&digest, context)
    context.deallocate(capacity: 1)
    var hexString = ""
    for byte in digest {
       hexString += String(format:"%02x", byte)
    }
    return hexString
}

And here it is put to use in Google's sample code:

func createAndLoadInterstitial() {
    interstitial = GADInterstitial(adUnitID: G.googleMobileTestAdsId)
    interstitial.delegate = self
    let request = GADRequest()

    // Here's the magic.
    let id = ASIdentifierManager.shared().advertisingIdentifier!
    let md5id = md5(id.uuidString)

    // And now we use the magic.
    request.testDevices = [ kGADSimulatorID, md5id ]
    interstitial.load(request)
}
Andrew Duncan
  • 3,553
  • 4
  • 28
  • 55
  • Perfect Answer! Saved me. Thank you! One question, should I remove the test devices before the app goes on the store? – Jeff Mar 29 '17 at 23:57
  • 1
    I see in my code that I did remove the test devices for a release app, but I believe that is not necessary. I think they are no-ops for a release app. But I can't find where I read that. On the Intenets somewhere. – Andrew Duncan Mar 31 '17 at 02:08
0

In Swift 2, Xcode 7.3 I did this and the ad banner now shows test ad when I run in simulator:

    let request = GADRequest()
    request.testDevices = [kGADSimulatorID]
    bannerView.loadRequest(request)
Jervisbay
  • 149
  • 1
  • 1
  • 6
-1

find some log like following

 <Google> To get test ads on this device, call: request.testDevices = @[ @"7505289546eeae64cd2fxxxxxa2b94" ];

or

Use AdRequest.Builder.addTestDevice("AEC1F310D326xxxxx37BC") to get test ads on this device.
ygweric
  • 1,002
  • 1
  • 7
  • 22