Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save lucas-zimerman/2ea62cf172bf049fa61d48026135bbb9 to your computer and use it in GitHub Desktop.
Save lucas-zimerman/2ea62cf172bf049fa61d48026135bbb9 to your computer and use it in GitHub Desktop.
MSBuild Join privacyinfo files into one (WIP)
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Clears the bundle from any privacy info file created by Sentry.-->
<Target Name="ClearSentryBundleResource" BeforeTargets="PrepareForBuild" Condition="'$(Platform)' == 'iPhone' Or '$(Platform)' == 'iOS' or $(Platform) == 'iPhoneSimulator'">
<Message Importance="high" Text="Target ClearSentryBundleResource $(Platform)"/>
<PropertyGroup>
<PrivacyInfoFileName>PrivacyInfo.xcprivacy</PrivacyInfoFileName>
<SentryTargetEnabled>true</SentryTargetEnabled>
</PropertyGroup>
<ItemGroup>
<ItemsToRemove Include="@(BundleResource)" Condition="'%(FullPath)' == '$(OutputPath)$(PrivacyInfoFileName)'" />
<BundleResource Remove="@(ItemsToRemove)" />
</ItemGroup>
<Message Importance="high" Text="Sentry found privacy info files at @(UserPrivacyInfoIdentity) AND @(BundleResource)"/>
</Target>
<Target Name="FindUserPrivacyInfo" DependsOnTargets="ClearSentryBundleResource" AfterTargets="ClearSentryBundleResource" Condition="'$(SentryTargetEnabled)' == 'true'">
<Message Importance="high" Text="Target FindUserPrivacyInfo"/>
<PropertyGroup>
<UserPrvacyInfoFileName>UserPrivacyInfo.xcprivacy</UserPrvacyInfoFileName>
</PropertyGroup>
<!-- Iterate through each bundled resource and print its path -->
<ItemGroup>
<ProjectPrivacyInfoList Include="@(BundleResource)" Condition="'%(Filename)%(Extension)' == '$(UserPrvacyInfoFileName)'"/>
</ItemGroup>
<PropertyGroup>
<UserPrivacyInfoFullPath>@(ProjectPrivacyInfoList->'%(FullPath)')</UserPrivacyInfoFullPath>
<UserPrivacyInfoIdentity>@(ProjectPrivacyInfoList->'%(Identity)')</UserPrivacyInfoIdentity>
</PropertyGroup>
<Message Importance="high" Text="Sentry found privacy info files at @(UserPrivacyInfoIdentity) AND @(BundleResource)"/>
</Target>
<Target Name="ValidateUserPrivacyInfo"
DependsOnTargets="FindUserPrivacyInfo" AfterTargets="FindUserPrivacyInfo"
Condition="'$(UserPrivacyInfoIdentity)' != '' And '$(SentryTargetEnabled)' == 'true'">
<Message Importance="high" Text="Target ValidateUserPrivacyInfo"/>
<Message Importance="high" Text="Sentry found Privacy Info on the solution, preparing to merge Sentry Privacy info with the project Privacy info."/>
<ItemGroup>
<BundleResource Remove="$(UserPrivacyInfoIdentity)" />
</ItemGroup>
<PropertyGroup>
<PrivacyInfoHasRequiredFields>false</PrivacyInfoHasRequiredFields>
<HasPrivacyAPIKey>false</HasPrivacyAPIKey>
<MatchedKeys>false</MatchedKeys>
</PropertyGroup>
<!-- Check if the user Privacy Info has the minimum required fields -->
<!-- Only the basic fields are required, we don't need to be too rigid if the formating is missing some extra bits. -->
<XmlPeek XmlInputPath="$(UserPrivacyInfoFullPath)" Query="//plist/@version">
<Output TaskParameter="Result" ItemName="plistVersion"/>
</XmlPeek>
<Message Importance="high" Text="DID I RUN?"/>
<XmlPeek XmlInputPath="$(UserPrivacyInfoFullPath)" Query="//plist/dict">
<Output TaskParameter="Result" ItemName="privacyDictionary"/>
</XmlPeek>
<!-- NIT making it easier to read -->
<PropertyGroup Condition="'@(privacyDictionary)' != ''">
<privacyDictionary>@(privacyDictionary)</privacyDictionary>
</PropertyGroup>
<PropertyGroup Condition="'@(plistVersion)' != '' And '$(privacyDictionary)' != ''">
<PrivacyInfoHasRequiredFields>true</PrivacyInfoHasRequiredFields>
</PropertyGroup>
<Warning Text="Sentry found an invalid PrivacyInfo.xcprivacy file on your project so it cannot apply privacy info changes needed by Sentry." Condition="'$(PrivacyInfoHasRequiredFields)' == 'false'"/>
<PropertyGroup Condition=" $(privacyDictionary.Contains('NSPrivacyAccessedAPITypes'))">
<HasPrivacyAPIKey>true</HasPrivacyAPIKey>
</PropertyGroup>
</Target>
<Target Name="Create_TemporaryPrivacyFile"
DependsOnTargets="ValidateUserPrivacyInfo" AfterTargets="ValidateUserPrivacyInfo"
Condition="'$(PrivacyInfoHasRequiredFields)' == 'true' and '$(SentryTargetEnabled)' == 'true'">
<Message Importance="high" Text="Target Create_TemporaryPrivacyFile"/>
<PropertyGroup>
<TemporaryNewPrivacyFile>$(OutDir)$(PrivacyInfoFileName)</TemporaryNewPrivacyFile>
<!-- Define the XML content to be added -->
</PropertyGroup>
<!-- Copy the file to the build output directory -->
<Copy SourceFiles="$(UserPrivacyInfoFullPath)" DestinationFolder="$(OutDir)"/>
<Message Importance="high" Text="Creating $(TemporaryNewPrivacyFile)"/>
<ItemGroup>
<Content Include="$(TemporaryNewPrivacyFile)">
<Link>PrivacyInfo.xcprivacy</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Target>
<Target Name="Delete_TemporaryPrivacyFile"
DependsOnTargets="Create_TemporaryPrivacyFile" AfterTargets="Build"
Condition="'$(PrivacyInfoHasRequiredFields)' == 'true' and '$(SentryTargetEnabled)' == 'true'">
<Message Importance="high" Text="Target Delete_TemporaryPrivacyFile"/>
<ItemGroup>
<Content Remove="@(Content)" />
</ItemGroup>
<Message Importance="high" Text="Removing $(TemporaryNewPrivacyFile)"/>
<Delete Files="$(TemporaryNewPrivacyFile)" />
</Target>
<Target Name="AddNewPrivacyKeys"
DependsOnTargets="Create_TemporaryPrivacyFile" AfterTargets="Create_TemporaryPrivacyFile"
Condition="'$(HasPrivacyAPIKey)' == 'false' And '$(SentryTargetEnabled)' == 'true'">
<Message Importance="high" Text="Target AddNewPrivacyKeys"/>
<Message Importance="high" Text="LETS GO! new keys Copy $(UserPrivacyInfoFullPath) to $(FullOutDirPath)"/>
<PropertyGroup>
<!-- Define the XML content to be added -->
<NewXmlContent>
<![CDATA[
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>C617.1</string>
</array>
</dict>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>35F9.1</string>
</array>
</dict>
</array>
]]>
</NewXmlContent>
</PropertyGroup>
<!-- Merge User dictionary with Sentry Privacy manifest.-->
<XmlPeek
XmlInputPath="$(TemporaryNewPrivacyFile)"
Query="//plist/dict/*">
<Output TaskParameter="Result" ItemName="UserPrivacyDict" />
</XmlPeek>
<PropertyGroup>
<UserPrivacyDict>@(UserPrivacyDict)</UserPrivacyDict>
</PropertyGroup>
<XmlPoke
XmlInputPath="$(TemporaryNewPrivacyFile)"
Query="/plist/dict"
Value="$([System.String]::Concat($(UserPrivacyDict), $(NewXmlContent))) "/>
<Message Importance="High" Text="TEST $(UserPrivacyDict) AND $(UserPrivacyDict)"/>
</Target>
<Target Name="MergePrivacyKeys"
DependsOnTargets="Create_TemporaryPrivacyFile" AfterTargets="Create_TemporaryPrivacyFile"
Condition="'$(HasPrivacyAPIKey)' == 'true'">
<Message Importance="high" Text="Target MergePrivacyKeys"/>
</Target>
<Target Name="AddNewPrivacyInfo"
DependsOnTargets="FindUserPrivacyInfo" AfterTargets="FindUserPrivacyInfo"
Condition="'$(UserPrivacyInfoIdentity)' == '' And '$(SentryTargetEnabled)' == 'true'">
<Message Importance="high" Text="Target AddNewPrivacyInfo"/>
<Message Importance="high" Text="Applying Sentry PrivacyInfo to the project output"/>
<PropertyGroup>
<!-- Get the folder path of the .targets file -->
<SentryPrivacyFile Condition="'$(TargetsFolderPath)' == ''">$(MSBuildThisFileDirectory)../Privacy/SentryPrivacyInfo.xcprivacy</SentryPrivacyFile>
</PropertyGroup>
<ItemGroup>
<Content Include="$(SentryPrivacyFile)">
<Link>PrivacyInfo.xcprivacy</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Target>
<Target Name="AddNewPrivacyInfo_RemoveAfterBuild" DependsOnTargets="AddNewPrivacyInfo" AfterTargets="Build"
Condition="'$(UserPrivacyInfoIdentity)' == '' And '$(SentryTargetEnabled)' == 'true'">
<Message Importance="high" Text="Target AddNewPrivacyInfo_RemoveAfterBuild"/>
<ItemGroup>
<!-- Use the Remove task to remove the Content item -->
<Content Remove="@(Content)" />
</ItemGroup>
</Target>
</Project>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment