Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Paket doesn't correctly handle Nougat compilation (v7/7.1) target for Xamarin.Android when installing Xamarin.Forms #2809

Closed
tastyeggs opened this issue Oct 1, 2017 · 19 comments

Comments

@tastyeggs
Copy link
Contributor

Description

When installing a Xamarin.Forms package into a Xamarin.Android application, targeting Nougat (v7.1), Paket creates references to .netstandard1.0 libraries, instead of the monoandroid libraries.

When I drop compile version (TargetFrameworkVersion) to 6.0, it links correctly against the MonoAndroid10 libraries

Repro steps

  1. Create a new Xamarin.Android project
  2. Install Xamarin.Forms (latest 2.4.0.282)
  3. Set Compile using Android version (TargetFramework) to 7.0 or 7.1 (Nougat)
  4. Builds will fail, since the Xamarin Android platform libraries are not linked, instead .netstandard1.0 libraries are linked

It seems there is an explicit condition set for Android7/7.1 for .netstandard1.0. This does not work for Xamarin.Forms.

ZIP file with solution attached.

Expected behavior

The referenced dlls must be from lib\MonoAndroid10 directory.

Actual behavior

The referenced dlls come from lib\netstandard1.0 directory.

Known workarounds

Drop compilation target framework to 6.0, or use Nuget.

test.zip

@forki
Copy link
Member

forki commented Oct 2, 2017

In the attached zip you didn't set your TargetFrameworkIdentifier to MonoAndroid

@tastyeggs
Copy link
Contributor Author

Does this need to be set? I've never had to do that.

Also why would it then work for Android 6 and below?

@forki
Copy link
Member

forki commented Oct 2, 2017

Yes I think it always need to be set - otherwise the when condition is not fulfilled

@tastyeggs
Copy link
Contributor Author

After some digging, TargetFrameworkIdentifier is set to MonoAndroid in Xamarin.Android.CSharp.targets, that's included by default in all Xamarin.Android projects:

https://github.com/xamarin/xamarin-android/blob/master/src/Xamarin.Android.Build.Tasks/Xamarin.Android.CSharp.targets

Note that we're emitting two different When conditions for Android, so this seems to be intentional:

This includes the dlls from lib\MonoAndroid10 directory:

<When Condition="$(TargetFrameworkIdentifier) == 'MonoAndroid' And ($(TargetFrameworkVersion) == 'v1.0' Or $(TargetFrameworkVersion) == 'v2.2' Or $(TargetFrameworkVersion) == 'v2.3' Or $(TargetFrameworkVersion) == 'v4.0.3' Or $(TargetFrameworkVersion) == 'v4.1' Or $(TargetFrameworkVersion) == 'v4.2' Or $(TargetFrameworkVersion) == 'v4.3' Or $(TargetFrameworkVersion) == 'v4.4' Or $(TargetFrameworkVersion) == 'v5.0' Or $(TargetFrameworkVersion) == 'v5.1' Or $(TargetFrameworkVersion) == 'v6.0')">

and then below that, this condition includes dlls from the netstandard10 directory:

<When Condition="($(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.5' Or $(TargetFrameworkVersion) == 'v4.5.1' Or $(TargetFrameworkVersion) == 'v4.5.2' Or $(TargetFrameworkVersion) == 'v4.5.3' Or $(TargetFrameworkVersion) == 'v4.6' Or $(TargetFrameworkVersion) == 'v4.6.1' Or $(TargetFrameworkVersion) == 'v4.6.2' Or $(TargetFrameworkVersion) == 'v4.6.3' Or $(TargetFrameworkVersion) == 'v4.7' Or $(TargetFrameworkVersion) == 'v5.0')) Or ($(TargetFrameworkIdentifier) == '.NETStandard' And ($(TargetFrameworkVersion) == 'v1.0' Or $(TargetFrameworkVersion) == 'v1.1' Or $(TargetFrameworkVersion) == 'v1.2' Or $(TargetFrameworkVersion) == 'v1.3' Or $(TargetFrameworkVersion) == 'v1.4' Or $(TargetFrameworkVersion) == 'v1.5' Or $(TargetFrameworkVersion) == 'v1.6' Or $(TargetFrameworkVersion) == 'v2.0')) Or ($(TargetFrameworkIdentifier) == '.NETCoreApp' And ($(TargetFrameworkVersion) == 'v1.0' Or $(TargetFrameworkVersion) == 'v1.1' Or $(TargetFrameworkVersion) == 'v2.0')) Or ($(TargetFrameworkIdentifier) == 'MonoAndroid' And ($(TargetFrameworkVersion) == 'v7.0' Or $(TargetFrameworkVersion) == 'v7.1' Or $(TargetFrameworkVersion) == 'v8.0')) Or ($(TargetFrameworkIdentifier) == 'MonoTouch') Or ($(TargetFrameworkIdentifier) == 'Xamarin.tvOS') Or ($(TargetFrameworkIdentifier) == 'Xamarin.watchOS')">

