Migração de projeto de associação do Xamarin.Android
No .NET, não há nenhum conceito de um projeto de associação do Android como um tipo de projeto separado. Qualquer um dos grupos de itens do MSBuild ou ações de build que funcionam em projetos de associação do Xamarin.Android tem suporte por meio de um aplicativo ou biblioteca do .NET para Android.
Para migrar uma biblioteca de associação do Xamarin.Android para uma biblioteca de classes do .NET para Android:
No Visual Studio, crie um novo projeto de Associação de Biblioteca Java do Android com o mesmo nome do projeto de associação do Xamarin.Android:
A abertura do arquivo de projeto confirmará que você tem um projeto no estilo do SDK do .NET:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net8.0-android</TargetFramework> <SupportedOSPlatformVersion>21</SupportedOSPlatformVersion> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> </PropertyGroup> </Project>
Observação
O arquivo de projeto de uma biblioteca de associação do Android é idêntico ao arquivo de projeto de uma biblioteca de classes do Android.
Adicione o seu Arquivo Java (JAR) ou Arquivo Android (AAR) ao projeto e verifique se a sua ação de build está definida como AndroidLibrary.
Copie todas as transformações ou adições da biblioteca de associações do Xamarin.Android.
Opções herdadas sem suporte
As opções herdadas a seguir não têm mais suporte. As alternativas com suporte estão disponíveis há vários anos e a opção de migração mais suave é atualizar e testar seus projetos atuais com essas opções antes de migrá-los para o .NET.
AndroidClassParser
jar2xml
não é mais uma opção válida para a propriedade $(AndroidClassParser)
. class-parse
agora é a opção padrão e a única com suporte.
class-parse
aproveita muitos novos recursos modernos não disponíveis em jar2xml
, como:
- Nomes de parâmetro automáticos para métodos de classe (se o código Java for compilado com
javac -parameters
). - Suporte ao Kotlin.
- Suporte a membro de interface estático/padrão (DIM).
- Suporte a anotações de tipo de referência anulável (NRT) Java.
AndroidCodegenTarget
XamarinAndroid
não é mais uma opção válida para a propriedade $(AndroidCodegenTarget)
. XAJavaInterop1
agora é a opção padrão e a única com suporte.
Se você tiver um código associado à mão em seus arquivos Additions
que interage com o código de associação gerado, talvez seja necessário atualizar para ser compatível com XAJavaInterop1
.
Inclusão de arquivo padrão
Dada a seguinte estrutura de arquivo:
Transforms/
Metadata.xml
foo.jar
Os arquivos Transforms\*.xml
são incluídos automaticamente como um item @(TransformFile)
, e os arquivos .jar
/.aar
são incluídos automaticamente como um item @(AndroidLibrary)
. Isso associará os tipos C# para os tipos Java encontrados em foo.jar
usando as correções de metadados de Transforms\Metadata.xml
.
O comportamento padrão de mascaramento de arquivo relacionado ao Android é definido em AutoImport.props. Este comportamento pode ser desabilitado para itens Android definindo a propriedade $(EnableDefaultAndroidItems)
como false
, ou todo o comportamento de inclusão de item padrão pode ser desabilitado definindo a propriedade $(EnableDefaultItems)
como false
.
Arquivos indesejados .jar
ou .aar
podem ser incluídos com os caracteres curinga padrão. Por exemplo, os seguintes erros do compilador C# resultam de um arquivo AndroidStudio\gradle\wrapper\gradle-wrapper.jar
ser associado involuntariamente:
Org.Gradle.Cli.AbstractCommandLineConverter.cs(11,89): error CS0535: 'Download' does not implement interface member 'IDownload.Download(URI, File)'
Org.Gradle.Wrapper.Download.cs(10,60): error CS0535: 'AbstractCommandLineConverter' does not implement interface member 'ICommandLineConverter.Convert(ParsedCommandLine, Object)'
Para resolver este problema, você pode remover o arquivo específico no arquivo de projeto:
<ItemGroup>
<AndroidLibrary Remove="AndroidStudio\gradle\wrapper\gradle-wrapper.jar" />
</ItemGroup>
Como alternativa, você pode excluir todos os arquivos em uma pasta:
<AndroidLibrary Remove="AndroidStudio\**\*" />
Novos nomes de grupo de itens
<AndroidLibrary>
agora é o grupo de itens recomendado a ser usado para todos os arquivos .jar
e .aar
. No Xamarin.Android, foram usados os seguintes grupos de itens, que podem usar metadados de item para obter o mesmo resultado:
Grupo de itens herdados | Novo Grupo de Itens | Metadados de item | Tipo de projeto herdado |
---|---|---|---|
AndroidAarLibrary |
AndroidLibrary |
Bind="false" |
Aplicativo |
AndroidJavaLibrary |
AndroidLibrary |
Bind="false" |
Aplicativo ou biblioteca de classes |
EmbeddedJar |
AndroidLibrary |
N/D | Projeto de associação |
EmbeddedReferenceJar |
AndroidLibrary |
Bind="false" |
Projeto de associação |
InputJar |
AndroidLibrary |
Pack="false" |
Projeto de associação |
LibraryProjectZip |
AndroidLibrary |
N/D | Projeto de associação |
Considere um arquivo .aar
ou .jar
no qual você não está interessado em incluir uma associação C#. Isso é comum para casos em que você tem dependências Java ou Kotlin que você não precisa chamar do C#. Neste caso, você pode definir os metadados Bind
como false
. Por padrão, o arquivo é captado pelos curingas padrão. Você também pode usar o atributo Update
para definir os metadados Bind
:
<ItemGroup>
<AndroidLibrary Update="foo.jar" Bind="false">
</ItemGroup>
Em um projeto de biblioteca de classes Android, isso redistribuiria o arquivo .jar
dentro do pacote NuGet resultante como está. Em um projeto de aplicativo Android, isso incluiria o arquivo .jar
no arquivo .apk
ou .aab
resultante. Nenhum dos dois incluiria uma associação C# para esta biblioteca Java.
Arquivos JAR/AAR inseridos
No Xamarin.Android, o Java .jar
ou .aar
geralmente era inserido na associação .dll
como um recurso inserido. No entanto, isso levou a builds lentos, pois cada .dll
deve ser aberto e verificado quanto ao código Java. Se encontrado, ele deve ser extraído para o disco a ser usado.
No .NET, o código Java não está mais inserido no .dll
. O processo de build do aplicativo incluirá automaticamente qualquer arquivo .jar
ou .aar
encontrados no mesmo diretório que um .dll
referenciado.
Se um projeto fizer referência a uma associação por meio de <PackageReference>
ou <ProjectReference>
, tudo funcionará e nenhuma consideração adicional será necessária. No entanto, se um projeto fizer referência a uma associação por meio de <Reference>
, o .jar
/.aar
deverá estar localizado ao lado do .dll
. Ou seja, para a seguinte referência:
<Reference Include="MyBinding.dll" />
Um diretório como o do exemplo a seguir não funcionará:
lib/
MyBinding.dll
Em vez disso, o diretório também deve conter o código nativo:
lib/
MyBinding.dll
mybinding.jar
Considerações sobre migração
Há vários novos recursos definidos por padrão para ajudar a produzir associações que correspondam melhor aos seus equivalentes Java. No entanto, se você estiver migrando um projeto de associação existente, esses recursos poderão criar associações que não são compatíveis com a API com suas associações existentes. Para manter a compatibilidade, convém desabilitar ou modificar esses novos recursos.
Constantes de interface
Tradicionalmente, o C# não permite que constantes sejam declaradas em um interface
, o que é um padrão comum em Java:
public interface Foo {
public static int BAR = 1;
}
Anteriormente, este padrão tinha suporte criando uma class
alternativa contendo as constantes:
public abstract class Foo : Java.Lang.Object
{
public static int Bar = 1;
}
Com o C# 8, essas constantes são colocadas no interface
:
public interface IFoo
{
public static int Bar = 1;
}
No entanto, isto significa que a classe alternativa da qual o código existente pode depender não é mais gerada.
A configuração da propriedade $(AndroidBoundInterfacesContainConstants)
como false
no arquivo de projeto será revertida para o comportamento herdado.
Tipos de interface aninhados
Tradicionalmente, o C# não permite que tipos aninhados sejam declarados em um interface
, o que é permitido em Java:
public interface Foo {
public class Bar { }
}
Este padrão foi suportado movendo o tipo aninhado para um tipo de nível superior com um nome gerado composto pela interface e pelo nome do tipo aninhado:
public interface IFoo { }
public class IFooBar : Java.Lang.Object { }
Com o C# 8, os tipos aninhados podem ser colocados no interface
:
public interface IFoo
{
public class Bar : Java.Lang.Object { }
}
No entanto, isso significa que a classe de nível superior da qual o código existente pode depender não é mais gerada.
A configuração da propriedade $(AndroidBoundInterfacesContainTypes)
como false
no arquivo de projeto será revertida para o comportamento herdado.
Se você quiser usar uma abordagem híbrida, por exemplo, para manter os tipos aninhados existentes movidos para um tipo de nível superior, mas permitir que quaisquer tipos aninhados futuros permaneçam aninhados, você poderá especificar isso no nível interface
usando metadata
para definir o atributo unnest
. Defini-lo como true
resultará em "cancelar o aninhamento" de qualquer tipo aninhado (comportamento herdado):
<attr path="/api/package[@name='my.package']/interface[@name='Foo']" name="unnest">true</attr>
Defini-lo como false
resultará em tipos aninhados que permanecem aninhados no interface
(comportamento do .NET):
<attr path="/api/package[@name='my.package']/interface[@name='Foo']" name="unnest">false</attr>
Usando esta abordagem, você pode deixar a propriedade $(AndroidBoundInterfacesContainTypes)
como true
e definir unnest
como true
para cada interface
um com tipos aninhados que você tem atualmente. Eles sempre permanecerão tipos de nível superior, enquanto todos os novos tipos aninhados introduzidos posteriormente serão aninhados.
Membros de interface estáticos e padrão (DIM)
Tradicionalmente, o C# não permite que as interfaces contenham membros static
e métodos default
:
public interface Foo {
public static void Bar () { ... }
public default void Baz () { ... }
}
Os membros estáticos nas interfaces têm suporte ao movê-los para um irmão class
:
public interface IFoo { }
public class Foo
{
public static void Bar () { ... }
}
Os métodos de interface default
tradicionalmente não são associados, pois eles não são necessários e não existia um constructo C# para dar suporte a eles.
Com o C# 8, os membros static
e default
têm suporte em interfaces, espelhando a interface Java:
public interface IFoo
{
public static void Bar () { ... }
public default void Baz () { ... }
}
No entanto, isso significa que o irmão alternativo class
que contém static
membros não será mais gerado.
A configuração da propriedade $AndroidBoundInterfacesContainStaticAndDefaultInterfaceMethods
como false
no arquivo de projeto será revertida para o comportamento herdado.
Tipos de referência anuláveis
O suporte para tipos de referência anuláveis (NRT) foi adicionado ao Xamarin.Android 11.0. O suporte a NRT pode ser habilitado usando o mecanismo .NET padrão:
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
Como o padrão para .NET é disable
, o mesmo se aplica a projetos do Xamarin.Android.
Resource.designer.cs
No Xamarin.Android, os projetos de associação Java não dão suporte à geração de um arquivo Resource.designer.cs
. Como os projetos de associação são apenas bibliotecas de classes no .NET, este arquivo será gerado. Esta pode ser uma alteração interruptiva ao migrar projetos existentes.
Um exemplo de falha dessa alteração é se a associação gerar uma classe nomeada Resource
no namespace raiz:
error CS0101: The namespace 'MyBinding' already contains a definition for 'Resource'
Ou, no caso do AndroidX, há arquivos de projeto com -
no nome, como androidx.window/window-extensions.csproj
. Isso resulta no namespace raiz window-extensions
e C# inválido em Resource.designer.cs
:
error CS0116: A namespace cannot directly contain members such as fields, methods or statements
error CS1514: { expected
error CS1022: Type or namespace definition, or end-of-file expected
Para desabilitar a geração Resource.designer.cs
, defina a propriedade $(AndroidGenerateResourceDesigner)
como false
no arquivo de projeto:
<PropertyGroup>
<AndroidGenerateResourceDesigner>false</AndroidGenerateResourceDesigner>
</PropertyGroup>