Maui Android RuntimeIdentifiers and SelfContained - xamarin.android

Im very lost with this, try different solutions i search here and nothing works. I published the first apk version a week ago, but when i run visual studio today, it doesn't build.
EveryTime i build the app output gives -> "NETSDK1031 It is not supported to build or publish a self-contained application without specifying a RuntimeIdentifier. You must either specify a RuntimeIdentifier or set SelfContained to false."
Also if someone could explain me, to understand whats happening, appreciate it.
My .csproj
<PropertyGroup>
<TargetFrameworks>net6.0-ios;net6.0-maccatalyst;net6.0-android31.0</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net6.0-windows10.0.19041.0</TargetFrameworks>
<OutputType>Exe</OutputType>
<RootNamespace>AppRipsaPagosMAUI</RootNamespace>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<!-- App Identifier -->
<ApplicationId>com.companyname.appripsapagosmaui</ApplicationId>
<ApplicationIdGuid>61252DD6-68C5-4051-9E5F-30226AFF9A7E</ApplicationIdGuid>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">14.2</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">14.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
</PropertyGroup>

Please try to change net6.0-android31.0 to net6.0-android in <TargetFrameworks> tag. And remove bin and obj folders, clean + rebuild + maui-check with package manager console with maui-check library

Related

iOS code signing key '?Apple Distribution: My Name (xxxxxx)' not found in keychain

Environment:
Windows 10 Home, 21H2
VS Version 17.3.0 Preview 1.1
I have followed these steps to get to this error:
Create a new VS project
Select .NET MAUI App
Choose a file location and leave everything else to default
Setting the project configuration file to this
<PropertyGroup>
<TargetFrameworks>net6.0-android;net6.0-ios;net6.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net6.0-windows10.0.19041.0</TargetFrameworks>
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>$(TargetFrameworks);net6.0-tizen</TargetFrameworks> -->
<OutputType>Exe</OutputType>
<RootNamespace>MauiApp1</RootNamespace>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ImplicitUsings>enable</ImplicitUsings>
<!-- Display name -->
<ApplicationTitle>MauiApp1</ApplicationTitle>
<!-- App Identifier -->
<ApplicationId>com.testapp.maui</ApplicationId>
<ApplicationIdGuid>CE4B9160-2B17-4559-8E4C-EA410A9A7966</ApplicationIdGuid>
<!-- Versions -->
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">14.2</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">14.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
<RuntimeIdentifier>ios-arm64</RuntimeIdentifier>
<CodesignKey>‌Apple Distribution: My Name (xxxxxxx)</CodesignKey>
<CodesignProvision>Apple Provisioning</CodesignProvision>
<ArchiveOnBuild>true</ArchiveOnBuild>
<TcpPort>58181</TcpPort>
<ServerAddress>xxxxx</ServerAddress>
<ServerUser>xxxxx</ServerUser>
<ServerPassword>xxxxx</ServerPassword>
<_DotNetRootRemoteDirectory>/Users/xxxxx/Library/Caches/Xamarin/XMA/SDKs/dotnet/</_DotNetRootRemoteDirectory>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net6.0-ios|AnyCPU'">
<BuildIpa>True</BuildIpa>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net6.0-ios|AnyCPU'">
<BuildIpa>True</BuildIpa>
</PropertyGroup>
<ItemGroup>
<!-- App Icon -->
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4" />
<!-- Splash Screen -->
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128" />
<!-- Images -->
<MauiImage Include="Resources\Images\*" />
<MauiImage Update="Resources\Images\dotnet_bot.svg" BaseSize="168,208" />
<!-- Custom Fonts -->
<MauiFont Include="Resources\Fonts\*" />
<!-- Raw Assets (also remove the "Resources\Raw" prefix) -->
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
Connect to the build Mac
Test run on Windows as Windows app, successful.
Run this command
dotnet publish -f:net6.0-ios -c:Release
Error
iOS code signing key '?Apple Distribution: My Name (xxxxxx)' not found
in keychain.
I've also tried doing a Release build through VS GUI (Right click on Solution -> Rebuild), then I get this error:
Code signing must be enabled to create an Xcode archive.
Previous to that
I executed step by step according to this https://github.com/dotnet/maui/issues/4397 and this https://www.youtube.com/watch?v=kpZi5xAvpZA
Did all the necessary steps in my Apple Developer Account
Installed the certificate in the keychain on a Mac
Installed the provisioning file in XCode
Initially my certificate in the keychain on the Mac showed invalid/not trusted. After doing this https://stackoverflow.com/a/65120256/5909367 it shows valid
Also notice, there is a question mark in the error '?Apple Distribution: My Name (xxxxxx)', which I don't know where it's coming from.
Update:
I used this command to create a log file during the build
dotnet publish -f:net6.0-ios -c:Release /bl:msbuild.binlog
The logfile can be viewed with this tool: https://msbuildlog.com/
In this logfile, the error message does not have the question mark. So I guess the question mark is just a display error when writing the log message.
In the binlog then, it literally says this:
The certificate 'Apple Distribution: My Name (xxx)' does not match
'Apple Distribution: My Name (xxx)‌'.
I have checked character for character. It is exactly the same string.
I also have noticed, that it does download the certificates from the server, because I can see them listed in the binlog after the entry "DetectingSigningIdentity"
I figured it out, thanks to the last comment!
The string
<CodesignKey>‌Apple Distribution: My Name (xxx)</CodesignKey>
contains a hidden character. I can't reproduce this in this post, because the hidden characters get filtered out.
But it can be reproduced with a string to hex converter: https://online-toolz.com/tools/text-hex-convertor.php
Type in this hex code: 3ee2808c and it will produce this character "<". When you type 3e, it will produce the same character "<". The problem is when copy/pasted, hidden characters come with it.
To prove this you can simply copy/paste the "<" from the first product into the tool again.
Looking up the character "e2808c", it stands for a "Zero-width non-joiner" https://en.wikipedia.org/wiki/Zero-width_non-joiner https://www.fileformat.info/info/unicode/char/200c/index.htm
How this got into the string, I don't know. I also didn't know that there can be hidden characters in strings!
So then one of these hidden strings got into my CodesignKey tag, and it would not match anymore. Visual Studio pointed this out correctly with a question mark. But my interpretation of the error was wrong, because I didn't expect something to be there that I can not see....