Note that we're specifically pointing MonoAndroid v7.0/v7.1/v8.0 to these directories. My guess is something to do with some recent .NET Standard change.

I'll dig through the code when I get a chance.

@tastyeggs
Copy link
Contributor Author

This likely happens because of this:

In FrameworkHandling.fs:

member internal x.RawSupportedPlatforms =
        match x with
        ...
        | MonoAndroid MonoAndroidVersion.V7 -> [ MonoAndroid MonoAndroidVersion.V6; DotNetStandard DotNetStandardVersion.V1_6 ]
        | MonoAndroid MonoAndroidVersion.V7_1 -> [ MonoAndroid MonoAndroidVersion.V7 ]
        | MonoAndroid MonoAndroidVersion.V8 -> [ MonoAndroid MonoAndroidVersion.V7_1 ]
        ...

In combination with the following nuspec:

<references>
      ...
      <group targetFramework=".NETStandard1.0">
        <reference file="Xamarin.Forms.Core.dll" />
        <reference file="Xamarin.Forms.Platform.dll" />
        <reference file="Xamarin.Forms.Xaml.dll" />
      </group>
      ...
      <group targetFramework="MonoAndroid1.0">
        <reference file="Xamarin.Forms.Core.dll" />
        <reference file="Xamarin.Forms.Platform.dll" />
        <reference file="Xamarin.Forms.Xaml.dll" />
        <reference file="FormsViewGroup.dll" />
        <reference file="Xamarin.Forms.Platform.Android.dll" />
      </group>
     ...

My guess is this causes paket to write references for Xamarin.Forms package to the .NETStandard framework for MonoAndroid 7/7.1/8. For Xamarin Forms to work properly, the references need to be made to the MonoAndroid framework.

@forki is my assessment correct? Any suggestions on how I can go about fixing this?

@forki
Copy link
Member

forki commented Nov 26, 2017

Why is setting the target framework not working for you?

@tastyeggs
Copy link
Contributor Author

Do you mean setting the framework restriction in paket.references?

I've tried setting nuget Xamarin.Forms 2.5.0.91635 framework: MonoAndroid7.1 in paket.references, but that simply leads to the removal of the unused When conditions. MonoAndroid 7/7.1/8 are still grouped under the condition that adds the .netstandard references.

@forki
Copy link
Member

forki commented Nov 26, 2017

No in very first comment I meant setting TargetFrameworkIdentifier in the csproj.

@tastyeggs
Copy link
Contributor Author

Nope, that doesn't have any impact because:

  1. TargetFrameworkIdentifier is set by Xamarin.Android.CSharp.targets anyway
  2. The real issue here is MonoAndroid 7/7.1/8 are treated differently from MonoAndroid <= 6, and as a result they aren't getting the essential references required to compile the project.

See the above two When conditions in my third comment -- MonoAndroid 7/7.1/8 are set to use references from the .netstandard directory instead of the MonoAndroid10 directory. This works just fine when I set TargetFrameworkVersion to 6.0

@forki
Copy link
Member

forki commented Nov 26, 2017 via email

@matthid
Copy link
Member

matthid commented Nov 26, 2017

TargetFrameworkIdentifier is set by Xamarin.Android.CSharp.targets anyway

That doesn't mean paket can find it...

@forki
Copy link
Member

forki commented Nov 26, 2017 via email

@tastyeggs
Copy link
Contributor Author

