How to build x86 and ARM in a single apk under Xamarin? - xamarin

In my setup, I have a simple Xamarin app MyApp under Visual Studio 2015. The wizard automatically generates various sub-projects such as MyApp.Droid, MyApp.iOS, etc. I also have a C++ Android Shared Dynamic Library project MyShared in the solution and MyApp.Droid has a reference to MySharedproject. Here is the relevant information from MyApp.Droid.csproj file:
<ItemGroup>
<ProjectReference Include="..\..\MyShared\MyShared.vcxproj">
<Project>{4301be08-ecf3-4c36-a487-473858bc5506}</Project>
<Name>MyShared</Name>
<TargetPlatformIdentifier>Android</TargetPlatformIdentifier>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\MyApp\MyApp.csproj">
<Project>{321FA0D9-3F50-4AC3-8F86-4E97DCA3FA86}</Project>
<Name>MyApp</Name>
</ProjectReference>
</ItemGroup>
Project MyApp.Droid also has armeabi-v7a and x86 platforms selected under Properties-->Android Options-->Advanced settings.
When I build the solution and export the apk file, here is what I see under lib/ directory:
lib/x86/libMyShared.so
lib/x86/libmonodroid.so
lib/x86/libmonosgen-2.0.so
lib/armeabi-v7a/libmonodroid.so
lib/armeabi-v7a/libmonosgen-2.0.so
As you can see, libMyShared.so is missing for armeabi-v7a architecture.
How do I configure the project such that libMyShared.so is built and pulled in for both the architectures? Regards.

Related

Uno.dll :: Could not load file or assembly 'Uno, Version=255.255.255.255'

Trying to reference Windows.Devices.Geolocation to use the Geolocator class from a .NET 6 core WinUI desktop head. I suspect - I am not sure - maybe the NetStandard flavor of Uno.dll intending to load here and that is why FileNotFoundException ?
FileNotFoundException: Could not load file or assembly 'Uno, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
<PackageReference Include="Uno.WinUI" Version="4.2.6" />
Perhaps a little bit of WinDBG helps anything ? For me nothing.
What is more, it is not just a run time issue, even Visual Studio can't locate the assembly in source :
Procmon reveils, the assembly is found in the right nuget folder but the respective application process log not found:
I made a PR to your GitHub repro, but the steps needed were as follows.
First, the library had to be switched to multi-targeted by changing to <TargetFrameworks> in the .csproj:
<PropertyGroup>
<TargetFrameworks>net6.0;net6.0-windows10.0.19041.0</TargetFrameworks>
</PropertyGroup>
Now the net6.0 target is for all Uno targets and the net6.0-windows10.0.19041.0 is specifically for WinAppSDK on Windows desktop.
Secondly, the Uno.WinUI needs to be referenced only on Uno targets, so:
<ItemGroup Condition="'$(TargetFramework)' != 'net6.0-windows10.0.19041.0'">
<PackageReference Include="Uno.WinUI" Version="4.2.6" />
</ItemGroup>
After these changes, the Windows project will no longer try to access the Geolocator type from Uno.dll and will use the proper Windows SDK Geolocator:

Create nuget package that references referenced .dlls without using .nuspec