Visual Studio (Xamarin): DependencyService + Nuget + iOS = Fail

We are writing a Visual Studio (Xamarin) cross-platform application that will share quite a bit of functionality with the next application we write, so we wanted to put that shared functionality into a "library" so we could test it, share it easily, etc.
The only way we found to write a cross-platform library, is to create it using the standard Xamarin DependencyService paradigm, turn it into a NuGet package, and then load that package into our main app. For better or worse, we did this before Microsoft provided a template for generating NuGet libraries like this, so we had to roll it ourselves.
This works fine for Android, but now I'd like to get the same code working for iOS and it's simply not working. No errors, no warnings, but when I run the app and call
Client = DependencyService.Get<IClient>();
It simply returns null. If I look at the Output/Debug window, it is loading the 'Company.Client.Abstractions.dll' (the root DLL containing the definition of IClient) but not the iOS-specific 'Company.Client.dll' (which contains the iOS-specific implementation of IClient).
Here's my nuspec file:
<?xml version="1.0"?>
<package >
<metadata>
<id>Client</id>
<version>0.0.35</version>
<authors>Me</authors>
<owners>Company</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Stuff</description>
<releaseNotes>Initial release</releaseNotes>
<copyright>Copyright 2017 Company</copyright>
<dependencies>
<group targetFramework="MonoAndroid">
<dependency id="Xamarin.Forms" version="2.3.4.247" />
</group>
<group targetFramework="Xamarin.iOS10">
<dependency id="Xamarin.Forms" version="2.3.4.247" />
</group>
<group targetFramework="uap">
<dependency id="Xamarin.Forms" version="2.3.4.247" />
</group>
</dependencies>
</metadata>
<files>
<!-- Cross-platform reference assemblies -->
<file src="Company.Client.Abstractions\bin\Debug\Company.Client.Abstractions.dll" target="lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\Company.Client.Abstractions.dll" />
<file src="Company.Client.Abstractions\bin\Debug\Company.Client.Abstractions.pdb" target="lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\Company.Client.Abstractions.pdb" />
<!-- iOS reference assemblies -->
<file src="Company.Client.iOS\bin\iPhone\Debug\Company.Client.dll" target="lib\Xamarin.iOS10\Company.Client.dll" />
<file src="Company.Client.iOS\bin\iPhone\Debug\Company.Client.pdb" target="lib\Xamarin.iOS10\Company.Client.pdb" />
<!-- Android reference assemblies -->
<file src="Company.Client.Android\bin\Debug\Company.Client.dll" target="lib\MonoAndroid10\Company.Client.dll" />
<file src="Company.Client.Android\bin\Debug\Company.Client.pdb" target="lib\MonoAndroid10\Company.Client.pdb" />
<!-- UWP reference assemblies -->
<file src="Company.Client.UWP\bin\Debug\Company.Client.dll" target="lib\UAP10\Company.Client.dll" />
<file src="Nuvectra.Client.UWP\bin\Debug\Company.Client.pdb" target="lib\UAP10\Company.Client.pdb" />
</files>
</package>
I'm thinking there are two classes of possible problems:
I'm generating the DLL wrong
I'm generating the application wrong
Looking at the generated DLLs, the Android DLL is 28k long, the iOS DLL is 23k, so it doesn't look like the iOS DLL is empty. Is there a tool that would let me inspect the iOS DLL and make sure it has the necessary entry point(s)?
The Project that generates the iOS DLL has these settings:
Target framework: Xamarin.iOS
Output type: Class Library
Condition compilation symbols: __ UNIFIED__;__ MOBILE__;__ IOS__
Platform: Active (Any CPU)
The application that is using the DLL has these settings for the iOS Project:
SDK Version: Default
Linker Behavior: Don't Link
Platform: Active (iPhone)
Supported Architectures: ARMv7 + ARM64
Target framework: Xamarin.IOS
Output type: Console Application
Conditional compilation symbols: __ UNIFIED__;__ MOBILE__;__ IOS__
The interface definition in my 'Abstractions' project looks like this:
namespace Company.Client
{
public abstract class IClient
{
void abstract function();
}
}
and the implementation in my iOS project looks like this:
using Company.Client.iOS;
[assembly: Xamarin.Forms.Dependency (typeof (IosClient))]
namespace Company.Client.iOS
{
public class IosClient : IClient
{
void override function();
}
}
We tried many different ways to create a NuGet package with platform-specific code loaded using DependencyService and every single way had the same problem - worked fine under Android, failed under iOS.
The solution is to create a class in the iOS library that is not loaded using DependencyService, and then in the iOS application, create an instance of that class. That's enough to convince the iOS application that it actually needs to load the iOS library DLL, and then the rest of the DependencyService magic works correctly.