Sure, I've attached two csproj files in the ZIP file:

  1. Orig.csproj is what paket currently generates
  2. Modified.csproj is what it should generate for Xamarin.Forms to correctly work. Note that this affects lots of other packages as well -- as long as Xamarin.Android's Target Framework is set to >= 7.0 (Nougat/Oreo).

CSProjs.zip

@tastyeggs
Copy link
Contributor Author

Apologies, closed by mistake

@tastyeggs tastyeggs reopened this Dec 1, 2017
@ylatuya
Copy link

ylatuya commented Dec 14, 2017

I can reproduce the issue too, where for Android it's using lib/netstandard1.0 instead of lib/MonoAndroid10.
My csproj is using, adding TargetFrameworkIdentifier although it's not needed since Xamarin.Android.CSharp.targets is already setting it

 <TargetFrameworkVersion>v7.0</TargetFrameworkVersion>
 <TargetFrameworkIdentifier>MonoAndroid</TargetFrameworkIdentifier>

Here is the relevant part of the csproj where for iOS it's doing it correctly and for Android it's using the same condition as for Net45

285   <Choose>
286     <When Condition="$(TargetFrameworkIdentifier) == 'Xamarin.iOS'">
287       <ItemGroup>
288         <Reference Include="Xamarin.Forms.Core">
289           <HintPath>..\..\packages\Xamarin.Forms\lib\Xamarin.iOS10\Xamarin.Forms.Core.dll</HintPath>
290           <Private>True</Private>
291           <Paket>True</Paket>
292         </Reference>
293         <Reference Include="Xamarin.Forms.Platform">
294           <HintPath>..\..\packages\Xamarin.Forms\lib\Xamarin.iOS10\Xamarin.Forms.Platform.dll</HintPath>
295           <Private>True</Private>
296           <Paket>True</Paket>
297         </Reference>
298         <Reference Include="Xamarin.Forms.Platform.iOS">
299           <HintPath>..\..\packages\Xamarin.Forms\lib\Xamarin.iOS10\Xamarin.Forms.Platform.iOS.dll</HintPath>
300           <Private>True</Private>
301           <Paket>True</Paket>
302         </Reference>
303         <Reference Include="Xamarin.Forms.Xaml">
304           <HintPath>..\..\packages\Xamarin.Forms\lib\Xamarin.iOS10\Xamarin.Forms.Xaml.dll</HintPath>
305           <Private>True</Private>
306           <Paket>True</Paket>
307         </Reference>
308       </ItemGroup>
309     </When>
310     <When Condition="($(TargetFrameworkIdentifier) == 'MonoAndroid' And $(TargetFrameworkVersion) == 'v7.0') Or ($(TargetFrameworkIdentifier) == '.NETFramework' And $(TargetFrameworkVersion) == 'v4.5')">
311       <ItemGroup>
312         <Reference Include="Xamarin.Forms.Core">
313           <HintPath>..\..\packages\Xamarin.Forms\lib\netstandard1.0\Xamarin.Forms.Core.dll</HintPath>
314           <Private>True</Private>
315           <Paket>True</Paket>
316         </Reference>
317         <Reference Include="Xamarin.Forms.Platform">
318           <HintPath>..\..\packages\Xamarin.Forms\lib\netstandard1.0\Xamarin.Forms.Platform.dll</HintPath>
319           <Private>True</Private>
320           <Paket>True</Paket>
321         </Reference>
322         <Reference Include="Xamarin.Forms.Xaml">
323           <HintPath>..\..\packages\Xamarin.Forms\lib\netstandard1.0\Xamarin.Forms.Xaml.dll</HintPath>
324           <Private>True</Private>
325           <Paket>True</Paket>
326         </Reference>
327       </ItemGroup>
328     </When>
329   </Choose>

