我正在使用 SDK 风格的多目标项目升级 Xamarin Native 解决方案以在 .net 6 上运行。
据我了解,编写平台相关代码有两种方法: a) 相应平台目录(例如“iOS”或“MacCatalyst”)内的代码始终针对该平台进行有条件编译。 b) 代码可以通过例如
#if IOS
. 进行显式条件编译
当两个平台之间共享大量代码时,这两种方法似乎都不理想。 (a) 中的代码是重复的,而 (b) 中的代码则布满了
#if
s。
有没有更好的方法在这两个平台之间共享代码?
MSBuild Conditions可用于控制不同情况下的构建操作。
考虑到
true
的默认值 <EnableDefaultCompileItems>
,最简单的方法是从不应该包含该文件夹的目标中删除该文件夹。
目标是让(大多数)iOS 代码同时包含在 iOS 和 MacCatalyst 上;因此将其从所有其他目标框架中排除。
步骤:
iosShared
。YourProject.csproj
来停止这种情况: <ItemGroup Condition="'$(TargetFramework)' != 'net6.0-ios' And
'$(TargetFramework)' != 'net6.0-maccatalyst'">
<Compile Remove="iosShared\**\*" />
</ItemGroup>
我正在考虑在
Platforms/iOS
下创建一个“共享”文件夹
并将该文件夹符号链接到 Platforms/MacCatalyst/Shared
。
仍在等待其他答案,以及对此答案的评论。
编辑:我在 Visual Studio For Mac 2022 上尝试过此操作。
Platforms/MacCatalyst/Shared
处的符号链接文件夹在解决方案资源管理器中显示为带有红色标题的单个文件,即,其子树不可见。然而,该项目对于 iOS 和 Mac Catalyst 来说都符合要求。由于共享代码可以从其原始位置 Platforms/iOS/Shared
访问,因此这看起来像是有效的策略,尽管有些不受支持。
迟到加入讨论。这是我想出的解决方案。以下代码片段会智能地复制 iOS 中已更改的 .cs 文件,并确保删除 MacCatalyst 下所有在 iOS 下不再具有等效同级文件的 .cs 文件。
请注意,如果您要在 CI 管道中使用它,则必须在 .csproj 上启动构建之前显式且单独地调用目标“CloneIOSSourceCodeToMacCatalyst_Impl”,如下所示:
<!-- its vital to call this target explicitly before compilation kicks in -->
<Message Importance="High" Text="** [Builder] Copying iOS *.cs -> MacCatalyst"/>
<MSBuild Projects="path/to/your/project.csproj" Targets="CloneIOSSourceCodeToMacCatalyst_Impl"/>
<!-- COMPILE -->
<MSBuild Projects="path/to/your/project.csproj" Targets="Build"/>
以及片段本身:
<!-- this is meant to be an automation automatically invoked by the IDE itself to make our lives a bit easier -->
<Target Condition=" $([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst' "
Name="CloneIOSSourceCodeToMacCatalyst"
BeforeTargets="CoreCompile">
<CallTarget Targets="CloneIOSSourceCodeToMacCatalyst_Impl"/>
</Target>
<!-- we made this a separate target without conditions so that it will be directly invocable by our build script -->
<Target Name="CloneIOSSourceCodeToMacCatalyst_Impl">
<Message Importance="High" Text="**** [CloneIOSSourceCodeToMacCatalyst_Impl] Copying iOS *.cs -> MacCatalyst"/>
<!-- intelligently copy over only the files that changed from ios -->
<ItemGroup>
<iOSFiles Include="Platforms\iOS\**\*.*"/>
</ItemGroup>
<Copy SourceFiles="@(iOSFiles)"
DestinationFolder="Platforms\MacCatalyst\%(RecursiveDir)"
SkipUnchangedFiles="true"/>
<!-- and now delete all those files under mac-catalyst that no longer have an equivalent sibling file under ios -->
<ItemGroup>
<MacCatalystSourceFiles Include="$([System.IO.Directory]::GetFiles('Platforms\MacCatalyst', '*.cs', SearchOption.AllDirectories))" />
<MacCatalystSourceFiles>
<RespectiveIosFilePath>$([System.String]::Copy('%(Identity)').Replace('MacCatalyst', 'iOS'))</RespectiveIosFilePath>
</MacCatalystSourceFiles>
<RespectiveIosFiles Include="@(MacCatalystSourceFiles->'%(RespectiveIosFilePath)')" />
<RespectiveIosFilesThatDontExist Include="@(RespectiveIosFiles)" Condition=" !Exists(%(RespectiveIosFiles.Identity)) " />
<RespectiveIosFilesThatDontExist>
<RespectiveMacCatalystFilePath>$([System.String]::Copy('%(Identity)').Replace('iOS', 'MacCatalyst'))</RespectiveMacCatalystFilePath>
</RespectiveIosFilesThatDontExist>
<MacCatalystStrayFilesToDelete Include="@(RespectiveIosFilesThatDontExist->'%(RespectiveMacCatalystFilePath)')" />
</ItemGroup>
<Delete Files="@(MacCatalystStrayFilesToDelete)" />
<Touch Files="Platforms\MacCatalyst\_DONT_EDIT_ANY_FILES_IN_HERE__ITS_POINTLESS_" AlwaysCreate="true" Condition=" !Exists('Platforms\MacCatalyst\_DONT_EDIT_ANY_FILES_IN_HERE__ITS_POINTLESS_') " />
</Target>