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
9 changes: 4 additions & 5 deletions Configuration.props
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,11 @@
<AndroidLatestStableApiLevel Condition="'$(AndroidLatestStableApiLevel)' == ''">37</AndroidLatestStableApiLevel>
<AndroidLatestStablePlatformId Condition="'$(AndroidLatestStablePlatformId)' == ''">37.0</AndroidLatestStablePlatformId>
<AndroidLatestStableFrameworkVersion Condition="'$(AndroidLatestStableFrameworkVersion)'==''">v17.0</AndroidLatestStableFrameworkVersion>
<!-- If there is a second *stable* API level (e.g. 38.1 alongside 38), set it here:
<AndroidLatestStableApiLevel2 Condition="'$(AndroidLatestStableApiLevel2)' == ''">38.1</AndroidLatestStableApiLevel2>
-->
<!-- If there is a second *stable* API level (e.g. 38.1 alongside 38), set it here: -->
<AndroidLatestStableApiLevel2 Condition="'$(AndroidLatestStableApiLevel2)' == ''">37.1</AndroidLatestStableApiLevel2>
<!-- *Latest* *unstable* API level binding that we support; this can be the same as *stable* -->
<AndroidLatestUnstableApiLevel Condition="'$(AndroidLatestUnstableApiLevel)' == ''">37.1</AndroidLatestUnstableApiLevel>
<AndroidLatestUnstablePlatformId Condition="'$(AndroidLatestUnstablePlatformId)' == ''">37.1</AndroidLatestUnstablePlatformId>
<AndroidLatestUnstableApiLevel Condition="'$(AndroidLatestUnstableApiLevel)' == ''">$(AndroidLatestStableApiLevel2)</AndroidLatestUnstableApiLevel>
<AndroidLatestUnstablePlatformId Condition="'$(AndroidLatestUnstablePlatformId)' == ''">$(AndroidLatestStableApiLevel2)</AndroidLatestUnstablePlatformId>
<AndroidLatestUnstableFrameworkVersion Condition="'$(AndroidLatestUnstableFrameworkVersion)'==''">v17.1</AndroidLatestUnstableFrameworkVersion>
<!-- The default API level used for $(TargetPlatformVersion) -->
<AndroidDefaultTargetDotnetApiLevel Condition=" '$(AndroidDefaultTargetDotnetApiLevel)' == '' ">$(AndroidLatestStableApiLevel)</AndroidDefaultTargetDotnetApiLevel>
Expand Down
23 changes: 13 additions & 10 deletions Documentation/workflow/HowToAddNewApiLevel.md
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,15 @@ the `csv` variable within `MainForm.FindAPILevelMethodsToolStripMenuItem_Click`.
Once this process is complete, use `Tools` -> `Export Final Method Map`, and create a *new*
`.csv` file, e.g. `new-methodmap.csv`.

Copy the contents of `new-methodmap.csv` and *append* to `src/Mono.Android/methodmap.csv`.
Note: `new-methodmap.csv` will likely use JNI syntax for package names, e.g. `android/widget`.
`methodmap.csv` ***must*** use *Java* syntax for package names, e.g. `android.widget`.
Comment thread
jonathanpeppers marked this conversation as resolved.
Use **sed**(1) to fix package names and nested class names:

```sh
sed 's,/,.,g;s/\$/./g' < src/Mono.Android/new-methodmap.csv > src/Mono.Android/new-methodmap2.csv
```

Copy the contents of `new-methodmap2.csv` and *append* to `src/Mono.Android/methodmap.csv`.

There may be redundant duplicate entries within `methodmap.csv`. Use the **uniq**(1)
Unix app to remove duplicate entries.
Expand Down Expand Up @@ -604,15 +612,10 @@ are automatically converted into `Android.Graphics.Color`.

### Finishing the method map

The official `methodmap.csv` uses a slightly different format than the one used for enumification.

Using BindingStudio:

- Ensure the "new api level method map" CSV file is loaded.
- Choose `Tools` -> `Export Final Method Map`
- Choose a temporary file name
- Open the temporary file, copy the contents to the bottom of the official:
- dotnet/android/src/Mono.Android/methodmap.csv
The normalized `new-methodmap2.csv` output appended in the **Mapping methods** section
is the final method map. Do not export and append the BindingStudio output again, as
the raw output uses JNI package and nested-type syntax that `methodmap.csv` does not
support.

Congrats! Enumification is complete!

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ public override bool Execute ()

// Check to see if Api has a previous Api defined.
if (!api_versions.TryGetValue (ApiLevel, out string previousApiLevel)) {
LogError ($"Please add ApiLevel:{ApiLevel} to the list of supported apis.");
LogError ($"Please add ApiLevel:{ApiLevel} to the list of supported apis. Supported APIs include: " +
string.Join (", ", api_versions.Keys.OrderBy (k => k)) + ".");
return !Log.HasLoggedErrors;
}

Expand Down
37 changes: 37 additions & 0 deletions build-tools/manifest-attribute-codegen/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,14 @@ These represent valid instances of entries and attributes respectively that can
For example, consider the following valid `AndroidManifest.xml` entry:

```xml
<!-- app AndroidManifest.xml, possibly generated -->
<activity name="MyActivity" />
```

This is partially declared within the Android SDK `attrs_manifest.xml` as:

