最近苹果对于没有使用广告的应用却调用了advertisingIdentifier的话会被决绝申请。
被Reject的内容如下:
We found your app uses the iOS Advertising Identifier but does not include ad functionality. This does not comply with the terms of the iOS Developer Program License Agreement, as required by the App Store Review Guidelines.
主要的原因是Unity生成的Xcode项目里有一个文件调用了advertisingIdentifier,如果你的项目没有使用广告服务的话,请手动禁止调用。
步骤如下:
- 首先在Xcode项目中找到DeviceSettings.mm文件
- 打开文件并且删除下面的函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
static
id
QueryASIdentifierManager
(
)
{
<
.
.
>
}
static
void
QueryAdID
(
)
{
<
.
.
>
}
static
void
QueryAdTracking
(
)
{
<
.
.
>
}
|
- 将下面的静态变量删除
1
2
3
|
static
NSString*
_ADID
=
nil
;
static
bool
_AdTrackingEnabled
=
false
;
|
- 找到对应的代码修改为如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
extern
"C"
const
char
*
UnityAdvertisingIdentifier
(
)
{
return
NULL
;
}
extern
"C"
bool
UnityAdvertisingTrackingEnabled
(
)
{
return
false
;
}
static
void
QueryDeviceID
(
)
{
if
(
_DeviceID
==
nil
)
{
#if UNITY_PRE_IOS7_TARGET
if
(
!
_ios70orNewer
)
_InitDeviceIDPreIOS7
(
)
;
#endif
// first check vendor id
if
(
_DeviceID
==
nil
)
{
QueryVendorID
(
)
;
_DeviceID
=
_VendorID
;
}
}
}
|
顺便贴出一下我修改之后的DeviceSettings.mm文件如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
|
#include <sys/types.h>
#include <sys/sysctl.h>
#if UNITY_PRE_IOS7_TARGET
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <CommonCrypto/CommonDigest.h>
static
void
_InitDeviceIDPreIOS7
(
)
;
#endif
#include "DisplayManager.h"
static
NSString*
_DeviceID
=
nil
;
static
NSString*
_VendorID
=
nil
;
static
NSString*
_DeviceName
=
nil
;
static
NSString*
_SystemName
=
nil
;
static
NSString*
_SystemVersion
=
nil
;
static
NSString*
_DeviceModel
=
nil
;
static
int
_DeviceGeneration
=
deviceUnknown
;
static
float
_DeviceDPI
=
-
1.0f
;
static
void
QueryDeviceID
(
)
;
static
void
QueryAdID
(
)
;
static
void
QueryAdTracking
(
)
;
static
void
QueryVendorID
(
)
;
static
void
QueryDeviceName
(
)
;
static
void
QuerySystemName
(
)
;
static
void
QuerySystemVersion
(
)
;
static
void
QueryDeviceModel
(
)
;
static
void
QueryDeviceGeneration
(
)
;
static
void
EstimateDeviceDPI
(
)
;
//
// unity interface
//
extern
"C"
const
char
*
UnityDeviceUniqueIdentifier
(
)
{
QueryDeviceID
(
)
;
return
[
_DeviceID
UTF8String
]
;
}
extern
"C"
const
char
*
UnityVendorIdentifier
(
)
{
QueryVendorID
(
)
;
return
[
_VendorID
UTF8String
]
;
}
extern
"C"
const
char
*
UnityAdvertisingIdentifier
(
)
{
return
NULL
;
}
extern
"C"
bool
UnityAdvertisingTrackingEnabled
(
)
{
return
false
;
}
extern
"C"
const
char
*
UnityDeviceName
(
)
{
QueryDeviceName
(
)
;
return
[
_DeviceName
UTF8String
]
;
}
extern
"C"
const
char
*
UnitySystemName
(
)
{
QuerySystemName
(
)
;
return
[
_SystemName
UTF8String
]
;
}
extern
"C"
const
char
*
UnitySystemVersion
(
)
{
QuerySystemVersion
(
)
;
return
[
_SystemVersion
UTF8String
]
;
}
extern
"C"
const
char
*
UnityDeviceModel
(
)
{
QueryDeviceModel
(
)
;
return
[
_DeviceModel
UTF8String
]
;
}
extern
"C"
int
UnityDeviceGeneration
(
)
{
QueryDeviceGeneration
(
)
;
return
_DeviceGeneration
;
}
extern
"C"
float
UnityDeviceDPI
(
)
{
EstimateDeviceDPI
(
)
;
return
_DeviceDPI
;
}
//------------------------------------------------------------------------------
//
//
static
void
QueryDeviceID
(
)
{
if
(
_DeviceID
==
nil
)
{
#if UNITY_PRE_IOS7_TARGET
if
(
!
_ios70orNewer
)
_InitDeviceIDPreIOS7
(
)
;
#endif
// first check vendor id
if
(
_DeviceID
==
nil
)
{
QueryVendorID
(
)
;
_DeviceID
=
_VendorID
;
}
}
}
static
id
QueryASIdentifierManager
(
)
{
return
nil
;
}
static
void
QueryAdID
(
)
{
}
static
void
QueryAdTracking
(
)
{
}
static
void
QueryVendorID
(
)
{
if
(
_VendorID
==
nil
&&
[
UIDevice
instancesRespondToSelector
:
@
selector
(
identifierForVendor
)
]
)
_VendorID
=
(
NSString*
)
[
[
[
[
UIDevice
currentDevice
]
performSelector
:
@
selector
(
identifierForVendor
)
]
UUIDString
]
retain
]
;
}
static
NSString*
QueryDeviceStringProperty
(
SEL
prop
)
{
return
[
UIDevice
instancesRespondToSelector
:
prop
]
?
[
[
[
UIDevice
currentDevice
]
performSelector
:
prop
]
retain
]
:
nil
;
}
static
void
QueryDeviceName
(
)
{
if
(
_DeviceName
==
nil
)
_DeviceName
=
QueryDeviceStringProperty
(
@
selector
(
name
)
)
;
}
static
void
QuerySystemName
(
)
{
if
(
_SystemName
==
nil
)
_SystemName
=
QueryDeviceStringProperty
(
@
selector
(
systemName
)
)
;
}
static
void
QuerySystemVersion
(
)
{
if
(
_SystemVersion
==
nil
)
_SystemVersion
=
QueryDeviceStringProperty
(
@
selector
(
systemVersion
)
)
;
}
static
void
QueryDeviceModel
(
)
{
if
(
_DeviceModel
==
nil
)
{
size_t
size
;
::
sysctlbyname
(
"hw.machine"
,
NULL
,
&
size
,
NULL
,
0
)
;
char
*
model
=
(
char
*
)
::
malloc
(
size
+
1
)
;
::
sysctlbyname
(
"hw.machine"
,
model
,
&
size
,
NULL
,
0
)
;
model
[
size
]
=
0
;
_DeviceModel
=
[
[
NSString
stringWithUTF8String
:
model
]
retain
]
;
::
free
(
model
)
;
}
}
static
void
QueryDeviceGeneration
(
)
{
if
(
_DeviceGeneration
==
deviceUnknown
)
{
const
char
*
model
=
UnityDeviceModel
(
)
;
if
(
!
strcmp
(
model
,
"iPhone2,1"
)
)
_DeviceGeneration
=
deviceiPhone3GS
;
else
if
(
!
strncmp
(
model
,
"iPhone3,"
,
8
)
)
_DeviceGeneration
=
deviceiPhone4
;
else
if
(
!
strncmp
(
model
,
"iPhone4,"
,
8
)
)
_DeviceGeneration
=
deviceiPhone4S
;
else
if
(
!
strncmp
(
model
,
"iPhone6,"
,
8
)
)
_DeviceGeneration
=
deviceiPhone5S
;
else
if
(
!
strcmp
(
model
,
"iPod1,1"
)
)
_DeviceGeneration
=
deviceiPodTouch1Gen
;
else
if
(
!
strcmp
(
model
,
"iPod2,1"
)
)
_DeviceGeneration
=
deviceiPodTouch2Gen
;
else
if
(
!
strcmp
(
model
,
"iPod3,1"
)
)
_DeviceGeneration
=
deviceiPodTouch3Gen
;
else
if
(
!
strcmp
(
model
,
"iPod4,1"
)
)
_DeviceGeneration
=
deviceiPodTouch4Gen
;
else
if
(
!
strncmp
(
model
,
"iPod5,"
,
6
)
)
_DeviceGeneration
=
deviceiPodTouch5Gen
;
else
if
(
!
strcmp
(
model
,
"iPad1,1"
)
)
_DeviceGeneration
=
deviceiPad1Gen
;
// check iphone5c, ipad2 and ipad3 separately - they are special cases as apple reused major ver for different hws
if
(
_DeviceGeneration
==
deviceUnknown
)
{
if
(
!
strncmp
(
model
,
"iPhone5,"
,
8
)
)
{
int
rev
=
atoi
(
model
+
8
)
;
if
(
rev
>=
3
)
_DeviceGeneration
=
deviceiPhone5C
;
// iPhone5,3
else
_DeviceGeneration
=
deviceiPhone5
;
}
else
if
(
!
strncmp
(
model
,
"iPad2,"
,
6
)
)
{
int
rev
=
atoi
(
model
+
6
)
;
if
(
rev
>=
5
)
_DeviceGeneration
=
deviceiPadMini1Gen
;
// iPad2,5
else
_DeviceGeneration
=
deviceiPad2Gen
;
}
else
if
(
!
strncmp
(
model
,
"iPad3,"
,
6
)
)
{
int
rev
=
atoi
(
model
+
6
)
;
if
(
rev
>=
4
)
_DeviceGeneration
=
deviceiPad4Gen
;
// iPad3,4
else
_DeviceGeneration
=
deviceiPad3Gen
;
}
}
// completely unknown hw - just determine form-factor
if
(
_DeviceGeneration
==
deviceUnknown
)
{
if
(
!
strncmp
(
model
,
"iPhone"
,
6
)
)
_DeviceGeneration
=
deviceiPhoneUnknown
;
else
if
(
!
strncmp
(
model
,
"iPad"
,
4
)
)
_DeviceGeneration
=
deviceiPadUnknown
;
else
if
(
!
strncmp
(
model
,
"iPod"
,
4
)
)
_DeviceGeneration
=
deviceiPodTouchUnknown
;
_DeviceGeneration
=
deviceUnknown
;
}
}
}
static
void
EstimateDeviceDPI
(
)
{
if
(
_DeviceDPI
<
0.0f
)
{
float
baseDPI
=
160.0f
;
// phone-like devices
float
scaleFactor
=
1.0f
;
const
char
*
model
=
UnityDeviceModel
(
)
;
if
(
::
strncmp
(
model
,
"iPad"
,
4
)
==
0
)
{
if
(
UnityDeviceGeneration
(
)
==
deviceiPadMini1Gen
)
baseDPI
=
167.0f
;
else
baseDPI
=
130.0f
;
}
if
(
[
UIScreen
instancesRespondToSelector
:
@
selector
(
scale
)
]
)
scaleFactor
=
(
float
)
[
[
UIScreen
mainScreen
]
scale
]
;
_DeviceDPI
=
baseDPI *
scaleFactor
;
}
}
//
// some higher-level helpers
//
extern
"C"
void
QueryTargetResolution
(
int
*
targetW
,
int
*
targetH
)
{
enum
{
kTargetResolutionNative
=
0
,
kTargetResolutionAutoPerformance
=
3
,
kTargetResolutionAutoQuality
=
4
,
kTargetResolution320p
=
5
,
kTargetResolution640p
=
6
,
kTargetResolution768p
=
7
}
;
int
targetRes
=
UnityGetTargetResolution
(
)
;
float
resMult
=
1.0f
;
if
(
targetRes
==
kTargetResolutionAutoPerformance
)
{
switch
(
UnityDeviceGeneration
(
)
)
{
case
deviceiPhone4
:
resMult
=
0.6f
;
break
;
case
deviceiPad1Gen
:
resMult
=
0.5f
;
break
;
default
:
resMult
=
0.75f
;
break
;
}
}
if
(
targetRes
==
kTargetResolutionAutoQuality
)
{
switch
(
UnityDeviceGeneration
(
)
)
{
case
deviceiPhone4
:
resMult
=
0.8f
;
break
;
case
deviceiPad1Gen
:
resMult
=
0.75f
;
break
;
default
:
resMult
=
1.0f
;
break
;
}
}
switch
(
targetRes
)
{
case
kTargetResolution320p
:
*
targetW
=
320
;
*
targetH
=
480
;
break
;
case
kTargetResolution640p
:
*
targetW
=
640
;
*
targetH
=
960
;
break
;
case
kTargetResolution768p
:
*
targetW
=
768
;
*
targetH
=
1024
;
break
;
default
:
*
targetW
=
GetMainDisplay
(
)
->
screenSize
.
width *
resMult
;
*
targetH
=
GetMainDisplay
(
)
->
screenSize
.
height *
resMult
;
break
;
}
}
//
// gritty stuff
//
#if UNITY_PRE_IOS7_TARGET
static
void
_InitDeviceIDPreIOS7
(
)
{
static
const
int
MD5_DIGEST_LENGTH
=
16
;
// macaddr: courtesy of FreeBSD hackers email list
int
mib
[
6
]
=
{
CTL_NET
,
AF_ROUTE
,
0
,
AF_LINK
,
NET_RT_IFLIST
,
0
}
;
mib
[
5
]
=
::
if_nametoindex
(
"en0"
)
;
size_t
len
=
0
;
::
sysctl
(
mib
,
6
,
NULL
,
&
len
,
NULL
,
0
)
;
char
*
buf
=
(
char
*
)
::
malloc
(
len
)
;
::
sysctl
(
mib
,
6
,
buf
,
&
len
,
NULL
,
0
)
;
sockaddr_dl*
sdl
=
(
sockaddr_dl*
)
(
(
if_msghdr*
)
buf
+
1
)
;
unsigned
char
*
mac
=
(
unsigned
char
*
)
LLADDR
(
sdl
)
;
char
macaddr_str
[
18
]
=
{
0
}
;
::
sprintf
(
macaddr_str
,
"%02X:%02X:%02X:%02X:%02X:%02X"
,
*
mac
,
*
(
mac
+
1
)
,
*
(
mac
+
2
)
,
*
(
mac
+
3
)
,
*
(
mac
+
4
)
,
*
(
mac
+
5
)
)
;
::
free
(
buf
)
;
unsigned
char
hash_buf
[
MD5_DIGEST_LENGTH
]
;
CC_MD5
(
macaddr_str
,
sizeof
(
macaddr_str
)
-
1
,
hash_buf
)
;
char
uid_str
[
MD5_DIGEST_LENGTH*
2
+
1
]
=
{
0
}
;
for
(
int
i
=
0
;
i
<
MD5_DIGEST_LENGTH
;
++
i
)
::
sprintf
(
uid_str
+
2
*
i
,
"%02x"
,
hash_buf
[
i
]
)
;
_DeviceID
=
[
[
NSString
stringWithUTF8String
:
uid_str
]
retain
]
;
}
#endif
|
接下来就可以再次提交申请了。祝你顺利通过。
2014/02/24追记
使用如下命令查找一下项目中哪里使用了Advertising Identifier。
1
2
|
➜
test
find
.
|
grep
-
v
.
svn
|
grep
"\.a"
|
grep
-
v
"\.app"
|
xargs
grep
advertisingIdentifier
Binary
file
.
/
Libraries
/
xxxxxxxxx
.
a
matches
|
还可以通过Strings命令来查看字节码文件。
首先将生成的ipa文件的后缀名改成zip,之后解压缩会生成一个文件夹,在文件夹内部有一个linux可执行文件名称基本为你的应用程序的名称。在终端之下如下命令:
1
2
3
4
|
➜
dev
.
app
strings
dev
{
your
app
name
}
|
grep
advertisingIdentifier
get_advertisingIdentifier
can
only
be
called
from
the
main
thread
.
UnityEngine
.
iPhone
::
get_advertisingIdentifier
advertisingIdentifier
|