And this is how it should be

  <Choose>
    <When Condition="$(TargetFrameworkIdentifier) == 'Xamarin.iOS'">
      <ItemGroup>
        <Reference Include="Xamarin.Forms.Core">
          <HintPath>..\..\packages\Xamarin.Forms\lib\Xamarin.iOS10\Xamarin.Forms.Core.dll</HintPath>
          <Private>True</Private>
          <Paket>True</Paket>
        </Reference>
        <Reference Include="Xamarin.Forms.Platform">
          <HintPath>..\..\packages\Xamarin.Forms\lib\Xamarin.iOS10\Xamarin.Forms.Platform.dll</HintPath>
          <Private>True</Private>
          <Paket>True</Paket>
        </Reference>
        <Reference Include="Xamarin.Forms.Platform.iOS">
          <HintPath>..\..\packages\Xamarin.Forms\lib\Xamarin.iOS10\Xamarin.Forms.Platform.iOS.dll</HintPath>
          <Private>True</Private>
          <Paket>True</Paket>
        </Reference>
        <Reference Include="Xamarin.Forms.Xaml">
          <HintPath>..\..\packages\Xamarin.Forms\lib\Xamarin.iOS10\Xamarin.Forms.Xaml.dll</HintPath>
          <Private>True</Private>
          <Paket>True</Paket>
        </Reference>
      </ItemGroup>
    </When>
    <When Condition="$(TargetFrameworkIdentifier) == 'MonoAndroid'">
      <ItemGroup>
        <Reference Include="Xamarin.Forms.Core">
          <HintPath>..\..\packages\Xamarin.Forms\lib\MonoAndroid10\Xamarin.Forms.Core.dll</HintPath>
          <Private>True</Private>
          <Paket>True</Paket>
        </Reference>
        <Reference Include="Xamarin.Forms.Platform">
          <HintPath>..\..\packages\Xamarin.Forms\lib\MonoAndroid10\Xamarin.Forms.Platform.dll</HintPath>
          <Private>True</Private>
          <Paket>True</Paket>
        </Reference>
        <Reference Include="Xamarin.Forms.Platform.iOS">
          <HintPath>..\..\packages\Xamarin.Forms\lib\MonoAndroid10\Xamarin.Forms.Platform.Android.dll</HintPath>
          <Private>True</Private>
          <Paket>True</Paket>
        </Reference>
        <Reference Include="Xamarin.Forms.Xaml">
          <HintPath>..\..\packages\Xamarin.Forms\lib\MonoAndroid10\Xamarin.Forms.Xaml.dll</HintPath>
          <Private>True</Private>
          <Paket>True</Paket>
        </Reference>
      </ItemGroup>
    </When>
    <When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And $(TargetFrameworkVersion) == 'v4.5'">
      <ItemGroup>
        <Reference Include="Xamarin.Forms.Core">
          <HintPath>..\..\packages\Xamarin.Forms\lib\netstandard1.0\Xamarin.Forms.Core.dll</HintPath>
          <Private>True</Private>
          <Paket>True</Paket>
        </Reference>
        <Reference Include="Xamarin.Forms.Platform">
          <HintPath>..\..\packages\Xamarin.Forms\lib\netstandard1.0\Xamarin.Forms.Platform.dll</HintPath>
          <Private>True</Private>
          <Paket>True</Paket>
        </Reference>
        <Reference Include="Xamarin.Forms.Xaml">
          <HintPath>..\..\packages\Xamarin.Forms\lib\netstandard1.0\Xamarin.Forms.Xaml.dll</HintPath>
          <Private>True</Private>
          <Paket>True</Paket>
        </Reference>
      </ItemGroup>
    </When>

@ylatuya
Copy link

ylatuya commented Dec 14, 2017

Here is a diff of the changes after trying to upgrade to Xamarin.Forms 2.5 that explains a bit better the impact of the issue:
https://gist.github.com/ylatuya/55eb4104b436c053c59dcd9e63e28f8b

@ylatuya
Copy link

ylatuya commented Dec 15, 2017

I have found another issue related to the same problem. Xamarin.Forms 2.5 has dependencies to Xamarin.Android.Support.foo packages that are no longer referenced in the csproj either.

@ylatuya
Copy link

ylatuya commented Jan 9, 2018

Is there anything else we can do to help resolve this issue? I would like to help but I have zero experience in F# or any other functional language. Paket is currently unusable right now for Xamarin Forms projects and we have to manually update dependencies. Rolling back to using nuget would be a downgrade in functionalities and we'd like to avoid it at any cost :)

@forki forki closed this as completed in 94f8149 Jan 11, 2018
@forki
Copy link
Member

forki commented Jan 11, 2018

should be fixed. I added a penalty for switiching from monoandroid to netstandard

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants