xamarin / Xamarin.Forms

Xamarin.Forms is no longer supported. Migrate your apps to .NET MAUI.
https://aka.ms/xamarin-upgrade
Other
5.62k stars 1.87k forks source link

Help needed #4906

Closed rafsanulhasan closed 5 years ago

rafsanulhasan commented 5 years ago

I need an information that couldn't find on google. I'm building a plugin for my own project that targets all of Windows (UWP+WPF), Linux using GTK, Android, MacOSX, iOS and Tizen. I have a seperate project for my customized plugins and controls with custom renderers. The project is multi-targeted for those platforms. I found everything that I need except two things. What should be the Target Frameworks for GTK & WPF. I used package references for Xamarin.Forms.Platform.GTK & Xamarin.Forms.Platform.WPF under .net 4.7.2. But what should I specify as Target Frameworks (TFM) for those two frameworks? For example we use MonoAndroid80, Xamarin.iOS10, Xamarin.Mac20 and so on.

Additionally, would you please specify the compiler directives like #if __ANDROID__ for the two platforms I stated above.

I highly appreciate your assistance. Thanks in advance.

PureWeen commented 5 years ago

If you inspect the csproj files of our GTK and WPF Control Gallery projects does that give you what you need?

https://github.com/xamarin/Xamarin.Forms/tree/master/Xamarin.Forms.ControlGallery.GTK https://github.com/xamarin/Xamarin.Forms/tree/master/Xamarin.Forms.ControlGallery.WPF

rafsanulhasan commented 5 years ago

Nope. Please Take a look at https://montemagno.com/new-plugin-for-xamarin-multi-target-templates-for-visual-studio-2017/

In that video and blog post @jamesmontemagno has discussed about creating a plugin for xamarin in a multi-targeted project.

This is my multitargeted project's .csproj file:

<Project Sdk="MSBuild.Sdk.Extras/1.6.61">

    <PropertyGroup>
        <!--Work around so the conditions work below-->
        <TargetFrameworks></TargetFrameworks>
        <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">net472;netstandard2.0;Xamarin.iOS10;MonoAndroid81;uap10.0.16299;tizen40;tizen5.0.0.14562</TargetFrameworks>
        <TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">net472;netstandard2.0;Xamarin.iOS10;Xamarin.Mac20;MonoAndroid81</TargetFrameworks>
        <!--Feel free to add as many targets as you need below
    netstandard1.0;netstandard2.0;MonoAndroid81;Xamarin.iOS10;uap10.0.16299;Xamarin.TVOS10;Xamarin.WatchOS10;Xamarin.Mac20;Tizen40
    For UWP update the version number with a version number you have installed.
    -->
        <AssemblyName>Synergy.GitHub.Core</AssemblyName>
        <RootNamespace>CodeHubX.Core</RootNamespace>
        <PackageId>Synergy.GitHub.Core</PackageId>

        <Product>$(AssemblyName) ($(TargetFramework))</Product>
        <AssemblyVersion>1.0.0.0</AssemblyVersion>
        <AssemblyFileVersion>1.0.0.0</AssemblyFileVersion>
        <Version>1.0.0.0</Version>
        <PackageVersion>1.0.0.0</PackageVersion>
        <PackOnBuild>true</PackOnBuild>
        <NeutralLanguage>en</NeutralLanguage>
        <LangVersion>default</LangVersion>
        <DefineConstants>$(DefineConstants);</DefineConstants>

        <UseFullSemVerForNuGet>false</UseFullSemVerForNuGet>
        <EnableDefaultCompileItems>false</EnableDefaultCompileItems>

        <LangVersion>latest</LangVersion>

        <!--TODO: Fill these in-->
        <PackageLicenseUrl>LINK TO LICENSE</PackageLicenseUrl>
        <PackageProjectUrl>LINK TO PROJECT</PackageProjectUrl>
        <RepositoryUrl>LINK TO PROJECT</RepositoryUrl>
        <PackageReleaseNotes>RELEASE NOTES</PackageReleaseNotes>
        <PackageIconUrl>ICON URL</PackageIconUrl>
        <PackageTags>xamarin, windows, ios, android, xamarin.forms, plugin, Synergy.GitHub.Core.Controls</PackageTags>

        <Title>Synergy.GitHub.Core.Controls Plugin for Xamarin and Windows</Title>
        <Summary>Summary of nuget</Summary>
        <Description>Plugin Description</Description>

        <Owners>YOU</Owners>
        <Authors>YOU</Authors>
        <Copyright>Copyright 2018</Copyright>
    </PropertyGroup>

    <PropertyGroup Condition=" '$(Configuration)'=='Debug' ">
        <DebugType>full</DebugType>
        <DebugSymbols>true</DebugSymbols>
        <GenerateDocumentationFile>false</GenerateDocumentationFile>
    </PropertyGroup>
    <PropertyGroup Condition=" '$(Configuration)'=='Release' ">
        <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
        <DebugType>pdbonly</DebugType>
        <GenerateDocumentationFile>true</GenerateDocumentationFile>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="Xamarin.Forms" Version="3.4.0.1009999" />
    </ItemGroup>

    <ItemGroup>
        <Compile Include="**\*.shared.cs" />
    </ItemGroup>

    <ItemGroup Condition=" $(TargetFramework.StartsWith('netstandard')) ">
        <PackageReference Include="Xamarin.Forms" Version="3.4.0.1009999" />
    </ItemGroup>

    <ItemGroup Condition=" $(TargetFramework.StartsWith('uap10.0')) ">
        <Compile Include="**\*.uwp.cs" />
        <!--
    If you need to add sdk references:
     <SDKReference Include="WindowsMobile, Version=10.0.16299.0">
      <Name>Windows Mobile Extensions for the UWP</Name>
    </SDKReference>
    -->
    </ItemGroup>

    <ItemGroup Condition=" $(TargetFramework.StartsWith('MonoAndroid')) ">
        <Compile Include="**\*.android.cs" />
    </ItemGroup>

    <ItemGroup Condition=" $(TargetFramework.StartsWith('Xamarin.iOS')) ">
        <Compile Include="**\*.ios.cs" />
    </ItemGroup>

    <ItemGroup Condition=" $(TargetFramework.StartsWith('Xamarin.TVOS')) ">
        <Compile Include="**\*.tvos.cs" />
    </ItemGroup>

    <ItemGroup Condition=" $(TargetFramework.StartsWith('Xamarin.WatchOS')) ">
        <Compile Include="**\*.watchos.cs" />
    </ItemGroup>

    <ItemGroup Condition=" $(TargetFramework.StartsWith('Xamarin.Mac'))">
        <Compile Include="**\*.mac.cs" />
    </ItemGroup>

    <!--<ItemGroup Condition=" $(TargetFramework.StartsWith('netcoreapp')) ">
        <Compile Include="**\*.netcore.cs" />
    </ItemGroup>-->

    <ItemGroup Condition=" $(TargetFramework.StartsWith('Tizen4')) ">
        <Compile Include="**\*.tizen.cs" />
        <PackageReference Include="Tizen.NET" Version="4.0.0" />
    </ItemGroup>

    <ItemGroup Condition=" $(TargetFramework.StartsWith('Tizen5')) ">
        <Compile Include="**\*.tizen.cs" />
        <PackageReference Include="Tizen.NET" Version="5.0.0.14562" />
    </ItemGroup>

    <ItemGroup Condition=" $(TargetFramework.StartsWith('net47')) ">
        <Compile Include="**\*.dotnet.cs" />
        <PackageReference Include="Xamarin.Forms.Platform.GTK" Version="3.4.0.1008975" />
        <PackageReference Include="Xamarin.Forms.Platform.WPF" Version="3.4.0.1008975" />
    </ItemGroup>
</Project>

As you can see I'm multi targeting net472;netstandard2.0;Xamarin.iOS10;MonoAndroid81;uap10.0.16299;tizen40;tizen5.0.0.14562 as my Xamarin Plugin. Besides that, I'm using these two NuGet Packages: Xamarin.Forms.Platform.GTK and Xamarin.Forms.Platform.WPF under .NET Framework

What I am trying to achieve is, I want to include these two frameworks: GTK (for Linux development using Xamarin) and WPF (for Windows 8 and lower).

My query is what should I use inside <TargetFrameworks></TargetFrameworks>.

I have looked at and studied https://github.com/jamesmontemagno/SettingsPlugin and found that I might don't need to specify specific framework for GTK & WPF because they both uses .NET Framework as Framework but I'm not sure about that.

If the statement above is correct, then I think I should use constants with compiler directives for conditional compilation Like the following code.

public class FileStorage : IFileStorage
    {
        public Task<byte[]> ReadAsBytes(string filename)
        {
                       #if __WPF__
            var data = File.ReadAllBytes(filename);

            if (data != null)
                data = data.CleanByteOrderMark();

            return Task.FromResult(data);
                       #elif __GTK__
                       return Encoding.UTF8.GetBytes(await ReadAsString(filename));
                       #endif
        }

        public async Task<string> ReadAsString(string filename)
        {
            var data = await ReadAsBytes(filename);

            if (data == null)
                return string.Empty;

            return Encoding.UTF8.GetString(data);
        }
    }

I want to know whether I need to specify a specific framework inside <TargetFrameworks></TargetFrameworks> in the project file itself or should I rather use the compiler directives in each code file.

So there is two question:

  1. If I need to specify a specific framework in the project file, what should be that? OR
  2. If I should do conditional compilation, what should be the constants in the compiler directives #If __GTK__ and #if __WPF__. Can I use GTK and WPF as constants?
PureWeen commented 5 years ago

Aw ok so those build targets come from the use of. It's not a XF thing https://github.com/onovotny/MSBuildSdkExtras

If you check out this project https://github.com/reactiveui/akavache

That uses GTK and WPF with multitargeting

rafsanulhasan commented 5 years ago

Okay, thanks @PureWeen. That somewhat helped me but after going through the Akavache project, I couldn't find the specific things that I need. Could you please refer me to specific file from that project so that I can find the specific things I need?

PureWeen commented 5 years ago

Here's an example https://github.com/reactiveui/ReactiveUI/blob/8c28dd1569009a6f4449d4f6f801c262d96a1a6c/src/ReactiveUI/ReactiveUI.csproj

I mispoke about GTK doesn't look like it supports that. I would open a ticket over here https://github.com/onovotny/MSBuildSdkExtras asking about GTK

WPF is just the net461 targets there's not a WPF target it's just net461 or net462 or whatever minimum library you want to support

rafsanulhasan commented 5 years ago

Thanks again... Can you please describe Prism VS RectiveUI?

Can I use both of them? Actually I need Prism because it simplifies the DI and Navigation. I'm also using Reactive extensions. Prior to new, I didn't know about reactiveui. Now I want to replace the reactive extensions with reactiveui because it seems that instead of doing reactive programming manually, ReactiveUI can make it easier.

PureWeen commented 5 years ago

@rafsanulhasan that's kind of a big one to explain. There is a lot of great documentation here https://reactiveui.net/

There is also a slack channel that's super active https://github.com/reactiveui/ReactiveUI#support

I haven't used Prism that much. The new Shell stuff would probably give you all you need for Navigation I bet :-) RxUI is more a toolkit to enable MVVM to be reactive whereas Prism is more an entire app pattern.