Problem: Top level project references MyLibrary nuget which references several vendor.dll files. Vendor.dll files should be able to be referenced by top level project when MyLibrary nuget package is added to top level project but they are not.
When I run the top level project I receive this error:
FileNotFoundException: Could not load file or assembly 'Vendor.A, Culture=neutral, PublicKeyToken=b88d1754d700e49a'. The system cannot find the file specified.
Vendor .dll files are not copied to bin folder.
I hope to find a resolution to this problem that does not require me to create a .nuspec file.
Structure of generated MyLibrary nuget package (observed with Nuget package explorer):
lib
net5.0-windows
Vendor.a.dll
Vendor.b.dll
net5.0-windows7.0
MyLibrary.dll
I do not understand where net5.0-windows7.0 comes from. It does not exist in TFM list referenced below. Also, if net5.0-windows7.0 is for some reason necessary, why does MyLibrary.dll exist there but not the .dlls it depends on?
Looking at the package from within Visual Studio 2019 it appears as follows (vendor dlls do not appear):
Packages
MyLibrary
Compile Time Assemblies
MyLibrary.dll
MyLibrary.csproj:
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFramework>net5.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<PropertyGroup>
<AssemblyVersion>1.0.0.1</AssemblyVersion>
<FileVersion>1.0.0.1</FileVersion>
<Version>1.0.0.3</Version>
</PropertyGroup>
<ItemGroup>
<Content Include="$(OutputPath)\Vendor.*.dll">
<Pack>true</Pack>
<PackagePath>lib\$(TargetFramework)</PackagePath>
</Content>
</ItemGroup>
<ItemGroup>
<Reference Include="Vendor.a">
<HintPath>VendorLib\Vendor.a.dll</HintPath>
</Reference>
<Reference Include="Vendor.b">
<HintPath>VendorLib\Vendor.b.dll</HintPath>
</Reference>
</ItemGroup>
TopLevel.csproj
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MyLibrary" Version="1.0.0.3" />
</ItemGroup>
Target Framework Monikers
Similar question
Similar question requiring nuspec
Similar question requiring nuspec
Possibly related issue
I also found an issue about this strange behavior and still did not know where the net5.0-windows7.0 from. Since the issue is still open and the Team does not know it is normal or a strange issue, as my opinion, net5.0-windows7.0 is the special version for wpf project's frameowork of nuget, so you should pack your dlls into such folder of nupkg.
Although this is not the best function, but is a workaround now. You can keep tracking the issue to get the explanation from the Product Team.
Or try my suggestions:
function one
1) change the targetframwork of your nuget project to
<TargetFramework>net5.0-windows7.0</TargetFramework>
As the Team said, net5.0-windows is the same as net5.0-windows7.0. However, they treat them differently in terms of packaging into nuget.
function two
2) still use <TargetFramework>net5.0-windows</TargetFramework>.
change this to:
<ItemGroup>
<Content Include="$(OutputPath)\Vendor.*.dll">
<Pack>true</Pack>
<PackagePath>lib\$(TargetFramework)7.0</PackagePath>
</Content>
</ItemGroup>
Besides, when you finish packing nuget project, please delete nuget caches first or delete all files under C:\Users\xxx\.nuget\packages, then install the new release version of the nuget package into the main project.
vendor is my custom nuget project name.

How should I include Package References in a VSIX project

My solution creates a Visual Studio Package from multiple projects, using multiple NuGet packages.
All of the Nuget packages are specified in the project files using PackageReference (rather than the older packages.config file). I am using Visual Studio 2019.
I have had a problem, that the DLLs referenced by NuGet Packages are not included in the VSIX installation.
There is a solution to this problem, described in this article by Daniel Cazzulino, by adding the following code to the project file:
<PropertyGroup>
<GetVsixSourceItemsDependsOn>$(GetVsixSourceItemsDependsOn);IncludeNuGetResolvedAssets</GetVsixSourceItemsDependsOn>
</PropertyGroup>
<Target Name="IncludeNuGetResolvedAssets" DependsOnTargets="ResolveNuGetPackageAssets">
<ItemGroup>
<VSIXCopyLocalReferenceSourceItem Include="#(ReferenceCopyLocalPaths)" />
</ItemGroup>
</Target>
This does work, but it blows up the size of the installation from about 20MB to about 40MB.
The installation now includes a lot of PDB files, which I don't really need.
More significantly, it brings in about 46MB of Visual Studio DLLs which are not necessary, because they are part of Visual Studio.
Is there a better way to ensure that the referenced NuGet packages are included in the VSIX, without inflating the installation with these other files?
You can use a simple script like this:
<Target Name="IncludeNuGetPackageReferences" AfterTargets="GetVsixSourceItems">
<ItemGroup>
<VSIXSourceItem Include="#(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.NuGetPackageId)' == 'Newtonsoft.Json'" />
<VSIXSourceItem Include="#(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.NuGetPackageId)' == 'xxx'" />
... </ItemGroup>
</Target>
You can specify what assemblies should be included into .vsix . And it won't copy the unnecessary VS assemblies after tests in my machine. Hint from smourier, thanks to him.
Hope it helps:)

ASP.NET Core (NET Framework) Teamcity build fails, VS builds properly

I have an ASP.NET Core project that builds properly with VS but fails with TeamCity.
It is a project that compiles to a library, but TeamCity tries to build it as an executable, and complains about the lack of 'main':
CSC error CS5001: Program does not contain a static 'Main' method suitable for an entry point
The content of the .csproj file are as follow:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<OutputType>Library</OutputType>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net462</TargetFramework>
<RuntimeIdentifier>win7-x86</RuntimeIdentifier>
<OutputTypeEx>library</OutputTypeEx>
<StartupObject />
<AssemblyName>Test</AssemblyName>
<RootNamespace>Test</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.3" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
</ItemGroup>
</Project>
Visual studio has no problem building the dll file.
To reproduce:
Create an ASP.NET Core (.NET Framework) project
Change the output type to library
Remove the program.cs / startup.cs files
Compile with Visual Studio to confirm a library is being built
Build with Team City and an error will appear
To avoid that error, Please look into this SO post or this
You should be using the dotnet core plugin or you can easily
configure dotnet build command(if dotnet is present in your build
servers).
Or you can refer the MusicStore build.cmd file for reference. This basically downloads and installs the dotnet and all the dependencies and then builds the project.
Hope it helps!
I found a workaround; in the project file, VS puts this:
<OutputTypeEx>library</OutputTypeEx>
I need to add one line:
<OutputType>Library</OutputType>
<OutputTypeEx>library</OutputTypeEx>
So it looks like the build with TeamCity is not handling the OutputTypeEx propery but it handles the OutputType one.
I still see this as a bug, but at least there is a workaround.

Embedding Project with Typescript into another project

I have a Visual Studio project that uses Typescript. This projects gets compiled into a dll and then referenced in the main project. This works fine for all normally compiled files, but I am hitting an issue when it comes to transpiled javascript files.
The sub project has the following in the .csproj file
<Target Name="AfterClean">
<ItemGroup>
<EmbeddedResource Include="**\*.html;**\*.cshtml;**\*.css;**\*.js;**\*.map;**\*.jpg;**\*.png" />
</ItemGroup>
</Target>
This will include the .js files in the project when a Rebuild Solution is run, but it will not include the .js files when a normal build or a "Run" from Visual studio is used.
I believe the issue is to do with timings, I want the embedding to occur after the typescript transpile has happened, but before the dll is included in the main project.
I have tried the following options "BeforeBuild", "AfterBuild", "BeforeResolveReference", "AfterResolveReferences", "BeforeResGen" and "AfterResGen". - Found from a msdn article here
Ideally I would like to add a DependsOnTargets=TypeScript compile to my embedding task so it forced the embed to happen after the transpile, but the typescript compile does not appear to be a target as it just appears like this in the .csproj file, so I don't believe this is possible
<ItemGroup>
<TypeScriptCompile Include="app\app.module.ts" />
...
</ItemGroup>
Any ideas would be greatly appreciated
(I am using Visual Studio 2015 Update 3 and Typescript 1.8)
EDIT: The build server does not have tsc on the PATH so I am unable to call tsc from a prebuild event
I have tried to do similar thing, the solution works for me is use TypeScript command line to compile TypeScript in the pre-build event.
<PropertyGroup>
<PreBuildEvent>
tsc $(ProjectDir)\Scripts\references.d.ts
// or compile tsconfig.json if you use TypeScript 1.8
// tsc --project $(ProjectDir)\Scripts\
</PreBuildEvent>
</PropertyGroup>
Then add following target element for BeforeBuild:
<Target Name="BeforeBuild" DependsOnTargets="PreBuildEvent">
<ItemGroup>
<EmbeddedResource Include="**\*.js" />
</ItemGroup>
</Target>
You can find more information about tsconfig.json here.

Resources