Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Important Changes for iOS ‘Kids’ Apps - Action Needed By Developers

Discussion in 'iOS and tvOS' started by ScottF, Mar 2, 2020.

  1. planetfactory

    planetfactory

    Joined:
    May 18, 2016
    Posts:
    55
    Last edited: Jul 13, 2020
  2. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
  3. unity_gKe7NiHQiej-Lw

    unity_gKe7NiHQiej-Lw

    Joined:
    Jul 13, 2020
    Posts:
    1
    Hey guys. We are still getting rejection from Apple.

    I have done all steps from the original post and I'm using Unity 2018.4.24.f1

    I'm executing this code in the Command Line inside a folder containing my generated "libiPhone-lib.a"


    find . -iname "*.a" -print0 | xargs -0 -I {} nm -j "{}" | c++filt | egrep -i 'isAdvertisingTrackingEnabled|advertisingIdentifier'


    The result is:


    no symbols
    _UnityAdvertisingIdentifier
    no symbols
    _UnityAdvertisingIdentifier
    IOSScripting::IsAdvertisingTrackingEnabled()
    _UnityAdvertisingIdentifier
    Device_CUSTOM_GetAdvertisingIdentifier()
    Device_CUSTOM_IsAdvertisingTrackingEnabled()
    Register_UnityEngine_iOS_Device_GetAdvertisingIdentifier()
    Register_UnityEngine_iOS_Device_IsAdvertisingTrackingEnabled()
    IOSScripting::IsAdvertisingTrackingEnabled()
    Device_CUSTOM_GetTVOSAdvertisingIdentifier()
    Application_CUSTOM_RequestAdvertisingIdentifierAsync(Il2CppObject*)
    Register_UnityEngine_tvOS_Device_GetTVOSAdvertisingIdentifier()
    Register_UnityEngine_Application_RequestAdvertisingIdentifierAsync()
    no symbols


    I'm afraid that is exactly what Apple is detecting when they are reviewing my App.

    Do you guys were able to have your apps Approved?

    @JeffDUnity3D, do you have any lead? I have already done all steps described in the link you have recently posted:
    https://support.unity3d.com/hc/en-u...entifier-selectors-from-the-Unity-SDK-on-iOS-
     
  4. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
  5. planetfactory

    planetfactory

    Joined:
    May 18, 2016
    Posts:
    55
  6. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    As mentioned, we are investigating
     
    Last edited: Jul 14, 2020
  7. Dan_Stradh

    Dan_Stradh

    Joined:
    Mar 22, 2018
    Posts:
    13
    Any news here about that ? Did anyone was able to publish something on the AppStore in Kids Apps ? Or everyone's binary contains IDFA even if everything is deactivated ? Kind of a big problem here if that's the case ...
     
    Last edited: Jul 15, 2020
  8. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    I will update here when we have additional information, we are still researching.
     
  9. kl20

    kl20

    Joined:
    Feb 18, 2017
    Posts:
    5
    Hi, do we have any update on this? It's been almost a week without any communication and we've been unable to release our app for around two weeks now.
     
    MohHeader likes this.
  10. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Can you confirm the current content in your DeviceSettings.mm file in your XCode project, perhaps attach here?
     
  11. jonscarybeasties

    jonscarybeasties

    Joined:
    Jul 22, 2020
    Posts:
    1
    Hi, an app I have been working on has been rejected today as well with the same rejection message as everyone else.

    "Third-party analytics or third-party advertising with the ability to collect, transmit or share identifiable information, including, for example, location. Specifically, we found your app was made with the Unity SDK. This particular SDK contained the following selectors that pertain to advertisements:

    isAdvertisingTrackingEnabled
    advertisingIdentifier

    It would be appropriate to work with Unity, in removing these selectors located in the UnityEngine.Analytics and/or UnityEngine.Advertisments components within your app before resubmitting."

    I have been actively removing the IDFA from the DeviceSettings.mm file since early this year and have been able to submit updates prior to today. It has been a month or two since the last app update was submitted.

    The DeviceSettings.mm file removes any reference to Advertising Identifier and empties the offending functions out. This was built with 2019.2.21 and replaced after the Unity build with this sanitised version.

    We need a solution as this is now blocking releases of scheduled apps.

    The DeviceSettings.mm file is as follows:

    Code (CSharp):
    1. #include <sys/types.h>
    2. #include <sys/sysctl.h>
    3.  
    4. #include "DisplayManager.h"
    5.  
    6. // ad/vendor ids
    7.  
    8. extern "C" const char* UnityAdvertisingIdentifier()
    9. {
    10.     return NULL;
    11. }
    12.  
    13. extern "C" int UnityGetLowPowerModeEnabled()
    14. {
    15.     return [[NSProcessInfo processInfo] isLowPowerModeEnabled] ? 1 : 0;
    16. }
    17.  
    18. extern "C" int UnityGetWantsSoftwareDimming()
    19. {
    20. #if !PLATFORM_TVOS
    21.     UIScreen* mainScreen = [UIScreen mainScreen];
    22.     return mainScreen.wantsSoftwareDimming ? 1 : 0;
    23. #else
    24.     return 0;
    25. #endif
    26. }
    27.  
    28. extern "C" void UnitySetWantsSoftwareDimming(int enabled)
    29. {
    30. #if !PLATFORM_TVOS
    31.     UIScreen* mainScreen = [UIScreen mainScreen];
    32.     mainScreen.wantsSoftwareDimming = enabled;
    33. #endif
    34. }
    35.  
    36. extern "C" int UnityAdvertisingTrackingEnabled()
    37. {
    38.     return 0;
    39. }
    40.  
    41. extern "C" const char* UnityVendorIdentifier()
    42. {
    43.     static const char*  _VendorID           = NULL;
    44.  
    45.     if (_VendorID == NULL)
    46.         _VendorID = AllocCString([[UIDevice currentDevice].identifierForVendor UUIDString]);
    47.  
    48.     return _VendorID;
    49. }
    50.  
    51. // UIDevice properties
    52.  
    53. #define QUERY_UIDEVICE_PROPERTY(FUNC, PROP)                                         \
    54.     extern "C" const char* FUNC()                                                   \
    55.     {                                                                               \
    56.         static const char* value = NULL;                                            \
    57.         if (value == NULL && [UIDevice instancesRespondToSelector:@selector(PROP)]) \
    58.             value = AllocCString([UIDevice currentDevice].PROP);                    \
    59.         return value;                                                               \
    60.     }
    61.  
    62. QUERY_UIDEVICE_PROPERTY(UnityDeviceName, name)
    63. QUERY_UIDEVICE_PROPERTY(UnitySystemName, systemName)
    64. QUERY_UIDEVICE_PROPERTY(UnitySystemVersion, systemVersion)
    65.  
    66. #undef QUERY_UIDEVICE_PROPERTY
    67.  
    68. // hw info
    69.  
    70. extern "C" const char* UnityDeviceModel()
    71. {
    72.     static const char* _DeviceModel = NULL;
    73.  
    74.     if (_DeviceModel == NULL)
    75.     {
    76.         size_t size;
    77.         ::sysctlbyname("hw.machine", NULL, &size, NULL, 0);
    78.  
    79.         char* model = (char*)::malloc(size + 1);
    80.         ::sysctlbyname("hw.machine", model, &size, NULL, 0);
    81.         model[size] = 0;
    82.  
    83. #if TARGET_OS_SIMULATOR
    84.         if (!strncmp(model, "i386", 4) || !strncmp(model, "x86_64", 6))
    85.         {
    86.             NSString* simModel = [[NSProcessInfo processInfo] environment][@"SIMULATOR_MODEL_IDENTIFIER"];
    87.             if ([simModel length] > 0)
    88.             {
    89.                 _DeviceModel = AllocCString(simModel);
    90.                 ::free(model);
    91.                 return _DeviceModel;
    92.             }
    93.         }
    94. #endif
    95.  
    96.         _DeviceModel = AllocCString([NSString stringWithUTF8String: model]);
    97.         ::free(model);
    98.     }
    99.  
    100.     return _DeviceModel;
    101. }
    102.  
    103. extern "C" int UnityDeviceCPUCount()
    104. {
    105.     static int _DeviceCPUCount = -1;
    106.  
    107.     if (_DeviceCPUCount <= 0)
    108.     {
    109.         // maybe would be better to use HW_AVAILCPU
    110.         int     ctlName[]   = {CTL_HW, HW_NCPU};
    111.         size_t  dataLen     = sizeof(_DeviceCPUCount);
    112.  
    113.         ::sysctl(ctlName, 2, &_DeviceCPUCount, &dataLen, NULL, 0);
    114.     }
    115.     return _DeviceCPUCount;
    116. }
    117.  
    118. extern "C" int UnityGetPhysicalMemory()
    119. {
    120.     return ([[NSProcessInfo processInfo] physicalMemory]) / (1024 * 1024);
    121. }
    122.  
    123. // misc
    124. extern "C" const char* UnitySystemLanguage()
    125. {
    126.     static const char* _SystemLanguage = NULL;
    127.  
    128.     if (_SystemLanguage == NULL)
    129.     {
    130.         NSArray* lang = [[NSUserDefaults standardUserDefaults] objectForKey: @"AppleLanguages"];
    131.         if (lang.count > 0)
    132.             _SystemLanguage = AllocCString(lang[0]);
    133.     }
    134.  
    135.     return _SystemLanguage;
    136. }
    137.  
    138. enum DeviceType : uint8_t
    139. {
    140.     deviceTypeUnknown = 0,
    141.     iPhone = 1,
    142.     iPad = 2,
    143.     iPod = 3,
    144.     AppleTV = 4
    145. };
    146.  
    147. struct DeviceTableEntry
    148. {
    149.     DeviceType deviceType;
    150.     uint8_t majorGen;
    151.     uint8_t minorGenMin;
    152.     uint8_t minorGenMax;
    153.     DeviceGeneration device;
    154. };
    155.  
    156. DeviceTableEntry DeviceTable[] =
    157. {
    158.     { iPhone, 2, 1, 1, deviceiPhone3GS },
    159.     { iPhone, 3, 1, 3, deviceiPhone4 },
    160.     { iPhone, 4, 1, 1, deviceiPhone4S },
    161.     { iPhone, 5, 3, 4, deviceiPhone5C },
    162.     { iPhone, 5, 1, 2, deviceiPhone5 },
    163.     { iPhone, 6, 1, 2, deviceiPhone5S },
    164.     { iPhone, 7, 2, 2, deviceiPhone6 },
    165.     { iPhone, 7, 1, 1, deviceiPhone6Plus },
    166.     { iPhone, 8, 1, 1, deviceiPhone6S },
    167.     { iPhone, 8, 2, 2, deviceiPhone6SPlus },
    168.     { iPhone, 8, 4, 4, deviceiPhoneSE1Gen },
    169.     { iPhone, 9, 1, 1, deviceiPhone7 },
    170.     { iPhone, 9, 3, 3, deviceiPhone7 },
    171.     { iPhone, 9, 2, 2, deviceiPhone7Plus },
    172.     { iPhone, 9, 4, 4, deviceiPhone7Plus },
    173.     { iPhone, 10, 1, 1, deviceiPhone8 },
    174.     { iPhone, 10, 4, 4, deviceiPhone8 },
    175.     { iPhone, 10, 2, 2, deviceiPhone8Plus },
    176.     { iPhone, 10, 5, 5, deviceiPhone8Plus },
    177.     { iPhone, 10, 3, 3, deviceiPhoneX },
    178.     { iPhone, 10, 6, 6, deviceiPhoneX },
    179.     { iPhone, 11, 8, 8, deviceiPhoneXR },
    180.     { iPhone, 11, 2, 2, deviceiPhoneXS },
    181.     { iPhone, 11, 4, 4, deviceiPhoneXSMax },
    182.     { iPhone, 11, 6, 6, deviceiPhoneXSMax },
    183.     { iPhone, 12, 1, 1, deviceiPhone11 },
    184.     { iPhone, 12, 3, 3, deviceiPhone11Pro },
    185.     { iPhone, 12, 5, 5, deviceiPhone11ProMax },
    186.  
    187.     { iPod, 4, 1, 1, deviceiPodTouch4Gen },
    188.     { iPod, 5, 1, 1, deviceiPodTouch5Gen },
    189.     { iPod, 7, 1, 1, deviceiPodTouch6Gen },
    190.     { iPod, 9, 1, 1, deviceiPodTouch7Gen },
    191.  
    192.     { iPad, 2, 5, 7, deviceiPadMini1Gen },
    193.     { iPad, 4, 4, 6, deviceiPadMini2Gen },
    194.     { iPad, 4, 7, 9, deviceiPadMini3Gen },
    195.     { iPad, 5, 1, 2, deviceiPadMini4Gen },
    196.     { iPad, 2, 1, 4, deviceiPad2Gen },
    197.     { iPad, 3, 1, 3, deviceiPad3Gen },
    198.     { iPad, 3, 4, 6, deviceiPad4Gen },
    199.     { iPad, 6, 11, 12, deviceiPad5Gen },
    200.     { iPad, 7, 5, 6, deviceiPad6Gen },
    201.     { iPad, 7, 11, 12, deviceiPad7Gen },
    202.     { iPad, 4, 1, 3, deviceiPadAir1 },
    203.     { iPad, 5, 3, 4, deviceiPadAir2 },
    204.     { iPad, 6, 7, 8, deviceiPadPro1Gen },
    205.     { iPad, 7, 1, 2, deviceiPadPro2Gen },
    206.     { iPad, 6, 3, 4, deviceiPadPro10Inch1Gen },
    207.     { iPad, 7, 3, 4, deviceiPadPro10Inch2Gen },
    208.     { iPad, 8, 1, 4, deviceiPadPro11Inch },
    209.     { iPad, 8, 5, 8, deviceiPadPro3Gen },
    210.  
    211.     { AppleTV, 5, 3, 3, deviceAppleTV1Gen },
    212.     { AppleTV, 6, 2, 2, deviceAppleTV2Gen }
    213. };
    214.  
    215. extern "C" int ParseDeviceGeneration(const char* model)
    216. {
    217.     DeviceType deviceType = deviceTypeUnknown;
    218.  
    219.     if (!strncmp(model, "iPhone", 6))
    220.     {
    221.         deviceType = iPhone;
    222.         model += 6;
    223.     }
    224.     else if (!strncmp(model, "iPad", 4))
    225.     {
    226.         deviceType = iPad;
    227.         model += 4;
    228.     }
    229.     else if (!strncmp(model, "iPod", 4))
    230.     {
    231.         deviceType = iPod;
    232.         model += 4;
    233.     }
    234.     else if (!strncmp(model, "AppleTV", 7))
    235.     {
    236.         deviceType = AppleTV;
    237.         model += 7;
    238.     }
    239.  
    240.     char* endPtr;
    241.     int majorGen = (int)strtol(model, &endPtr, 10);
    242.     int minorGen = (int)strtol(endPtr + 1, &endPtr, 10);
    243.  
    244.     if (strlen(endPtr) == 0)
    245.     {
    246.         for (int i = 0; i < sizeof(DeviceTable) / sizeof(DeviceTable[0]); ++i)
    247.         {
    248.             if (deviceType != DeviceTable[i].deviceType)
    249.                 continue;
    250.             if (majorGen != DeviceTable[i].majorGen)
    251.                 continue;
    252.             if (minorGen < DeviceTable[i].minorGenMin || minorGen > DeviceTable[i].minorGenMax)
    253.                 continue;
    254.             return DeviceTable[i].device;
    255.         }
    256.     }
    257.  
    258.     if (deviceType == iPhone)
    259.         return deviceiPhoneUnknown;
    260.     else if (deviceType == iPad)
    261.         return deviceiPadUnknown;
    262.     else if (deviceType == iPod)
    263.         return deviceiPodTouchUnknown;
    264.  
    265.     return deviceUnknown;
    266. }
    267.  
    268. extern "C" int UnityDeviceGeneration()
    269. {
    270.     static int _DeviceGeneration = deviceUnknown;
    271.  
    272.     if (_DeviceGeneration == deviceUnknown)
    273.     {
    274.         const char* model = UnityDeviceModel();
    275.         _DeviceGeneration = ParseDeviceGeneration(model);
    276.     }
    277.     return _DeviceGeneration;
    278. }
    279.  
    280. extern "C" int UnityDeviceSupportsUpsideDown()
    281. {
    282.     switch (UnityDeviceGeneration())
    283.     {
    284.         // devices without home button
    285.         case deviceiPhoneX: case deviceiPhoneXS: case deviceiPhoneXSMax: case deviceiPhoneXR:
    286.         case deviceiPhone11: case deviceiPhone11Pro: case deviceiPhone11ProMax:
    287.             return 0;
    288.         default:
    289.             return 1;
    290.     }
    291. }
    292.  
    293. extern "C" int UnityDeviceSupportedOrientations()
    294. {
    295.     int device = UnityDeviceGeneration();
    296.     int orientations = 0;
    297.  
    298.     orientations |= (1 << portrait);
    299.     orientations |= (1 << landscapeLeft);
    300.     orientations |= (1 << landscapeRight);
    301.     if (UnityDeviceSupportsUpsideDown())
    302.         orientations |= (1 << portraitUpsideDown);
    303.  
    304.     return orientations;
    305. }
    306.  
    307. extern "C" int UnityDeviceIsStylusTouchSupported()
    308. {
    309.     int deviceGen = UnityDeviceGeneration();
    310.     return (deviceGen == deviceiPadPro1Gen ||
    311.         deviceGen == deviceiPadPro10Inch1Gen ||
    312.         deviceGen == deviceiPadPro2Gen ||
    313.         deviceGen == deviceiPadPro10Inch2Gen) ? 1 : 0;
    314. }
    315.  
    316. extern "C" int UnityDeviceCanShowWideColor()
    317. {
    318.     if (@available(iOS 10.0, tvOS 10.0, *))
    319.         return [UIScreen mainScreen].traitCollection.displayGamut == UIDisplayGamutP3;
    320.  
    321.     return false;
    322. }
    323.  
    324. extern "C" float UnityDeviceDPI()
    325. {
    326.     static float _DeviceDPI = -1.0f;
    327.  
    328.     if (_DeviceDPI < 0.0f)
    329.     {
    330.         switch (UnityDeviceGeneration())
    331.         {
    332.             // iPhone
    333.             case deviceiPhone3GS:
    334.                 _DeviceDPI = 163.0f; break;
    335.             case deviceiPhone4:
    336.             case deviceiPhone4S:
    337.             case deviceiPhone5:
    338.             case deviceiPhone5C:
    339.             case deviceiPhone5S:
    340.             case deviceiPhone6:
    341.             case deviceiPhone6S:
    342.             case deviceiPhoneSE1Gen:
    343.             case deviceiPhone7:
    344.             case deviceiPhone8:
    345.             case deviceiPhoneXR:
    346.             case deviceiPhone11:
    347.                 _DeviceDPI = 326.0f; break;
    348.             case deviceiPhone6Plus:
    349.             case deviceiPhone6SPlus:
    350.             case deviceiPhone7Plus:
    351.             case deviceiPhone8Plus:
    352.                 _DeviceDPI = 401.0f; break;
    353.             case deviceiPhoneX:
    354.             case deviceiPhoneXS:
    355.             case deviceiPhoneXSMax:
    356.             case deviceiPhone11Pro:
    357.             case deviceiPhone11ProMax:
    358.                 _DeviceDPI = 458.0f; break;
    359.  
    360.             // iPad
    361.             case deviceiPad2Gen:
    362.                 _DeviceDPI = 132.0f; break;
    363.             case deviceiPad3Gen:
    364.             case deviceiPad4Gen:        // iPad retina
    365.             case deviceiPadAir1:
    366.             case deviceiPadAir2:
    367.             case deviceiPadPro1Gen:
    368.             case deviceiPadPro10Inch1Gen:
    369.             case deviceiPadPro2Gen:
    370.             case deviceiPadPro10Inch2Gen:
    371.             case deviceiPad5Gen:
    372.             case deviceiPad6Gen:
    373.             case deviceiPadPro11Inch:
    374.             case deviceiPadPro3Gen:
    375.                 _DeviceDPI = 264.0f; break;
    376.             case deviceiPad7Gen:
    377.                 _DeviceDPI = 326.0f; break;
    378.  
    379.             // iPad mini
    380.             case deviceiPadMini1Gen:
    381.                 _DeviceDPI = 163.0f; break;
    382.             case deviceiPadMini2Gen:
    383.             case deviceiPadMini3Gen:
    384.             case deviceiPadMini4Gen:
    385.                 _DeviceDPI = 326.0f; break;
    386.  
    387.             // iPod
    388.             case deviceiPodTouch4Gen:
    389.             case deviceiPodTouch5Gen:
    390.             case deviceiPodTouch6Gen:
    391.             case deviceiPodTouch7Gen:
    392.                 _DeviceDPI = 326.0f; break;
    393.  
    394.             // unknown (new) devices
    395.             case deviceiPhoneUnknown:
    396.                 _DeviceDPI = 326.0f; break;
    397.             case deviceiPadUnknown:
    398.                 _DeviceDPI = 264.0f; break;
    399.             case deviceiPodTouchUnknown:
    400.                 _DeviceDPI = 326.0f; break;
    401.         }
    402.  
    403.         // If we didn't find DPI, set it to "unknown" value.
    404.         if (_DeviceDPI < 0.0f)
    405.             _DeviceDPI = 0.0f;
    406.     }
    407.  
    408.     return _DeviceDPI;
    409. }
    410.  
    411. // device id with fallback for pre-ios7
    412.  
    413. extern "C" const char* UnityDeviceUniqueIdentifier()
    414. {
    415.     static const char* _DeviceID = NULL;
    416.  
    417.     if (_DeviceID == NULL)
    418.         _DeviceID = UnityVendorIdentifier();
    419.  
    420.     return _DeviceID;
    421. }
    422.  
     
  12. kl20

    kl20

    Joined:
    Feb 18, 2017
    Posts:
    5
    Our DeviceSettings.mm file is as follows:

    Code (CSharp):
    1. #include <sys/types.h>
    2. #include <sys/sysctl.h>
    3.  
    4. #include "DisplayManager.h"
    5.  
    6. // ad/vendor ids
    7. #if UNITY_USES_IAD
    8. #include <AdSupport/ASIdentifierManager.h>
    9. static id QueryASIdentifierManager()
    10. {
    11.     NSBundle* bundle = [NSBundle bundleWithPath: @"/System/Library/Frameworks/AdSupport.framework"];
    12.     if (bundle)
    13.     {
    14.         [bundle load];
    15.         Class retClass = [bundle classNamed: @"ASIdentifierManager"];
    16.         return [retClass performSelector: @selector(sharedManager)];
    17.     }
    18.  
    19.     return nil;
    20. }
    21.  
    22. #endif
    23.  
    24. extern "C" const char* UnityAdvertisingIdentifier()
    25. {
    26.     static const char* _ADID = NULL;
    27.  
    28. #if UNITY_USES_IAD
    29.     static const NSString* _ADIDNSString = nil;
    30.  
    31.     // ad id can be reset during app lifetime
    32.     id manager = QueryASIdentifierManager();
    33.     if (manager)
    34.     {
    35.         NSString* adid = [[manager performSelector: @selector(advertisingIdentifier)] UUIDString];
    36.         // Do stuff to avoid UTF8String leaks. We still leak if ADID changes, but that shouldn't happen too often.
    37.         if (![_ADIDNSString isEqualToString: adid])
    38.         {
    39.             _ADIDNSString = adid;
    40.             free((void*)_ADID);
    41.             _ADID = AllocCString(adid);
    42.         }
    43.     }
    44. #endif
    45.  
    46.     return _ADID;
    47. }
    48.  
    49. extern "C" int UnityGetLowPowerModeEnabled()
    50. {
    51.     return [[NSProcessInfo processInfo] isLowPowerModeEnabled] ? 1 : 0;
    52. }
    53.  
    54. extern "C" int UnityGetWantsSoftwareDimming()
    55. {
    56. #if !PLATFORM_TVOS
    57.     UIScreen* mainScreen = [UIScreen mainScreen];
    58.     return mainScreen.wantsSoftwareDimming ? 1 : 0;
    59. #else
    60.     return 0;
    61. #endif
    62. }
    63.  
    64. extern "C" void UnitySetWantsSoftwareDimming(int enabled)
    65. {
    66. #if !PLATFORM_TVOS
    67.     UIScreen* mainScreen = [UIScreen mainScreen];
    68.     mainScreen.wantsSoftwareDimming = enabled;
    69. #endif
    70. }
    71.  
    72. extern "C" int UnityAdvertisingTrackingEnabled()
    73. {
    74.     bool _AdTrackingEnabled = false;
    75.  
    76. #if UNITY_USES_IAD
    77.     // ad tracking can be changed during app lifetime
    78.     id manager = QueryASIdentifierManager();
    79.     if (manager)
    80.         _AdTrackingEnabled = [manager performSelector: @selector(isAdvertisingTrackingEnabled)];
    81. #endif
    82.  
    83.     return _AdTrackingEnabled ? 1 : 0;
    84. }
    85.  
    86. extern "C" const char* UnityVendorIdentifier()
    87. {
    88.     static const char*  _VendorID           = NULL;
    89.  
    90.     if (_VendorID == NULL)
    91.         _VendorID = AllocCString([[UIDevice currentDevice].identifierForVendor UUIDString]);
    92.  
    93.     return _VendorID;
    94. }
    95.  
    96. // UIDevice properties
    97.  
    98. #define QUERY_UIDEVICE_PROPERTY(FUNC, PROP)                                         \
    99.     extern "C" const char* FUNC()                                                   \
    100.     {                                                                               \
    101.         static const char* value = NULL;                                            \
    102.         if (value == NULL && [UIDevice instancesRespondToSelector:@selector(PROP)]) \
    103.             value = AllocCString([UIDevice currentDevice].PROP);                    \
    104.         return value;                                                               \
    105.     }
    106.  
    107. QUERY_UIDEVICE_PROPERTY(UnityDeviceName, name)
    108. QUERY_UIDEVICE_PROPERTY(UnitySystemName, systemName)
    109. QUERY_UIDEVICE_PROPERTY(UnitySystemVersion, systemVersion)
    110.  
    111. #undef QUERY_UIDEVICE_PROPERTY
    112.  
    113. // hw info
    114.  
    115. extern "C" const char* UnityDeviceModel()
    116. {
    117.     static const char* _DeviceModel = NULL;
    118.  
    119.     if (_DeviceModel == NULL)
    120.     {
    121.         size_t size;
    122.         ::sysctlbyname("hw.machine", NULL, &size, NULL, 0);
    123.  
    124.         char* model = (char*)::malloc(size + 1);
    125.         ::sysctlbyname("hw.machine", model, &size, NULL, 0);
    126.         model[size] = 0;
    127.  
    128. #if TARGET_OS_SIMULATOR
    129.         if (!strncmp(model, "i386", 4) || !strncmp(model, "x86_64", 6))
    130.         {
    131.             NSString* simModel = [[NSProcessInfo processInfo] environment][@"SIMULATOR_MODEL_IDENTIFIER"];
    132.             if ([simModel length] > 0)
    133.             {
    134.                 _DeviceModel = AllocCString(simModel);
    135.                 ::free(model);
    136.                 return _DeviceModel;
    137.             }
    138.         }
    139. #endif
    140.  
    141.         _DeviceModel = AllocCString([NSString stringWithUTF8String: model]);
    142.         ::free(model);
    143.     }
    144.  
    145.     return _DeviceModel;
    146. }
    147.  
    148. extern "C" int UnityDeviceCPUCount()
    149. {
    150.     static int _DeviceCPUCount = -1;
    151.  
    152.     if (_DeviceCPUCount <= 0)
    153.     {
    154.         // maybe would be better to use HW_AVAILCPU
    155.         int     ctlName[]   = {CTL_HW, HW_NCPU};
    156.         size_t  dataLen     = sizeof(_DeviceCPUCount);
    157.  
    158.         ::sysctl(ctlName, 2, &_DeviceCPUCount, &dataLen, NULL, 0);
    159.     }
    160.     return _DeviceCPUCount;
    161. }
    162.  
    163. extern "C" int UnityGetPhysicalMemory()
    164. {
    165.     return ([[NSProcessInfo processInfo] physicalMemory]) / (1024 * 1024);
    166. }
    167.  
    168. // misc
    169. extern "C" const char* UnitySystemLanguage()
    170. {
    171.     static const char* _SystemLanguage = NULL;
    172.  
    173.     if (_SystemLanguage == NULL)
    174.     {
    175.         NSArray* lang = [[NSUserDefaults standardUserDefaults] objectForKey: @"AppleLanguages"];
    176.         if (lang.count > 0)
    177.             _SystemLanguage = AllocCString(lang[0]);
    178.     }
    179.  
    180.     return _SystemLanguage;
    181. }
    182.  
    183. enum DeviceType : uint8_t
    184. {
    185.     deviceTypeUnknown = 0,
    186.     iPhone = 1,
    187.     iPad = 2,
    188.     iPod = 3,
    189.     AppleTV = 4
    190. };
    191.  
    192. struct DeviceTableEntry
    193. {
    194.     DeviceType deviceType;
    195.     uint8_t majorGen;
    196.     uint8_t minorGenMin;
    197.     uint8_t minorGenMax;
    198.     DeviceGeneration device;
    199. };
    200.  
    201. DeviceTableEntry DeviceTable[] =
    202. {
    203.     { iPhone, 2, 1, 1, deviceiPhone3GS },
    204.     { iPhone, 3, 1, 3, deviceiPhone4 },
    205.     { iPhone, 4, 1, 1, deviceiPhone4S },
    206.     { iPhone, 5, 3, 4, deviceiPhone5C },
    207.     { iPhone, 5, 1, 2, deviceiPhone5 },
    208.     { iPhone, 6, 1, 2, deviceiPhone5S },
    209.     { iPhone, 7, 2, 2, deviceiPhone6 },
    210.     { iPhone, 7, 1, 1, deviceiPhone6Plus },
    211.     { iPhone, 8, 1, 1, deviceiPhone6S },
    212.     { iPhone, 8, 2, 2, deviceiPhone6SPlus },
    213.     { iPhone, 8, 4, 4, deviceiPhoneSE1Gen },
    214.     { iPhone, 9, 1, 1, deviceiPhone7 },
    215.     { iPhone, 9, 3, 3, deviceiPhone7 },
    216.     { iPhone, 9, 2, 2, deviceiPhone7Plus },
    217.     { iPhone, 9, 4, 4, deviceiPhone7Plus },
    218.     { iPhone, 10, 1, 1, deviceiPhone8 },
    219.     { iPhone, 10, 4, 4, deviceiPhone8 },
    220.     { iPhone, 10, 2, 2, deviceiPhone8Plus },
    221.     { iPhone, 10, 5, 5, deviceiPhone8Plus },
    222.     { iPhone, 10, 3, 3, deviceiPhoneX },
    223.     { iPhone, 10, 6, 6, deviceiPhoneX },
    224.     { iPhone, 11, 8, 8, deviceiPhoneXR },
    225.     { iPhone, 11, 2, 2, deviceiPhoneXS },
    226.     { iPhone, 11, 4, 4, deviceiPhoneXSMax },
    227.     { iPhone, 11, 6, 6, deviceiPhoneXSMax },
    228.     { iPhone, 12, 1, 1, deviceiPhone11 },
    229.     { iPhone, 12, 3, 3, deviceiPhone11Pro },
    230.     { iPhone, 12, 5, 5, deviceiPhone11ProMax },
    231.  
    232.     { iPod, 4, 1, 1, deviceiPodTouch4Gen },
    233.     { iPod, 5, 1, 1, deviceiPodTouch5Gen },
    234.     { iPod, 7, 1, 1, deviceiPodTouch6Gen },
    235.     { iPod, 9, 1, 1, deviceiPodTouch7Gen },
    236.  
    237.     { iPad, 2, 5, 7, deviceiPadMini1Gen },
    238.     { iPad, 4, 4, 6, deviceiPadMini2Gen },
    239.     { iPad, 4, 7, 9, deviceiPadMini3Gen },
    240.     { iPad, 5, 1, 2, deviceiPadMini4Gen },
    241.     { iPad, 2, 1, 4, deviceiPad2Gen },
    242.     { iPad, 3, 1, 3, deviceiPad3Gen },
    243.     { iPad, 3, 4, 6, deviceiPad4Gen },
    244.     { iPad, 6, 11, 12, deviceiPad5Gen },
    245.     { iPad, 7, 5, 6, deviceiPad6Gen },
    246.     { iPad, 7, 11, 12, deviceiPad7Gen },
    247.     { iPad, 4, 1, 3, deviceiPadAir1 },
    248.     { iPad, 5, 3, 4, deviceiPadAir2 },
    249.     { iPad, 6, 7, 8, deviceiPadPro1Gen },
    250.     { iPad, 7, 1, 2, deviceiPadPro2Gen },
    251.     { iPad, 6, 3, 4, deviceiPadPro10Inch1Gen },
    252.     { iPad, 7, 3, 4, deviceiPadPro10Inch2Gen },
    253.     { iPad, 8, 1, 4, deviceiPadPro11Inch },
    254.     { iPad, 8, 5, 8, deviceiPadPro3Gen },
    255.  
    256.     { AppleTV, 5, 3, 3, deviceAppleTV1Gen },
    257.     { AppleTV, 6, 2, 2, deviceAppleTV2Gen }
    258. };
    259.  
    260. extern "C" int ParseDeviceGeneration(const char* model)
    261. {
    262.     DeviceType deviceType = deviceTypeUnknown;
    263.  
    264.     if (!strncmp(model, "iPhone", 6))
    265.     {
    266.         deviceType = iPhone;
    267.         model += 6;
    268.     }
    269.     else if (!strncmp(model, "iPad", 4))
    270.     {
    271.         deviceType = iPad;
    272.         model += 4;
    273.     }
    274.     else if (!strncmp(model, "iPod", 4))
    275.     {
    276.         deviceType = iPod;
    277.         model += 4;
    278.     }
    279.     else if (!strncmp(model, "AppleTV", 7))
    280.     {
    281.         deviceType = AppleTV;
    282.         model += 7;
    283.     }
    284.  
    285.     char* endPtr;
    286.     int majorGen = (int)strtol(model, &endPtr, 10);
    287.     int minorGen = (int)strtol(endPtr + 1, &endPtr, 10);
    288.  
    289.     if (strlen(endPtr) == 0)
    290.     {
    291.         for (int i = 0; i < sizeof(DeviceTable) / sizeof(DeviceTable[0]); ++i)
    292.         {
    293.             if (deviceType != DeviceTable[i].deviceType)
    294.                 continue;
    295.             if (majorGen != DeviceTable[i].majorGen)
    296.                 continue;
    297.             if (minorGen < DeviceTable[i].minorGenMin || minorGen > DeviceTable[i].minorGenMax)
    298.                 continue;
    299.             return DeviceTable[i].device;
    300.         }
    301.     }
    302.  
    303.     if (deviceType == iPhone)
    304.         return deviceiPhoneUnknown;
    305.     else if (deviceType == iPad)
    306.         return deviceiPadUnknown;
    307.     else if (deviceType == iPod)
    308.         return deviceiPodTouchUnknown;
    309.  
    310.     return deviceUnknown;
    311. }
    312.  
    313. extern "C" int UnityDeviceGeneration()
    314. {
    315.     static int _DeviceGeneration = deviceUnknown;
    316.  
    317.     if (_DeviceGeneration == deviceUnknown)
    318.     {
    319.         const char* model = UnityDeviceModel();
    320.         _DeviceGeneration = ParseDeviceGeneration(model);
    321.     }
    322.     return _DeviceGeneration;
    323. }
    324.  
    325. extern "C" int UnityDeviceSupportsUpsideDown()
    326. {
    327.     switch (UnityDeviceGeneration())
    328.     {
    329.         // devices without home button
    330.         case deviceiPhoneX: case deviceiPhoneXS: case deviceiPhoneXSMax: case deviceiPhoneXR:
    331.         case deviceiPhone11: case deviceiPhone11Pro: case deviceiPhone11ProMax:
    332.             return 0;
    333.         default:
    334.             return 1;
    335.     }
    336. }
    337.  
    338. extern "C" int UnityDeviceSupportedOrientations()
    339. {
    340.     int device = UnityDeviceGeneration();
    341.     int orientations = 0;
    342.  
    343.     orientations |= (1 << portrait);
    344.     orientations |= (1 << landscapeLeft);
    345.     orientations |= (1 << landscapeRight);
    346.     if (UnityDeviceSupportsUpsideDown())
    347.         orientations |= (1 << portraitUpsideDown);
    348.  
    349.     return orientations;
    350. }
    351.  
    352. extern "C" int UnityDeviceIsStylusTouchSupported()
    353. {
    354.     int deviceGen = UnityDeviceGeneration();
    355.     return (deviceGen == deviceiPadPro1Gen ||
    356.         deviceGen == deviceiPadPro10Inch1Gen ||
    357.         deviceGen == deviceiPadPro2Gen ||
    358.         deviceGen == deviceiPadPro10Inch2Gen ||
    359.         deviceGen == deviceiPadPro11Inch ||
    360.         deviceGen == deviceiPadPro3Gen ||
    361.         deviceGen == deviceiPad6Gen) ? 1 : 0;
    362. }
    363.  
    364. extern "C" int UnityDeviceCanShowWideColor()
    365. {
    366.     return [UIScreen mainScreen].traitCollection.displayGamut == UIDisplayGamutP3;
    367. }
    368.  
    369. extern "C" float UnityDeviceDPI()
    370. {
    371.     static float _DeviceDPI = -1.0f;
    372.  
    373.     if (_DeviceDPI < 0.0f)
    374.     {
    375.         switch (UnityDeviceGeneration())
    376.         {
    377.             // iPhone
    378.             case deviceiPhone3GS:
    379.                 _DeviceDPI = 163.0f; break;
    380.             case deviceiPhone4:
    381.             case deviceiPhone4S:
    382.             case deviceiPhone5:
    383.             case deviceiPhone5C:
    384.             case deviceiPhone5S:
    385.             case deviceiPhone6:
    386.             case deviceiPhone6S:
    387.             case deviceiPhoneSE1Gen:
    388.             case deviceiPhone7:
    389.             case deviceiPhone8:
    390.             case deviceiPhoneXR:
    391.             case deviceiPhone11:
    392.                 _DeviceDPI = 326.0f; break;
    393.             case deviceiPhone6Plus:
    394.             case deviceiPhone6SPlus:
    395.             case deviceiPhone7Plus:
    396.             case deviceiPhone8Plus:
    397.                 _DeviceDPI = 401.0f; break;
    398.             case deviceiPhoneX:
    399.             case deviceiPhoneXS:
    400.             case deviceiPhoneXSMax:
    401.             case deviceiPhone11Pro:
    402.             case deviceiPhone11ProMax:
    403.                 _DeviceDPI = 458.0f; break;
    404.  
    405.             // iPad
    406.             case deviceiPad2Gen:
    407.                 _DeviceDPI = 132.0f; break;
    408.             case deviceiPad3Gen:
    409.             case deviceiPad4Gen:        // iPad retina
    410.             case deviceiPadAir1:
    411.             case deviceiPadAir2:
    412.             case deviceiPadPro1Gen:
    413.             case deviceiPadPro10Inch1Gen:
    414.             case deviceiPadPro2Gen:
    415.             case deviceiPadPro10Inch2Gen:
    416.             case deviceiPad5Gen:
    417.             case deviceiPad6Gen:
    418.             case deviceiPadPro11Inch:
    419.             case deviceiPadPro3Gen:
    420.                 _DeviceDPI = 264.0f; break;
    421.             case deviceiPad7Gen:
    422.                 _DeviceDPI = 326.0f; break;
    423.  
    424.             // iPad mini
    425.             case deviceiPadMini1Gen:
    426.                 _DeviceDPI = 163.0f; break;
    427.             case deviceiPadMini2Gen:
    428.             case deviceiPadMini3Gen:
    429.             case deviceiPadMini4Gen:
    430.                 _DeviceDPI = 326.0f; break;
    431.  
    432.             // iPod
    433.             case deviceiPodTouch4Gen:
    434.             case deviceiPodTouch5Gen:
    435.             case deviceiPodTouch6Gen:
    436.             case deviceiPodTouch7Gen:
    437.                 _DeviceDPI = 326.0f; break;
    438.  
    439.             // unknown (new) devices
    440.             case deviceiPhoneUnknown:
    441.                 _DeviceDPI = 326.0f; break;
    442.             case deviceiPadUnknown:
    443.                 _DeviceDPI = 264.0f; break;
    444.             case deviceiPodTouchUnknown:
    445.                 _DeviceDPI = 326.0f; break;
    446.         }
    447.  
    448.         // If we didn't find DPI, set it to "unknown" value.
    449.         if (_DeviceDPI < 0.0f)
    450.             _DeviceDPI = 0.0f;
    451.     }
    452.  
    453.     return _DeviceDPI;
    454. }
    455.  
    456. // device id with fallback for pre-ios7
    457.  
    458. extern "C" const char* UnityDeviceUniqueIdentifier()
    459. {
    460.     static const char* _DeviceID = NULL;
    461.  
    462.     if (_DeviceID == NULL)
    463.         _DeviceID = UnityVendorIdentifier();
    464.  
    465.     return _DeviceID;
    466. }
    467.  
    In Preprocessor.h we have:

    Code (CSharp):
    1. #define UNITY_USES_IAD 0
     
  13. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    @kl20 That doesn't look like the code mentioned at the beginning of this article if #if UNITY_USES_IAD evaluates to true.
     
  14. kl20

    kl20

    Joined:
    Feb 18, 2017
    Posts:
    5
    @JeffDUnity3D Isn't the point of `#define UNITY_USES_IAD 0` so it doesn't evaluate to true? Afaik it's not supposed to even compile the code within the guards. (which I thought was the fix that Unity rolled out to address this problem back in Jan/Feb)
     
  15. austin-beck

    austin-beck

    Joined:
    Oct 28, 2015
    Posts:
    19
    @JeffDUnity3D Any word on this? We have also followed your prior instructions and got rejected nonetheless. I completely understand that this relatively sudden policy change of Apple's has thrown a lot of things in the air but if there are any additional steps I can take to try to get approved, I'd like to know.
     
  16. planetfactory

    planetfactory

    Joined:
    May 18, 2016
    Posts:
    55
    Any news after 15 days? Are you still investigating? This is a major issue.
     
  17. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    No news, unfortunately we are back to square one with Apple. Once again we are going through the Submission/Rejection process iteratively ourselves, and reaching out to Apple.
     
  18. restauranttttt

    restauranttttt

    Joined:
    Aug 6, 2020
    Posts:
    15
    I made a phone call with Apple Reviewer, he told me I should contact with Unity3D official to solve the Unity3D engine problem.
    I have done what the threads say, delete all code maybe relate to idfa or tracking. After u3d build iOS project, I searched the "advertisingIdentifier", still exist in some 'cpp' file.

    Please help me, I really need to update my App.
     
  19. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    Did you make the changes suggested at the beginning of this thread? Otherwise, yes, we are still researching.
     
  20. restauranttttt

    restauranttttt

    Joined:
    Aug 6, 2020
    Posts:
    15
    yes, I tried all suggested solutions, all failed. So I requested a call help from Apple. Finally, I got the info mentioned before.
    Here is the question about unity engine:
    in unity setting, closed all the ad and tracking setting, why there are "advertisingIdentifier" string in several cpp files after build for ios?
    DeviceSetting.mm file is modified as suggested, apple still finds some idfa code in unity engine
     
  21. PIBOCO-Developer

    PIBOCO-Developer

    Joined:
    Feb 10, 2020
    Posts:
    11
    We are very urgently waiting for this to get resolved as we too are blocked from any further submissions :-(

    EDIT: We use Firebase BTW. But Apple told us that Firebase is OK according to their policy.
     
    Last edited: Aug 13, 2020
  22. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    We believe they are finding portions of code that is never called, we are continuing to investigate.
     
  23. PIBOCO-Developer

    PIBOCO-Developer

    Joined:
    Feb 10, 2020
    Posts:
    11
    We have boiled the issue down to an empty project with the Firebase Core package added (plus our settings plist + json). We've tried being very careful with plist values and frameworks and it still doesn't work. We find following strings in our xcarchive binary:

    /google/measurement/set_last_advertising_id_reset
    advertisingIdentifier
    advertisingIdentifierString
    isAdvertisingTrackingEnabled
    lastAdvertisingIDResetFeatureEnabled
    last_advertising_id_reset
    measurement.last_advertising_id_reset_feature_enabled
    setLastAdvertisingIDResetUserPropertyOnWorkerQueue
    setShouldSetLastAdvertisingIDResetUserProperty:
    shouldSetLastAdvertisingIDResetUserProperty​

    With a completely empty Unity project, we find nothing.

    Honestly I feel like that at this point, maybe the blame is with Google and not Unity (at least for our case), but I would love where it really goes wrong. We've reported it to Firebase Support and are awaiting an answer.
     
  24. Lord_Eniac

    Lord_Eniac

    Joined:
    Jan 28, 2020
    Posts:
    48
    I cannot speak for everyone, but I appreciate Unity's diligence in resolving this issue. May I ask what your investigation has revealed? I have learned in dealing with Apple that the company is super-picky. For instance, we have completely disabled the ads and analyics packages from the paid version of our app simply because we don't know if Apple will reject them.

    [soapbox time]
    My biggest gripe from a rejection standpoint is simply the amount of time it takes (from shortest "A" to longest "C") to A: build the project in Unity, B: run the app on the device from XCode, and C: archive the application (and finally upload which can also take an eternity, it seems). So, rather than roll the dice and have Apple reject or accept the app, we go for the safe bet of disable any and all ads and analytics to help ensure app acceptance. We would love to have analytics as part of our non-kids (17+ [because it's technically a medical app]) application. And maybe we can. I don't know. The "contains in app purchases" notice in our XCode project concerns me. There's a lot about the Apple process where "I just don't know". I sometimes wonder if even Apple knows Apple's policies.
     
  25. PIBOCO-Developer

    PIBOCO-Developer

    Joined:
    Feb 10, 2020
    Posts:
    11
    I would like to report that we have possibly solved our Firebase issue by upgrading our project from 2018LTS to 2019LTS. At least in a minimal test case. We are upgrading our entire app to see how it will fare.
     
  26. Dan_Stradh

    Dan_Stradh

    Joined:
    Mar 22, 2018
    Posts:
    13
    Looking forward to know !

    Still getting rejected with 2019 LTS =(
     
  27. PIBOCO-Developer

    PIBOCO-Developer

    Joined:
    Feb 10, 2020
    Posts:
    11
    At least the string search for "advertising" turns out negative. Do you have any advertising string matches in your binary, as described earlier in this thread?
     
  28. Dan_Stradh

    Dan_Stradh

    Joined:
    Mar 22, 2018
    Posts:
    13
    Yes, even with the "fix" unity did in DeviceSetting.mm...
    We use firebase too, but it's our own server, collecting data for us, and it should be ok by apple's policies
     
  29. PIBOCO-Developer

    PIBOCO-Developer

    Joined:
    Feb 10, 2020
    Posts:
    11
    Do you use any Firebase SDK's in your Unity project?
     
  30. Dan_Stradh

    Dan_Stradh

    Joined:
    Mar 22, 2018
    Posts:
    13
    Yes I have firebase SDK. But we use Countly, and we host our own Countly server.
    Even if we have no ads and disable Analytics in the code, and use the #if UNITY_USES_IAD,
    we still get rejected....I just want to know where the problem is coming from, some people at unity tells me it's probably a problem in unity, others wanna see my project to see if something is wrong, and others are telling me to remove older builds and try again....honestly I don't know what to think anymore....and don't know what to do to get my app accepted in the app store....

    Were you able to publish ?
    Is it a kid's app ?
     
    Last edited: Aug 19, 2020
  31. planetfactory

    planetfactory

    Joined:
    May 18, 2016
    Posts:
    55
    Hi,

    I can confirm that all apps are been approved, except for the ones that have Firebase. So, the problem is with Firebase... but Apple says that the problem is Unity. @JeffDUnity3D
     
    Dan_Stradh likes this.
  32. Dan_Stradh

    Dan_Stradh

    Joined:
    Mar 22, 2018
    Posts:
    13
    Really ? I'm gonna try and remove firebase and countly from the app, and try to resubmit.
    Thanks

    As soon as I know, I'll let you know if this fix works for me. Thank you very much

    Quick question, in what category is your app ? Is it a kid's app ?
     
  33. Dan_Stradh

    Dan_Stradh

    Joined:
    Mar 22, 2018
    Posts:
    13
    You were right...we removed firebase and....boom it got accepted....
     
    planetfactory likes this.
  34. restauranttttt

    restauranttttt

    Joined:
    Aug 6, 2020
    Posts:
    15
    Did you modify some code in unity?
    Is your app in KID category?
    Our app does not use Firebase or any other third part analysis tool. As we guess, some code about idfa not called in unity cause the rejection.
    Please tell us the details you did with your code or other settings!
     
  35. Dan_Stradh

    Dan_Stradh

    Joined:
    Mar 22, 2018
    Posts:
    13
    First of all, I'm using Unity 2019.4.0 some code about advertising in DeviceSettings.mm is already surrounded by #if UNITY_USES_IAD.
    In services in app purchaser are On, Analytics are on (since analytics are on by default when you use IAP), and ads are off.
    In the first scene of my game I have the following code:

    Analytics.initializeOnStartup = false;
    Analytics.enabled = false;
    PerformanceReporting.enabled = false;
    Analytics.limitUserTracking = false;
    Analytics.deviceStatsEnabled = false;

    By the way even if I run the command to see if there are any traces of ads or whatever, it tells me there are, so I guess that's not how they verify this stuff. Even if the terminal command returned me the following it got accepted

    no symbols
    _UnityAdvertisingIdentifier
    no symbols
    _UnityAdvertisingIdentifier
    IOSScripting::IsAdvertisingTrackingEnabled()
    _UnityAdvertisingIdentifier
    and so on....

    And the last test I did yesterday was removing Countly Analytics (it was running on our own servers to gather analytics for us we were not sending to a third party)....but I guess that since Countly requires firebase, I removed both countly and firebase entirely from my project. And it got accepted.

    Yes it's a kid's app

    I don't if that can help you out, let me know
     
  36. restauranttttt

    restauranttttt

    Joined:
    Aug 6, 2020
    Posts:
    15
    We use unity 2018.4.19. And we disable the Analytics in build setting. So can not call the codes you provide.
    We also run the command and found some symbols.
    We do not use any other third part analytics services.
    Apple has rejected our app several times.
    Apple told us to contact Unity Official to find out the solution.
    We have no idea what to do. So I am here...
     
  37. PIBOCO-Developer

    PIBOCO-Developer

    Joined:
    Feb 10, 2020
    Posts:
    11
    We had to fix some more issues from upgrading to 2019 but we're awaiting manual review from Apple. My hopes are not particularly high to be honest :-I
     
  38. PIBOCO-Developer

    PIBOCO-Developer

    Joined:
    Feb 10, 2020
    Posts:
    11
    Just to be sure, you all follow this guide, right?
     
  39. Dan_Stradh

    Dan_Stradh

    Joined:
    Mar 22, 2018
    Posts:
    13
    Did you removed Firebase from your project ? Let us know when you have news.
     
  40. Dan_Stradh

    Dan_Stradh

    Joined:
    Mar 22, 2018
    Posts:
    13
    I wasn't using third parties analytics, but was using countly and hosting our own servers, but since countly needed firebase, we had to have the sdk in our project. You dont have Firebase sdk ? Or google analytics ? What packages do you have installed in your project ? What services are active in the services window ? Do you use In app purchases ?
    If you do use in app purchases, I think analytics has to be there if you use in app purchases, try using the code I gave in the first scene of your app.
    add
    using UnityEngine.Analytics;

    and then

    Analytics.initializeOnStartup = false;
    Analytics.enabled = false;
    PerformanceReporting.enabled = false;
    Analytics.limitUserTracking = false;
    Analytics.deviceStatsEnabled = false;
     
    Last edited: Aug 21, 2020
  41. Dan_Stradh

    Dan_Stradh

    Joined:
    Mar 22, 2018
    Posts:
    13
    Well it worked for one app, but not for another one....honestly....Idk what to think anymore...I was sure everything was ok...
     
  42. restauranttttt

    restauranttttt

    Joined:
    Aug 6, 2020
    Posts:
    15
    So maybe your first app was lucky. Apple ignored the problem by accident.
    Nothing new from Unity official.
    In my opinion, I think there are some not called method or strings in unity code, but we can do nothing about them. Only Unity can modify those codes. Apple think those code should not appear in Child APP. I requested apple tech supporting to check my app project.Still rejected.
     
  43. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    677
    For others having that issue, removing the Firebase SDK completely + following the steps of Unity solved the issues for me. So the issue is not on Unity's side at least, it is Firebase that is accessing one of those APIs even when not using Firebase Analytics (I've tried to remove just the Analytics first).
     
  44. PIBOCO-Developer

    PIBOCO-Developer

    Joined:
    Feb 10, 2020
    Posts:
    11
    We passed review and released a new version today. The major change was upgrading to Unity 2019 and setting the PLIST value for GOOGLE_ANALYTICS_IDFV_COLLECTION_ENABLED to NO in Info.plist (not that we hadn't tried doing that before). We still have Firebase Auth in the project. This is so confusing.
     
  45. Dan_Stradh

    Dan_Stradh

    Joined:
    Mar 22, 2018
    Posts:
    13
    Did you already had that in your plist ?
    I don't have it it any plist...
    Can you tell me in wich plist you have or add that please ?
     
  46. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    677
    I had to stick with 2018 for now, so this could be the issue for me.

    In any case, this should be an opt-in feature if this goes against any of apple's guidelines, so I still see that as an issue on Google's side.
     
  47. wwcolter

    wwcolter

    Joined:
    Nov 4, 2016
    Posts:
    28
    After a month of back and forth with Apple, the update for our kids game update finally got approved. Unity support was fantastic! We detailed our experience hoping it can help someone.
     
  48. wwcolter

    wwcolter

    Joined:
    Nov 4, 2016
    Posts:
    28
    Analytics.limitUserTracking should be set to true, but I'm doubting that's why Apple rejected your game. They rejected our exact same build twice before finally approving it. Just keep rolling the dice and hope you get a reviewer who knows what they're doing :p
     
    Last edited: Aug 26, 2020
  49. restauranttttt

    restauranttttt

    Joined:
    Aug 6, 2020
    Posts:
    15
    We noticed that your Kids Category app includes analytics, advertising and collects, transmits, or has the ability to share personal information or device information with third parties.

    Your app includes the following feature(s), contrary to guideline 1.3 of the App Store Review Guidelines:

    Third-party analytics or third-party advertising with the ability to collect, transmit or share identifiable information, including, for example, IDFA. Specifically, we found your app was made with the Unity SDK. This particular SDK contained the following selectors that pertain to advertisements:

    advertisingIdentifier

    It would be appropriate to work with Unity, in removing these selectors located in the UnityEngine.Analytics and/or UnityEngine.Advertisments components within your app before resubmitting.
     
  50. PavelLU

    PavelLU

    Unity Technologies

    Joined:
    Feb 23, 2017
    Posts:
    106