Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Documentation/docs-mobile/TOC.yml
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,8 @@
href: messages/xa4249.md
- name: XA4258
href: messages/xa4258.md
- name: XA4263
href: messages/xa4263.md
- name: XA4301
href: messages/xa4301.md
- name: XA4302
Expand Down
1 change: 1 addition & 0 deletions Documentation/docs-mobile/messages/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ Either change the value in the AndroidManifest.xml to match the $(SupportedOSPla
+ [XA4255](xa4255.md): Generated trimmable type map Java source '{path}' was not found.
+ [XA4256](xa4256.md): Skipping Java peer type '{type}' from assembly '{assembly}' because referenced type '{referencedType}' from assembly '{referencedAssembly}' could not be resolved in '{path}'. This type will not be included in the trimmable type map.
+ [XA4258](xa4258.md): Java name '{name}' contains reserved Java identifier '{identifier}'. Change the package or type name.
+ [XA4263](xa4263.md): The exported member '{member}' has unsupported signature type '{type}'. Use a Java peer type, a supported managed-to-Java mapping, or [ExportParameter].
+ XA4300: Native library '{library}' will not be bundled because it has an unsupported ABI.
+ [XA4301](xa4301.md): Apk already contains the item `xxx`.
+ [XA4302](xa4302.md): Unhandled exception merging \`AndroidManifest.xml\`: {ex}
Expand Down
28 changes: 28 additions & 0 deletions Documentation/docs-mobile/messages/xa4263.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
title: .NET for Android error XA4263
description: XA4263 error code
ms.date: 08/31/2026
f1_keywords:
- "XA4263"
---

# .NET for Android error XA4263

## Example message

```text
error XA4263: The exported member 'Peer.Get' has unsupported signature type 'ManagedValue'. Use a Java peer type, a supported managed-to-Java mapping, or [ExportParameter].
```

## Issue

An `[Export]` method or `[ExportField]` initializer uses a managed parameter or return type that has no Java type mapping.
The type cannot be represented safely in the generated Java declaration.
This error also occurs when `[ExportParameter]` specifies a Java mapping that is incompatible with the managed type.

## Solution

Use a primitive, string, array, Java peer, or another supported managed-to-Java type.
Apply input/output stream mappings only to `Stream`, and XML parser mappings only to `XmlReader`.
Do not apply these scalar mappings to arrays or other wrappers around those types.
The types must be the framework `System.IO.Stream` and `System.Xml.XmlReader` types, not user-defined types with the same full name.
2 changes: 2 additions & 0 deletions Xamarin.Android.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,10 @@
<Project Path="src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Xamarin.Android.Build.Tests.csproj" />
<Project Path="src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Xamarin.ProjectTools.csproj" />
<Project Path="tests/Microsoft.Android.Sdk.TrimmableTypeMap.IntegrationTests/Microsoft.Android.Sdk.TrimmableTypeMap.IntegrationTests.csproj" />
<Project Path="tests/Microsoft.Android.Sdk.TrimmableTypeMap.IntegrationTests/SpecialTypeCollisionFixture/SpecialTypeCollisionFixture.csproj" />
<Project Path="tests/Microsoft.Android.Sdk.TrimmableTypeMap.IntegrationTests/UserTypesFixture/UserTypesFixture.csproj" />
<Project Path="tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests.csproj" />
<Project Path="tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/MonoAndroidFixture/MonoAndroidFixture.csproj" />
<Project Path="tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/TestAttributeFixtures/TestAttributeFixtures.csproj" />
<Project Path="tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/TestFixtures/TestFixtures.csproj" />
<Project Path="tests/MSBuildDeviceIntegration/MSBuildDeviceIntegration.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ static void WriteUcoConstructor (this BinaryWriter writer, UcoConstructorData co
foreach (var parameterType in constructor.ManagedParameterTypes) {
writer.WriteTypeRef (parameterType);
}
writer.Write (constructor.ParameterKinds.Count);
foreach (var parameterKind in constructor.ParameterKinds) {
writer.Write ((int) parameterKind);
}
}

static void WriteNativeRegistration (this BinaryWriter writer, NativeRegistrationData registration)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,11 @@ sealed record UcoConstructorData
/// to the corresponding managed type before calling the user ctor.
/// </summary>
public IReadOnlyList<TypeRefData> ManagedParameterTypes { get; init; } = [];

/// <summary>
/// Per-parameter [ExportParameter] kinds for constructor argument marshalling.
/// </summary>
public IReadOnlyList<ExportParameterKindInfo> ParameterKinds { get; init; } = [];
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ static void BuildUcoConstructors (JavaPeerInfo peer, JavaPeerProxyData proxy)
AssemblyName = peer.AssemblyName,
},
ManagedParameterTypes = ctor.ManagedParameterTypes,
ParameterKinds = ctor.ManagedParameterExportKinds,
HasMatchingManagedCtor = ctor.HasMatchingManagedCtor,
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1182,7 +1182,7 @@ MethodDefinitionHandle EmitUcoConstructor (UcoConstructorData uco, JavaPeerProxy
if (uco.HasMatchingManagedCtor) {
var ctorRef = AddManagedCtorRef (targetTypeRef, uco.ManagedParameterTypes);
var managedCtorHandle = EmitUcoConstructorBody (uco.WrapperName, encodeSig,
enc => EmitManagedConstructorActivation (enc, targetTypeRef, ctorRef, uco.ManagedParameterTypes, jniParams),
enc => EmitManagedConstructorActivation (enc, targetTypeRef, ctorRef, uco.ManagedParameterTypes, uco.ParameterKinds, jniParams),
blob => EncodeUcoConstructorLocals_DefaultConstructor (blob, targetTypeRef));
AddUnmanagedCallersOnlyAttribute (managedCtorHandle);
return managedCtorHandle;
Expand Down Expand Up @@ -1278,6 +1278,7 @@ void EmitManagedConstructorActivation (
EntityHandle targetTypeRef,
MemberReferenceHandle ctorRef,
IReadOnlyList<TypeRefData> managedParameterTypes,
IReadOnlyList<ExportParameterKindInfo> parameterKinds,
IReadOnlyList<JniParamKind> jniParams)
{
var havePeer = enc.DefineLabel ();
Expand All @@ -1303,7 +1304,8 @@ void EmitManagedConstructorActivation (
enc.MarkLabel (havePeer);
enc.LoadLocal (4);
for (int i = 0; i < managedParameterTypes.Count; i++) {
EmitManagedConstructorArgument (enc, managedParameterTypes [i], jniParams [i], i + 2);
var parameterKind = i < parameterKinds.Count ? parameterKinds [i] : ExportParameterKindInfo.Unspecified;
EmitManagedConstructorArgument (enc, managedParameterTypes [i], parameterKind, jniParams [i], i + 2);
}
enc.Call (ctorRef, managedParameterTypes.Count, isInstance: true);

Expand Down Expand Up @@ -1383,53 +1385,14 @@ void EmitUcoConstructorBodyWithMarshal (TrackedInstructionEncoder encoder, Contr
cfb.AddFinallyRegion (tryStart, finallyStart, finallyStart, afterAll);
}

void EmitManagedConstructorArgument (TrackedInstructionEncoder encoder, TypeRefData managedType, JniParamKind jniKind, int argumentIndex)
void EmitManagedConstructorArgument (
TrackedInstructionEncoder encoder,
TypeRefData managedType,
ExportParameterKindInfo exportKind,
JniParamKind jniKind,
int argumentIndex)
{
if (managedType.ManagedTypeName == "System.Boolean") {
encoder.LoadArgument (argumentIndex);
encoder.LoadConstantI4 (0);
encoder.OpCode (ILOpCode.Cgt_un);
return;
}

if (jniKind != JniParamKind.Object) {
encoder.LoadArgument (argumentIndex);
return;
}

if (managedType.ManagedTypeName == "System.String") {
encoder.LoadArgument (argumentIndex);
encoder.LoadConstantI4 (0); // JniHandleOwnership.DoNotTransfer
encoder.Call (_jniEnvGetStringRef, parameterCount: 2, returnsValue: true);
return;
}

if (TryGetSzArrayElementType (managedType.ManagedTypeName, out var elementType)) {
var arrayType = ResolveManagedTypeHandle (managedType.ManagedTypeName, managedType.AssemblyName);
var elementTypeHandle = ResolveManagedTypeHandle (elementType, managedType.AssemblyName);

encoder.LoadArgument (argumentIndex);
encoder.LoadConstantI4 (0); // JniHandleOwnership.DoNotTransfer
encoder.LoadToken (elementTypeHandle);
encoder.Call (_getTypeFromHandleRef, parameterCount: 1, returnsValue: true);
encoder.Call (_jniEnvGetArrayRef, parameterCount: 3, returnsValue: true);
encoder.CastClass (arrayType);
return;
}

encoder.LoadArgument (argumentIndex);
encoder.LoadConstantI4 (0); // JniHandleOwnership.DoNotTransfer
if (managedType.ManagedTypeName == "System.Object") {
encoder.OpCode (ILOpCode.Ldnull);
encoder.Call (_javaLangObjectGetObjectRef, parameterCount: 3, returnsValue: true);
return;
}

var managedTypeHandle = ResolveManagedTypeHandle (managedType.ManagedTypeName, managedType.AssemblyName);
encoder.LoadToken (managedTypeHandle);
encoder.Call (_getTypeFromHandleRef, parameterCount: 1, returnsValue: true);
encoder.Call (_javaLangObjectGetObjectRef, parameterCount: 3, returnsValue: true);
encoder.CastClass (managedTypeHandle);
GetExportMethodDispatchEmitter ().LoadManagedArgument (encoder, managedType, exportKind, jniKind, argumentIndex);
}

EntityHandle ResolveRuntimeTypeSpec (RuntimeTypeSpec type)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ void LogUnresolvableJavaPeerSkippedWarning (
void LogJniAddNativeMethodRegistrationAttributeError (string managedTypeName);
void LogInvalidJavaNameError (string javaName, string invalidIdentifier);
void LogExportFieldWithParametersError ();
void LogExportOnGenericTypeError ();
void LogExportFieldOnGenericTypeError ();
void LogExportFieldReturnsVoidError ();
void LogUnsupportedExportSignatureError (string memberName, string managedTypeName);
void LogCustomJavaObjectError (string managedTypeName);
void LogCustomJavaObjectWarning (string managedTypeName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ sealed class AssemblyIndex : IDisposable

public MetadataReader Reader { get; }
public string AssemblyName { get; }
public string MetadataAssemblyName { get; }
public string AssemblyPath { get; }
internal TypeRefSignatureTypeProvider TypeRefSignatureProvider { get; }

Expand All @@ -53,6 +54,11 @@ sealed class AssemblyIndex : IDisposable
/// </summary>
public HashSet<string> ExportedTypeNames { get; } = new (StringComparer.Ordinal);

/// <summary>
/// Maps forwarded managed type names to the target assembly simple name.
/// </summary>
public Dictionary<string, string> ForwardedTypeAssemblies { get; } = new (StringComparer.Ordinal);

/// <summary>
/// True iff the assembly's metadata mentions
/// <c>Java.Interop.JniAddNativeMethodRegistrationAttribute</c> (as a
Expand All @@ -77,6 +83,7 @@ sealed class AssemblyIndex : IDisposable
valueTypeReferences = new TypeRefData? [reader.TypeReferences.Count + 1];
Reader = reader;
AssemblyName = assemblyName;
MetadataAssemblyName = reader.GetString (reader.GetAssemblyDefinition ().Name);
AssemblyPath = assemblyPath;
TypeRefSignatureProvider = new TypeRefSignatureTypeProvider (this);
}
Expand Down Expand Up @@ -107,7 +114,12 @@ void Build ()

foreach (var exportedTypeHandle in Reader.ExportedTypes) {
var exportedType = Reader.GetExportedType (exportedTypeHandle);
ExportedTypeNames.Add (GetExportedTypeFullName (exportedType));
var fullName = GetExportedTypeFullName (exportedType);
ExportedTypeNames.Add (fullName);
var forwardedAssemblyName = GetForwardedAssemblyName (exportedType);
if (forwardedAssemblyName is not null) {
ForwardedTypeAssemblies [fullName] = forwardedAssemblyName;
}
}

foreach (var typeHandle in Reader.TypeDefinitions) {
Expand Down Expand Up @@ -146,6 +158,18 @@ string GetExportedTypeFullName (ExportedType exportedType)
var ns = Reader.GetString (exportedType.Namespace);
return MetadataTypeNameResolver.JoinNamespaceAndName (ns, name);
}

string? GetForwardedAssemblyName (ExportedType exportedType)
{
if (exportedType.Implementation.Kind == HandleKind.AssemblyReference) {
var assemblyReference = Reader.GetAssemblyReference ((AssemblyReferenceHandle) exportedType.Implementation);
return Reader.GetString (assemblyReference.Name);
}
if (exportedType.Implementation.Kind == HandleKind.ExportedType) {
return GetForwardedAssemblyName (Reader.GetExportedType ((ExportedTypeHandle) exportedType.Implementation));
}
return null;
}
}

(RegisterInfo? register, TypeAttributeInfo? attrs) ParseAttributes (TypeDefinition typeDef)
Expand Down Expand Up @@ -173,8 +197,6 @@ string GetExportedTypeFullName (ExportedType exportedType)
registerInfo = registerInfo with { JniName = registerInfo.JniName.Replace ('.', '/') };
} else if (attrName == "JniTypeSignatureAttribute") {
registerInfo = ParseJniTypeSignatureAttribute (ca);
} else if (attrName == "ExportAttribute") {
// [Export] is a method-level attribute; it is parsed at scan time by JavaPeerScanner
} else if (IsKnownComponentAttribute (attrName)) {
attrInfo ??= CreateTypeAttributeInfo (attrName);
var value = DecodeAttribute (ca);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Microsoft.Android.Sdk.TrimmableTypeMap;
/// </summary>
enum ExportParameterKindInfo
{
Invalid = -1,
Unspecified = 0,
InputStream = 1,
OutputStream = 2,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,11 @@ public sealed record JavaConstructorInfo
/// </summary>
internal IReadOnlyList<TypeRefData> ManagedParameterTypes { get; init; } = [];

/// <summary>
/// Per-parameter [ExportParameter] kinds for constructor argument marshalling.
/// </summary>
internal IReadOnlyList<ExportParameterKindInfo> ManagedParameterExportKinds { get; init; } = [];

/// <summary>
/// True when this Java constructor has a matching public managed constructor on the target type.
/// </summary>
Expand Down
Loading
Loading