xamarin / GoogleApisForiOSComponents

MIT License
225 stars 156 forks source link

[Firebase/Database] Don't link with icucore. #626

Closed rolfbjarne closed 10 months ago

rolfbjarne commented 10 months ago

This avoids a problem where we might accidentally link with private symbols exported by libicucore.dylib instead of the same symbols provided in a static library.

This would show up as an App Store rejection:

TMS-90338: Non-public API usage - The app references non-public symbols:
_ubrk_openRules, _ucal_add, _ucal_close, _ucal_get, _ucal_getAttribute,
_ucal_getKeywordValuesForLocale, _ucal_getNow, _ucal_getTimeZoneDisplayName,
_ucal_getTimeZoneIDForWindowsID, _ucal_getWindowsTimeZoneID, _ucal_open,
_ucal_openTimeZoneIDEnumeration, _ucal_set, _ucal_setMillis, _ucol_close,
_ucol_closeElements, _ucol_getOffset, _ucol_getRules, _ucol_getSortKey,
_ucol_getStrength, _ucol_getVersion, _ucol_next, _ucol_open,
_ucol_openElements, _ucol_openRules, _ucol_previous, _ucol_safeClone,
_ucol_setAttribute, _ucol_setVariableTop, _ucol_strcoll, _ucurr_forLocale,
_ucurr_getName, _udat_close, _udat_countSymbols, _udat_format,
_udat_getSymbols, _udat_open, _udat_setCalendar, _udat_toPattern,
_udata_setCommonData, _udatpg_close, _udatpg_getBestPattern, _udatpg_open,
_uenum_close, _uenum_count, _uenum_next, _uldn_close,
_uldn_keyValueDisplayName, _uldn_open, _uloc_canonicalize,
_uloc_countAvailable, _uloc_getAvailable, _uloc_getBaseName,
_uloc_getCharacterOrientation, _uloc_getCountry, _uloc_getDefault,
_uloc_getDisplayCountry, _uloc_getDisplayLanguage, _uloc_getDisplayName,
_uloc_getISO3Country, _uloc_getISO3Language, _uloc_getKeywordValue,
_uloc_getLCID, _uloc_getLanguage, _uloc_getName, _uloc_getParent,
_uloc_setKeywordValue, _ulocdata_getCLDRVersion,
_ulocdata_getMeasurementSystem, _unorm2_getNFDInstance,
_unorm2_getNFKCInstance, _unorm2_getNFKDInstance, _unorm2_isNormalized,
_unum_close, _unum_getAttribute, _unum_getSymbol, _unum_open, _unum_toPattern,
_ures_close, _ures_getByKey, _ures_getSize, _ures_getStringByIndex,
_ures_open, _usearch_close, _usearch_first, _usearch_getBreakIterator,
_usearch_getMatchedLength, _usearch_last, _usearch_openFromCollator,
_usearch_setPattern, _usearch_setText.

This is what happens:

  1. Mono uses ICU for various purposes, and we ship the corresponding helper code as a static library (libicui18n.a).
  2. iOS also uses ICU, and does so privately, we have no access to iOS’ copy of those libraries.
  3. FirebaseDatabase links with libicucore.dylib (this is a dylib shipped in iOS). I’m not exactly sure why FirebaseDatabase does this, but it seems to be allowed by Apple.
  4. libicucore.dylib exports some of the symbols from iOS’ (private) copy of ICU. I’m assuming this is just an implementation detail on Apple’s side, and why they’ve added checks to the App Store to reject any apps that reference these private symbols. When using FirebaseDatabase, we end up asking the native linker to link with libicucore.dylib (-licucore) due to the LinkerFlags in the NativeReference item.
  5. We already ask the native linker to link with our own static version of ICU (from step 1) – by passing the path to the static library in question (libicui18n.a)
  6. Depending on which native linker argument comes first (-licucore or libicui18n.a) the native linker will find the symbols in one place or the other. If found in Apple’s libicucore.dylib, the app ends up rejected by the App Store.

So avoid all of this by making FirebaseDatabase not link with libicucore.dylib.

rolfbjarne commented 10 months ago

A workaround is to add something like this to the main app's project file:

<Target Name="DoNotLinkWithIcuCore" AfterTargets="_LoadLinkerOutput">
    <ItemGroup>
        <_AssemblyLinkerFlags Remove="-licucore" />
    </ItemGroup>
</Target>
<Target Name="DoNotLinkWithIcuCore2" AfterTargets="_ExpandNativeReferences">
    <ItemGroup>
        <_FrameworkNativeReference Update="@(_FrameworkNativeReference)" Condition="$([System.String]::Copy(&quot;%(_FrameworkNativeReference.LinkerFlags)&quot;).Contains (&quot;licucore&quot;))">
                <LinkerFlags>$([System.String]::Copy('%(_FrameworkNativeReference.LinkerFlags)').Replace('-licucore',''))</LinkerFlags>
        </_FrameworkNativeReference>
    </ItemGroup>
</Target>