```xml
<!-- in $ANDROID_SDK_HOME/platforms/android-*/data/res/values/attrs_manifest.xml -->
<declare-styleable name="AndroidManifestActivity" parent="AndroidManifestApplication">
<attr name="name" />
</declare-styleable>
Expand All @@ -64,6 +66,7 @@ The `<activity name="…"/>` element is represented in `metadata.xml` via both a
and an `<element/>` entry:

```xml
<!-- build-tools/manifest-attribute-codegen/metadata.xml -->
<type name="activity" namespace="Android.App" outputFile="src\Xamarin.Android.NamingCustomAttributes\Android.App\ActivityAttribute.cs" usage="AttributeTargets.Class" jniNameProvider="true" />
<element path="activity.name" visible="true" />
```
Expand Down Expand Up @@ -146,3 +149,37 @@ Optional metadata (note that if any metadata is set, `visible` is assumed to be
- **obsolete** - A string describing the reason for this member being `[Obsolete ("reason")]`
- **readonly** - Whether to generate the property with a `private set`; defaults to `false`
- **manualMap** - Whether to exclude the property from the `mapping` field used by `Xamarin.Android.Build.Tasks`; defaults to `false`

# Examples

Running the `GenerateManifestAttributes` target emits a message such as:

```
warning - Element: application.backupAgentProcess
```

The first question: is this *documented*? View the
[Google documentation for `<application>`](https://developer.android.com/guide/topics/manifest/application-element),
which -- at this writing on 2026-Aug-17 -- is ***not*** documented.
Consequently, we should ignore it, by updating `metadata.xml` to contain:

```xml
<element path="application.backupAgentProcess" visible="false" />
```

Running the `GenerateManifestAttributes` target emits a message such as:

```
warning - Type: <valid-general-purpose>
```

Similar but different to the `Element: application.backupAgentProcess` message:
a *Type* is an XML element, not an attribute on an XML element. As such, we would look at the
[App manifest overview](https://developer.android.com/guide/topics/manifest/manifest-intro)
documentation to see if *type* is mentioned in the left-hand sidebar to see if the element
is documented. At this writing on 2026-Aug-17, ***no*** `<valid-general-purpose>` element is
documented, and thus the Type (element) should be hidden by updating `metadata.xml` to contain:

```xml
<type name="valid-general-purpose" ignore="true" />
```
40 changes: 40 additions & 0 deletions build-tools/manifest-attribute-codegen/manifest-definition.xml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@
<a name='intentMatchingFlags' api-level='36.1' />
<a name='alternateLauncherIcons' format='reference' api-level='36.1' />
<a name='alternateLauncherLabels' format='reference' api-level='36.1' />
<a name='backupAgentProcess' api-level='37.0' />
<a name='zygotePreloadNativeLib' api-level='37.0' />
<a name='zygotePreloadNativeFunc' api-level='37.0' />
</e>
<e name='permission' api-level='10'>
<parent>manifest</parent>
Expand All @@ -119,6 +122,8 @@
<a name='maxSdkVersion' api-level='34' />
<a name='requiresPurpose' format='boolean' api-level='36.1' />
<a name='requiresPurposeTargetSdkVersion' format='integer' api-level='36.1' />
<a name='requiresGeneralPurposeTargetSdkVersion' format='integer' api-level='37.0' />
<a name='requiresPurposeStringTargetSdkVersion' format='integer' api-level='37.0' />
</e>
<e name='permission-group' api-level='10'>
<parent>manifest</parent>
Expand Down Expand Up @@ -153,6 +158,7 @@
<a name='requiredNotFeature' format='string' api-level='26' />
<a name='usesPermissionFlags' api-level='31' />
<a name='minSdkVersion' format='integer|string' api-level='34' />
<a name='purposeString' format='reference' api-level='37.0' />
</e>
<e name='uses-configuration' api-level='10'>
<parent>manifest</parent>
Expand Down Expand Up @@ -229,6 +235,7 @@
<a name='attributionTags' api-level='31' />
<a name='systemUserOnly' format='boolean' api-level='35' />
<a name='intentMatchingFlags' api-level='36.1' />
<a name='privateComputeCore' api-level='37.0' />
</e>
<e name='grant-uri-permission' api-level='10'>
<parent>provider</parent>
Expand Down Expand Up @@ -275,6 +282,8 @@
<a name='allowSharedIsolatedProcess' format='boolean' api-level='34' />
<a name='systemUserOnly' format='boolean' api-level='35' />
<a name='intentMatchingFlags' api-level='36.1' />
<a name='privateComputeCore' api-level='37.0' />
<a name='nativeService' format='boolean' api-level='37.0' />
</e>
<e name='receiver' api-level='10'>
<parent>application</parent>
Expand All @@ -293,6 +302,7 @@
<a name='roundIcon' api-level='25' />
<a name='attributionTags' api-level='31' />
<a name='intentMatchingFlags' api-level='36.1' />
<a name='privateComputeCore' api-level='37.0' />
</e>
<e name='activity' api-level='10'>
<parent>application</parent>
Expand Down Expand Up @@ -365,6 +375,7 @@
<a name='enableOnBackInvokedCallback' format='boolean' api-level='34' />
<a name='requireContentUriPermissionFromCaller' format='string' api-level='35' />
<a name='intentMatchingFlags' api-level='36.1' />
<a name='privateComputeCore' api-level='37.0' />
</e>
<e name='activity-alias' api-level='10'>
<parent>application</parent>
Expand All @@ -384,6 +395,7 @@
<a name='allowUntrustedActivityEmbedding' api-level='33' />
<a name='knownActivityEmbeddingCerts' api-level='33' />
<a name='intentMatchingFlags' api-level='36.1' />
<a name='privateComputeCore' api-level='37.0' />
</e>
<e name='meta-data' api-level='10'>
<parent>application</parent>
Expand Down Expand Up @@ -607,6 +619,7 @@
<a name='nativeHeapZeroInitialized' api-level='31' />
<a name='name' api-level='33' />
<a name='useEmbeddedDex' api-level='35' />
<a name='singleUser' api-level='37.1' />
</e>
<e name='deny-permission' api-level='30'>
<parent>processes</parent>
Expand Down Expand Up @@ -683,4 +696,31 @@
<parent>manifest</parent>
<a name='name' api-level='36.1' />
</e>
<e name='valid-general-purpose' api-level='37.0'>
<parent>permission</parent>
<a name='name' format='string' api-level='37.0' />
<a name='maxTargetSdkVersion' format='integer' api-level='37.0' />
</e>
<e name='general-purpose' api-level='37.0'>
<parent>uses-permission</parent>
<a name='name' format='string' api-level='37.0' />
<a name='minSdkVersion' format='integer|string' api-level='37.0' />
<a name='maxSdkVersion' format='integer' api-level='37.0' />
</e>
<e name='allow-component-access' api-level='37.0'>
<parent>manifest</parent>
</e>
<e name='allow-component-access-package' api-level='37.0'>
<parent>allow-component-access</parent>
<a name='name' api-level='37.0' />
<a name='certDigest' format='string' api-level='37.0' />
</e>
<e name='memory-budget' api-level='37.1'>
<parent>application</parent>
<a name='maxMb' api-level='37.1' />
<a name='state' api-level='37.1' />
<a name='additionalBytesPerDisplayPixel' api-level='37.1' />
<a name='additionalMbPerDensity' api-level='37.1' />
<a name='feature' api-level='37.1' />
</e>
</m>
16 changes: 16 additions & 0 deletions build-tools/manifest-attribute-codegen/metadata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
<!-- Manifest elements to ignore -->
<type name="action" ignore="true" />
<type name="activity-alias" ignore="true" />
<type name="allow-component-access" ignore="true" />
<type name="allow-component-access-package" ignore="true" />
<type name="additional-certificate" ignore="true" />
<type name="adopt-permissions" ignore="true" />
<type name="allow-permission" ignore="true" />
Expand All @@ -38,13 +40,15 @@
<type name="extension-sdk" ignore="true" />
<type name="extra" ignore="true" />
<type name="feature-group" ignore="true" />
<type name="general-purpose" ignore="true" />
<type name="install-constraints" ignore="true" />
<type name="install-constraints-fingerprint-prefix" ignore="true" />
<type name="intent" ignore="true" />
<type name="intent-category" ignore="true" />
<type name="key-set" ignore="true" />
<type name="library" ignore="true" />
<type name="manifest" ignore="true" />
<type name="memory-budget" ignore="true" />
<type name="original-package" ignore="true" />
<type name="package-verifier" ignore="true" />
<type name="path-permission" ignore="true" />
Expand Down Expand Up @@ -74,6 +78,7 @@
<type name="uses-sdk-library" ignore="true" />
<type name="uses-split" ignore="true" />
<type name="uses-static-library" ignore="true" />
<type name="valid-general-purpose" ignore="true" />
<type name="valid-purpose" ignore="true" />

<!-- <activity> - https://developer.android.com/guide/topics/manifest/activity-element -->
Expand Down Expand Up @@ -145,6 +150,7 @@
<element path="activity.playHomeTransitionSound" visible="false" />
<element path="activity.preferMinimalPostProcessing" visible="false" />
<element path="activity.primaryUserOnly" visible="false" />
<element path="activity.privateComputeCore" visible="false" />
<element path="activity.requiredDisplayCategory" visible="false" />
<element path="activity.splitName" visible="false" />
<element path="activity.systemUserOnly" visible="false" />
Expand Down Expand Up @@ -206,6 +212,7 @@
<element path="application.appComponentFactory" visible="false" />
<element path="application.attributionsAreUserVisible" visible="false" />
<element path="application.autoRevokePermissions" visible="false" />
<element path="application.backupAgentProcess" visible="false" />
<element path="application.cantSaveState" visible="false" />
<element path="application.classLoader" visible="false" />
<element path="application.crossProfile" visible="false" />
Expand All @@ -232,6 +239,8 @@
<element path="application.useEmbeddedDex" visible="false" />
<element path="application.usesNonSdkApi" visible="false" />
<element path="application.zygotePreloadName" visible="false" />
<element path="application.zygotePreloadNativeLib" visible="false" />
<element path="application.zygotePreloadNativeFunc" visible="false" />

<!-- Documented as deprecated -->
<element path="application.isGame" visible="false" />
Expand Down Expand Up @@ -306,7 +315,9 @@
<element path="permission.maxSdkVersion" visible="false" />
<element path="permission.permissionFlags" visible="false" />
<element path="permission.request" visible="false" />
<element path="permission.requiresGeneralPurposeTargetSdkVersion" visible="false" />
<element path="permission.requiresPurpose" visible="false" />
<element path="permission.requiresPurposeStringTargetSdkVersion" visible="false" />
<element path="permission.requiresPurposeTargetSdkVersion" visible="false" />

<!-- <permission-group> - https://developer.android.com/guide/topics/manifest/permission-group-element -->
Expand Down Expand Up @@ -366,6 +377,7 @@
<element path="provider.forceUriPermissions" visible="false" />
<element path="provider.intentMatchingFlags" visible="false" />
<element path="provider.logo" visible="false" />
<element path="provider.privateComputeCore" visible="false" />
<element path="provider.singleUser" visible="false" />
<element path="provider.splitName" visible="false" />
<element path="provider.systemUserOnly" visible="false" />
Expand All @@ -388,6 +400,7 @@
<element path="receiver.banner" visible="false" />
<element path="receiver.intentMatchingFlags" visible="false" />
<element path="receiver.logo" visible="false" />
<element path="receiver.privateComputeCore" visible="false" />
<element path="receiver.singleUser" visible="false" />

<!-- <service> - https://developer.android.com/guide/topics/manifest/service-element -->
Expand All @@ -411,6 +424,8 @@
<element path="service.externalService" visible="false" />
<element path="service.intentMatchingFlags" visible="false" />
<element path="service.logo" visible="false" />
<element path="service.nativeService" visible="false" />
<element path="service.privateComputeCore" visible="false" />
<element path="service.singleUser" visible="false" />
<element path="service.splitName" visible="false" />
<element path="service.stopWithTask" visible="false" />
Expand Down Expand Up @@ -443,6 +458,7 @@
<element path="uses-permission.minSdkVersion" visible="false" />
<element path="uses-permission.requiredFeature" visible="false" />
<element path="uses-permission.requiredNotFeature" visible="false" />
<element path="uses-permission.purposeString" visible="false" />
<!-- usesPermissionFlags - https://developer.android.com/develop/connectivity/bluetooth/bt-permissions#assert-never-for-location -->
<element path="uses-permission.usesPermissionFlags" visible="true" />

Expand Down
7 changes: 4 additions & 3 deletions src/Mono.Android.Runtime/Mono.Android.Runtime.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />

<!-- Only build the .NET 6+ version of 'Mono.Android.Runtime.dll' for the latest stable Android version. -->
<PropertyGroup Condition=" '$(AndroidApiLevel)' &lt; '$(AndroidDefaultTargetDotnetApiLevel)' ">
<PropertyGroup Condition=" $([MSBuild]::VersionLessThan($(AndroidApiLevel), $(AndroidDefaultTargetDotnetApiLevel))) ">
<BuildDependsOn></BuildDependsOn>
</PropertyGroup>

<!-- Copy .NET ref/runtime assemblies to bin/$(Configuration)/dotnet/packs folder -->
<PropertyGroup Condition=" '$(AndroidApiLevel)' &gt;= '$(AndroidDefaultTargetDotnetApiLevel)' ">
<PropertyGroup Condition=" $([MSBuild]::VersionGreaterThanOrEquals($(AndroidApiLevel), $(AndroidDefaultTargetDotnetApiLevel))) ">
<BuildDependsOn>
$(BuildDependsOn);
_CopyToPackDirs;
Expand All @@ -58,7 +58,8 @@
<PropertyGroup>
<InformationalVersion>$(AndroidPackVersion).$(PackVersionCommitCount); git-rev-head:$(XAVersionHash); git-branch:$(XAVersionBranch)</InformationalVersion>
<TargetPlatformIdentifier>Android</TargetPlatformIdentifier>
<TargetPlatformVersion>$(AndroidApiLevel).0</TargetPlatformVersion>
<TargetPlatformVersion Condition=" $(AndroidApiLevel.Contains('.')) ">$(AndroidApiLevel)</TargetPlatformVersion>
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">$(AndroidApiLevel).0</TargetPlatformVersion>
<SupportedOSPlatformVersion>$(AndroidMinimumDotNetApiLevel).0</SupportedOSPlatformVersion>
</PropertyGroup>
</Target>
Expand Down
2 changes: 1 addition & 1 deletion src/Mono.Android/Mono.Android.Apis.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@
<Level>37</Level>
<VersionCodeFull>37.1</VersionCodeFull>
<Id>37.1</Id>
<Stable>False</Stable>
<Stable>True</Stable>
</AndroidApiInfo>
</ItemGroup>
</Project>
Loading
Loading