Search code examples
c#xamarin.formsnuget-packageclass-librarymultitargeting

Create multi-target Xamarin.Forms NuGet package


I'm trying to build a single NuGet package that can be installed in Xamarin.Android, Xamarin.iOS, Xamarin.UWP and Xamarin.Forms (.NET Standard) projects. I can't use .NET Standard since I need to have a custom Activity for my Android project, custom AppDelegate for my iOS project, and a custom MainPage for my UWP project. In the initiators I want to use the ServiceCollection as DI provider.

In the docs they still mention the Portable Class Library (explicitly mentioned legacy, doesn't exist anymore in VS), or Manually Creating Packages (can't figure out what to do here), and then you also have websites mentioning the Xamarin.Forms Plugin, which also doesn't exist anymore.

I already made a solution with all 4 projects, but I can't figure out how I can create a single NuGet package for all 4 projects (all 3 target platforms).

Does anyone have an idea how we can build a multi-target NuGet package containing code for Android, iOS, and UWP, just like the Xamarin.Forms NuGet package?

I've also seen discussions like this: How does one create a project to create a Nuget package for Xamarin Forms supporting iOS, Android, and UWP?, but I'm not sure if this is still relevant, since the build.props and build.targets no longer exist in the MvvmCross repo.


Solution

  • I've pushed a working version to https://github.com/MintPlayer/MintPlayer.MVVM

    csproj-file

    <Project Sdk="MSBuild.Sdk.Extras/2.0.41">
    
      <!-- You must have the Android 8.0 SDK installed through the Android SDK manager -->
    
      <PropertyGroup>
        <AssemblyName>MintPlayer.MVVM</AssemblyName>
        <RootNamespace>MintPlayer.MVVM</RootNamespace>
        <TargetFrameworks>netstandard2.0;Xamarin.iOS10;MonoAndroid80;uap10.0.16299</TargetFrameworks>
        <_WriteTelemetryProperties>false</_WriteTelemetryProperties>
        <Authors>Pieterjan De Clippel</Authors>
        <Company>MintPlayer</Company>
        <Product>MintPlayer.MVVM</Product>
        <IncludeSymbols>true</IncludeSymbols>
        <SymbolPackageFormat>snupkg</SymbolPackageFormat>
        <Description>This package allows you to implement ViewModel Navigation and Dependency Injection in a Xamarin.Forms project</Description>
        <Version>1.0.0</Version>
        <Copyright />
        <PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
        <PackageProjectUrl>https://github.com/MintPlayer/MintPlayer.MVVM</PackageProjectUrl>
        <RepositoryUrl>https://github.com/MintPlayer/MintPlayer.MVVM</RepositoryUrl>
        <PackageTags>Xamarin.Forms, Viewmodel navigation, Dependency Injection</PackageTags>
        <PackageReleaseNotes>This package is still under construction</PackageReleaseNotes>
      </PropertyGroup>
    
      <ItemGroup>
        <Compile Remove="Platforms\**\*.cs" />
        <None Include="Platforms\**\*.cs" />
        <None Include="Resources\*.cs" />
        <Compile Remove="Resources\*.cs" />
      </ItemGroup>
    
      <ItemGroup Condition=" $(TargetFramework.StartsWith('uap')) ">
        <Compile Include="Platforms\UAP\**\*.cs" />
        <Compile Include="Platforms\Common\**\*.cs" />
      </ItemGroup>
    
      <ItemGroup Condition=" $(TargetFramework.StartsWith('netstandard')) ">
        <Compile Include="Platforms\Common\**\*.cs" />
      </ItemGroup>
    
      <ItemGroup Condition=" $(TargetFramework.StartsWith('Xamarin.iOS')) ">
        <Compile Include="Platforms\iOS\**\*.cs" />
        <Compile Include="Platforms\Common\**\*.cs" />
      </ItemGroup>
    
      <ItemGroup Condition=" $(TargetFramework.StartsWith('MonoAndroid')) ">
        <Compile Include="Platforms\Android\**\*.cs" />
        <Compile Include="Platforms\Common\**\*.cs" />
        
        <AndroidResource Include="Resources\**\*.xml" SubType="Designer" Generator="MSBuild:UpdateAndroidResources" />
        <AndroidResource Include="Resources\**\*.axml" SubType="Designer" Generator="MSBuild:UpdateAndroidResources" />
      </ItemGroup>
    
      <ItemGroup>
        <None Remove="Platforms\Common\MintPlayerMvvmExtensions.cs" />
        <None Remove="Platforms\Common\NavigationService.cs" />
        <None Remove="Platforms\Common\Platform.cs" />
      </ItemGroup>
    
      <ItemGroup>
        <PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.6" />
        <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.6" />
    
        <!--<PackageReference Include="Xamarin.Forms" Version="4.5.0.495" />-->
        <PackageReference Include="Xamarin.Forms" Version="3.1.0.697729" />
      </ItemGroup>
    
    </Project>
    

    Directory.build.props

    <Project>
      <PropertyGroup>
        <Company>MintPlayer</Company>
        <Copyright>Copyright © MintPlayer</Copyright>
        <RepositoryUrl>https://github.com/MintPlayer/MintPlayer.MVVM</RepositoryUrl>
        <Authors>Pieterjan De Clippel</Authors>
        <Owners>MintPlayer</Owners>
        <PackageReleaseNotes />
        <PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
        <PublishRepositoryUrl>true</PublishRepositoryUrl>
        <RepositoryType>git</RepositoryType>
        <Product>$(AssemblyName) ($(TargetFramework))</Product>
        <NeutralLanguage>en</NeutralLanguage>
        
        <LangVersion>latest</LangVersion>
        <NoWarn>$(NoWarn);1591;1701;1702;1705;VSX1000;NU1603</NoWarn>
        <GenerateDocumentationFile Condition=" '$(Configuration)' == 'Release' ">true</GenerateDocumentationFile>
        <GeneratePackageOnBuild Condition=" '$(Configuration)' == 'Release' and '$(IsTestProject)' != 'true'">true</GeneratePackageOnBuild>
        
        <Platform>AnyCPU</Platform>
        <DebugType>portable</DebugType>
        <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
        <EmbedUntrackedSources>true</EmbedUntrackedSources>
        
        <IsTestProject>$(MSBuildProjectName.Contains('UnitTests'))</IsTestProject>
      </PropertyGroup>
    </Project>
    

    Directory.build.targets

    <Project>
      <PropertyGroup Condition="$(TargetFramework.StartsWith('netstandard'))">
        <DefineConstants>$(DefineConstants);NETSTANDARD;PORTABLE</DefineConstants>
      </PropertyGroup>
      <PropertyGroup Condition="$(TargetFramework.StartsWith('Xamarin.iOS'))">
        <DefineConstants>$(DefineConstants);MONO;UIKIT;COCOA;IOS</DefineConstants>
      </PropertyGroup>
      <PropertyGroup Condition="$(TargetFramework.StartsWith('MonoAndroid'))">
        <DefineConstants>$(DefineConstants);MONO;ANDROID</DefineConstants>
        <MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
        <AndroidResgenClass>Resource</AndroidResgenClass>
        <AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
      </PropertyGroup>
    </Project>
    

    You must add the following to your .sln file

    Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7004E39A-BAF2-4F2F-B505-CC3DEC393CB6}"
        ProjectSection(SolutionItems) = preProject
            Directory.build.props = Directory.build.props
            Directory.build.targets = Directory.build.targets
        EndProjectSection
    EndProject