How to link resource files?

I have a strings.resx file that I've copied to another project. It has an associated strings.designer.cs file. The problem is that once I add them to the VS.NET project, they are separate.
In the older project, strings.designer.cs is a child of strings.resx. If I double click strings.resx, it auto generates a strings1.designer.cs file.
How do I recreate the association?
I could reproduce your issue.
After importing the resource in the new project if you look at the .csproj file you could find an ItemGroup section containing the <Compile Include="string.Designer.cs" /> item, similar to the following
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
....
<Compile Include="string.Designer.cs" />
</ItemGroup>
So to solve your issue do the following
While in VisualStudio unload the project.
Right click on the unloaded project and select "edit {your project name}" from the context menu
Find the ItemGroup section containing your <Compile Include="string.Designer.cs" />
Replace
<Compile Include="string.Designer.cs" />
by
<Compile Include="string.Designer.cs">
<DependentUpon>string.resx</DependentUpon>
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
</Compile>
Now reload the project ad you should see your files related on the solution explorer

Retain changes to existing files when publishing

I'm stuck in a scenario where my published file is initially correct, but then later is replaced by it's original version. I suspect that the order of events is wrong, coupled with what's in the root directory.
Essentially I have successfully setup my publishing environment where it executes a custom command to create some JavaScript (which gets created outside of my project). Because a file in source control needs to reference this newly created JavaScript, I am simply copying the file (MyControl.ascx) to a temp location (thus it loses the read lock by TFS) and I am having the custom command update the references to the JS. Once this is done, I gather all the files (custom JavaScript, as well as edited MyControl.ascx in it's temp location) and publish.
It publishes everything first, so I see the new JS as well as the updated MyControl.ascx, but a few minutes later it finishes the publish, and Control looks like how it looked in the root directory.
I think what's happening is it's just pushing out what's in the root (which includes MyControl.ascx) on top of my custom Control (which is in another directory).
<PropertyGroup>
<PipelineCollectFilesPhaseDependsOn>
CustomCollectFiles;
$(PipelineCollectFilesPhaseDependsOn);
</PipelineCollectFilesPhaseDependsOn>
</PropertyGroup>
<Target Name="CustomCollectFiles">
Exec Command="MyCommand.bat"
<ItemGroup>
<_BundledJS Include="$(MSBuildThisFileDirectory)..\..\Includes\javascript\*.js" />
<FilesForPackagingFromProject Include="%(_BundledJS.Identity)">
<DestinationRelativePath>Includes\javascript\%(Filename)%(Extension)
</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
<ItemGroup>
<_UpdatedControl Include="$(MSBuildThisFileDirectory)..\..\TempArea\MyControl.ascx" />
<FilesForPackagingFromProject Include="%(_UpdatedControl.Identity)">
<DestinationRelativePath>Controls\%(Filename)%(Extension)
</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
So you can see above i'm taking something that's in ....\TempArea\MyControl.ascx and pushing it out to Controls\%(Filename)%(Extension).
Any ideas how I can tell it to essentially retain my ....\TempArea\MyControl.ascx without then overwriting it with the original MyControl.ascx within the project (....\Controls\MyControl.ascx) ?
Thanks so much!
So I actually ended up figuring it out, and wanted to share:
<ItemGroup>
<_UpdatedControl Include="$(MSBuildThisFileDirectory)..\..\TempArea\MyControl.ascx" />
<FilesForPackagingFromProject Remove="Controls\MyControl.ascx" ></FilesForPackagingFromProject>
<FilesForPackagingFromProject Include="%(_UpdatedControl.Identity)" >
<DestinationRelativePath>Controls\%(RecursiveDir)%(Filename)%(Extension) </DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
So you can see here it actually removes the original control, then adds it back.
I also changed the target as such:
<PropertyGroup>
<OnAfterPipelineCollectFilesPhase>
CustomCollectFiles;
$(OnAfterPipelineCollectFilesPhase);
</OnAfterPipelineCollectFilesPhase>
</PropertyGroup>
Let me know if any questions would be happy to help!

TeamBuild: How to create a bug on a partially successful build

I am using TFS 2008 and writing my builds using the built-in TeamBuild. I have the build set up in such a way that it will create a work item of type Bug upon failure, and will also create a bug upon unit test failure. However; today our build partially succeeded due to the fact that an exec task kicked off an executable which had a return code that was not 0.
My question then; is there some way to determine a partial succession of a build and create a bug work item based on that detection?
A snippet from the build .proj file in which I create a bug based on a failed unit test run:
<Target Name="AfterTest">
<!-- Refresh the build properties. -->
<GetBuildProperties TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
BuildUri="$(BuildUri)"
Condition=" '$(IsDesktopBuild)' != 'true' ">
<Output TaskParameter="TestSuccess" PropertyName="TestSuccess" />
</GetBuildProperties>
<!-- Set CompilationStatus to Failed if TestSuccess is false. -->
<SetBuildProperties TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
BuildUri="$(BuildUri)"
CompilationStatus="Failed"
Condition=" '$(IsDesktopBuild)' != 'true' and '$(TestSuccess)' != 'true' ">
</SetBuildProperties>
<CreateNewWorkItem BuildNumber="$(BuildNumber)"
BuildURi="$(BuildURI)"
Description="A failed test run caused the CreateNewWorkItem task created this bug. $(BuildlogText)"
TeamProject="$(TeamProject)"
TeamFoundationServerUrl="$(TeamFoundationServerUrl)"
Title="Unit Test Failure in $(BuildNumber)"
WorkItemFieldValues="$(WorkItemFieldValues)"
WorkItemType="Bug"
Condition=" '$(IsDesktopBuild)' != 'true' and '$(TestSuccess)' != 'true' ">
</CreateNewWorkItem>
Any help would be greatly appreciated, thanks!
You could try to check for the error in another part of the build life cycle like
AfterDropBuild
You find the different targets to extend here

Resources