Skip to content

Commit 3a39d22

Browse files
committed
[build] Use $(AndroidPlatformId) when appropriate
Context: 485e39b Context: eb08bb4 ...and doubtless others... Three MSBuild properties control the `android.jar` which is bound and the `$(TargetFrameworkVersion)` of `Mono.Android.dll`: * `$(AndroidApiLevel)`: The API level that is bound. Must be an int. * `$(AndroidFrameworkVersion)`: The `$(TargetFrameworkVersion)` of the generated `Mono.Android.dll`. Must be *mostly* parseable by `System.Version` except with a leading `v`, e.g. `v10.0`. * `$(AndroidPlatformId)`: The "ID" of the API level. *Most* of the time, `$(AndroidApiLevel)` and `$(AndroidPlatformId)` will be *identical*: for API-29, they're both `29`. Where they differ is for new *preview* API levels, such as API-R: `$(AndroidApiLevel)` will be 30, but `$(AndroidPlatformId)` is `R`. The distinction is important because various filesystem paths within the Android SDK use the "id" and *not* the API level when they differ, e.g. the API-R `android.jar` is installed into: $(AndroidSdkDirectory)/platforms/android-R/android.jar We thus need to be *careful* when distinguishing between `$(AndroidApiLevel)` and `$(AndroidPlatformId)`, using the former when an integer is *required*, and using the latter whenever it refers to filesystem paths. Unfortunately, we *haven't* been careful, because these values really only differ for ~4 months out of the year, and for only one `$(TargetFrameworkVersion)` version. Start bringing some sanity...and finding bugs while we do so: `api-xml-adjuster.targets` should use `%(AndroidApiInfo.Id)` and *not* `%(AndroidApiLevel.Level)`, as it references filesystem locations. Consequently, `src/Mono.Android/Profiles/api-30.params.txt` must be renamed to `src/Mono.Android/Profiles/api-R.params.txt` so that it correctly embeds the `$(AndroidPlatformId)` value. `Mono.Android.targets` should likewise use `$(AndroidPlatformId)` and not `$(AndroidApiLevel)` when using filesystem paths from the SDK. For good measure, `Mono.Android.csproj` now overrides `$(IntermediateOutputPath)` to contain `$(AndroidPlatformId)`, because why not (MOAR CONSISTENCY!). These changes, unfortunately, introduce breakage, which will need to be addressed: *Because* API-R was installed into `$(AndroidSdkDirectory)/platforms/android-R`, `api-versions.xml` *was not previously used* because `Mono.Android.targets` was using `$(AndroidApiLevel)`, and `platforms/android-30/data/api-version.xml` does not yet exist. (It will come June! But not now.) As it didn't exist, it hit the fallback path and used `platform-tools/api/api-versions.xml` (4cd2060). You would *think* this wouldn't be a problem, but the API-R `api-versions.xml` is *missing* members relative to platform-tools, resulting in members *missing* `RegisterAttribute.ApiSince` values, which `Microsoft.DotNet.ApiCompat.exe` reports, e.g.: CannotChangeAttribute : Attribute 'Android.Runtime.RegisterAttribute' on 'Java.Lang.StringBuilder.TrimToSize()' changed from '[RegisterAttribute("trimToSize", "()V", "", ApiSince=9)]' in the contract to '[RegisterAttribute("trimToSize", "()V", "")]' in the implementation dotnet/java-interop@568d24ac added support to allow `generator --apiversions` to be specified multiple times. Take advantage of this new support to pass in the `api-versions.xml` files from *both* `platforms/android-R` *and* `platform-tools/api` when binding API levels > API-29. (Attempting to do this for *all* versions which have both resulted in bizarre API compat errors, as the `RegisterAttribute.ApiSince` value was *cleared*. ?!) This works around the deficiency in API-R's `api-versions.xml` and allows us to retain correct `RegisterAttribute.ApiSince` values. Aside: to manually build the API-R binding, use: msbuild /p:AndroidPlatformId=R /p:AndroidApiLevel=30 /p:AndroidFrameworkVersion=v10.0.99 src/Mono.Android/Mono.Android.csproj /v:diag > b.txt
1 parent 12df2be commit 3a39d22

File tree

5 files changed

+24
-27
lines changed

5 files changed

+24
-27
lines changed

build-tools/api-xml-adjuster/api-xml-adjuster.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
</_Api>
1616
</ItemGroup>
1717
<CreateItem Include="@(_Api)"
18-
AdditionalMetadata="ParameterDescription=$(_TopDir)\src\Mono.Android\Profiles\api-%(_Api.Level).params.txt;ClassParseXml=$(_OutputPath)api\api-%(_Api.Level).xml.class-parse;ApiAdjustedXml=$(_OutputPath)api\api-%(_Api.Level).xml.in">
18+
AdditionalMetadata="ParameterDescription=$(_TopDir)\src\Mono.Android\Profiles\api-%(_Api.Id).params.txt;ClassParseXml=$(_OutputPath)api\api-%(_Api.Id).xml.class-parse;ApiAdjustedXml=$(_OutputPath)api\api-%(_Api.Id).xml.in">
1919
<Output TaskParameter="Include" ItemName="ApiFileDefinition"/>
2020
</CreateItem>
2121
</Target>

src/Mono.Android/Mono.Android.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@
9797
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
9898
<PropertyGroup>
9999
<ImplicitlyExpandDesignTimeFacades>False</ImplicitlyExpandDesignTimeFacades>
100-
<IntermediateOutputPath>$(IntermediateOutputPath)android-$(AndroidApiLevel)\</IntermediateOutputPath>
100+
<IntermediateOutputPath>$(IntermediateOutputPath)android-$(AndroidPlatformId)\</IntermediateOutputPath>
101101
</PropertyGroup>
102102
<Import Project="Mono.Android.targets" />
103103
<PropertyGroup>

src/Mono.Android/Mono.Android.targets

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,18 @@
7979
Outputs="$(IntermediateOutputPath)mcw\Mono.Android.projitems">
8080
<MakeDir Directories="$(IntermediateOutputPath)mcw" />
8181
<PropertyGroup>
82-
<_ApiVersions Condition="Exists('$(AndroidSdkDirectory)\platforms\android-$(AndroidApiLevel)\data\api-versions.xml')">"$(AndroidSdkDirectory)\platforms\android-$(AndroidApiLevel)\data\api-versions.xml"</_ApiVersions>
83-
<_ApiVersions Condition="'$(_ApiVersions)'==''">"$(AndroidSdkDirectory)\platform-tools\api\api-versions.xml"</_ApiVersions>
82+
<_PlatformIdVersions>$(AndroidSdkDirectory)\platforms\android-$(AndroidPlatformId)\data\api-versions.xml</_PlatformIdVersions>
8483
</PropertyGroup>
84+
<ItemGroup>
85+
<_ApiVersion
86+
Condition=" '$(AndroidApiLevel)' > 29 Or !Exists ('$(_PlatformIdVersions)')"
87+
Include="$(AndroidSdkDirectory)\platform-tools\api\api-versions.xml"
88+
/>
89+
<_ApiVersion
90+
Condition="Exists('$(_PlatformIdVersions)')"
91+
Include="$(_PlatformIdVersions)"
92+
/>
93+
</ItemGroup>
8594
<PropertyGroup>
8695
<Generator>"$(XAInstallPrefix)xbuild\Xamarin\Android\generator.exe"</Generator>
8796
<_GenFlags>--public --product-version=7</_GenFlags>
@@ -91,7 +100,7 @@
91100
<_Fixup>--fixup=metadata</_Fixup>
92101
<_Enums1>--preserve-enums --enumflags=enumflags --enumfields=map.csv --enummethods=methodmap.csv</_Enums1>
93102
<_Enums2>--enummetadata=$(IntermediateOutputPath)mcw\enummetadata</_Enums2>
94-
<_Versions>--apiversions=$(_ApiVersions)</_Versions>
103+
<_Versions>@(_ApiVersion->'--apiversions="%(Identity)"', ' ')</_Versions>
95104
<_Annotations>--annotations="$(AndroidSdkDirectory)\platform-tools\api\annotations.zip"</_Annotations>
96105
<_Assembly>--assembly="Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"</_Assembly>
97106
<_TypeMap>--type-map-report=$(IntermediateOutputPath)mcw\type-mapping.txt</_TypeMap>

tests/api-compatibility/acceptable-breakages-v10.0.99.txt

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
11
Compat issues with assembly Mono.Android:
2-
CannotAddAbstractMembers : Member 'Android.Telephony.CellInfo.CellIdentity' is abstract in the implementation but is missing in the contract.
3-
CannotAddAbstractMembers : Member 'Android.Telephony.CellInfo.CellSignalStrength' is abstract in the implementation but is missing in the contract.
4-
CannotAddAbstractMembers : Member 'Android.Telephony.CellInfo.CellIdentity.get()' is abstract in the implementation but is missing in the contract.
5-
CannotAddAbstractMembers : Member 'Android.Telephony.CellInfo.CellSignalStrength.get()' is abstract in the implementation but is missing in the contract.
62
InterfacesShouldHaveSameMembers : Interface member 'Android.App.Application.IActivityLifecycleCallbacks.OnActivityPostCreated(Android.App.Activity, Android.OS.Bundle)' is present in the implementation but not in the contract.
73
InterfacesShouldHaveSameMembers : Interface member 'Android.App.Application.IActivityLifecycleCallbacks.OnActivityPostDestroyed(Android.App.Activity)' is present in the implementation but not in the contract.
84
InterfacesShouldHaveSameMembers : Interface member 'Android.App.Application.IActivityLifecycleCallbacks.OnActivityPostPaused(Android.App.Activity)' is present in the implementation but not in the contract.
@@ -24,11 +20,7 @@ InterfacesShouldHaveSameMembers : Interface member 'Android.Database.ICursor.Not
2420
InterfacesShouldHaveSameMembers : Interface member 'Android.Database.ICursor.SetNotificationUris(Android.Content.ContentResolver, System.Collections.Generic.IList<Android.Net.Uri>)' is present in the implementation but not in the contract.
2521
InterfacesShouldHaveSameMembers : Interface member 'Android.Media.AudioRecord.IOnRoutingChangedListener.Android.Media.IAudioRoutingOnRoutingChangedListener.OnRoutingChanged(Android.Media.IAudioRouting)' is present in the implementation but not in the contract.
2622
InterfacesShouldHaveSameMembers : Interface member 'Android.Media.AudioTrack.IOnRoutingChangedListener.Android.Media.IAudioRoutingOnRoutingChangedListener.OnRoutingChanged(Android.Media.IAudioRouting)' is present in the implementation but not in the contract.
27-
InterfacesShouldHaveSameMembers : Interface member 'Android.Media.MediaCas.IEventListener.OnPluginStatusUpdate(Android.Media.MediaCas, System.Int32, System.Int32)' is present in the implementation but not in the contract.
28-
InterfacesShouldHaveSameMembers : Interface member 'Android.Media.MediaCas.IEventListener.OnResourceLost(Android.Media.MediaCas)' is present in the implementation but not in the contract.
2923
InterfacesShouldHaveSameMembers : Interface member 'Android.Media.MediaCas.IEventListener.OnSessionEvent(Android.Media.MediaCas, Android.Media.MediaCas.Session, System.Int32, System.Int32, System.Byte[])' is present in the implementation but not in the contract.
30-
InterfacesShouldHaveSameMembers : Interface member 'Android.OS.IBinder.SuggestedMaxIpcSizeBytes' is present in the implementation but not in the contract.
31-
InterfacesShouldHaveSameMembers : Interface member 'Android.OS.IBinder.SuggestedMaxIpcSizeBytes.get()' is present in the implementation but not in the contract.
3224
InterfacesShouldHaveSameMembers : Interface member 'Android.Preferences.IPreferenceDataStore.GetBoolean(System.String, System.Boolean)' is present in the implementation but not in the contract.
3325
InterfacesShouldHaveSameMembers : Interface member 'Android.Preferences.IPreferenceDataStore.GetFloat(System.String, System.Single)' is present in the implementation but not in the contract.
3426
InterfacesShouldHaveSameMembers : Interface member 'Android.Preferences.IPreferenceDataStore.GetInt(System.String, System.Int32)' is present in the implementation but not in the contract.
@@ -135,28 +127,14 @@ InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IComparator.ThenCo
135127
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IComparator.ThenComparingLong(Java.Util.Functions.IToLongFunction)' is present in the implementation but not in the contract.
136128
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IIterator.ForEachRemaining(Java.Util.Functions.IConsumer)' is present in the implementation but not in the contract.
137129
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IList.Java.Lang.IIterable.Spliterator()' is present in the implementation but not in the contract.
138-
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IList.Of()' is present in the implementation but not in the contract.
139-
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IList.Of(Java.Lang.Object)' is present in the implementation but not in the contract.
140-
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IList.Of(Java.Lang.Object, Java.Lang.Object)' is present in the implementation but not in the contract.
141-
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IList.Of(Java.Lang.Object, Java.Lang.Object, Java.Lang.Object)' is present in the implementation but not in the contract.
142-
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IList.Of(Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object)' is present in the implementation but not in the contract.
143-
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IList.Of(Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object)' is present in the implementation but not in the contract.
144-
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IList.Of(Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object)' is present in the implementation but not in the contract.
145-
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IList.Of(Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object)' is present in the implementation but not in the contract.
146-
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IList.Of(Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object)' is present in the implementation but not in the contract.
147-
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IList.Of(Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object)' is present in the implementation but not in the contract.
148-
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IList.Of(Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object)' is present in the implementation but not in the contract.
149-
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IList.Of(Java.Lang.Object[])' is present in the implementation but not in the contract.
150130
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IList.ReplaceAll(Java.Util.Functions.IUnaryOperator)' is present in the implementation but not in the contract.
151131
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IList.Sort(Java.Util.IComparator)' is present in the implementation but not in the contract.
152132
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IMap.Compute(Java.Lang.Object, Java.Util.Functions.IBiFunction)' is present in the implementation but not in the contract.
153133
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IMap.ComputeIfAbsent(Java.Lang.Object, Java.Util.Functions.IFunction)' is present in the implementation but not in the contract.
154134
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IMap.ComputeIfPresent(Java.Lang.Object, Java.Util.Functions.IBiFunction)' is present in the implementation but not in the contract.
155-
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IMap.Entry(Java.Lang.Object, Java.Lang.Object)' is present in the implementation but not in the contract.
156135
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IMap.ForEach(Java.Util.Functions.IBiConsumer)' is present in the implementation but not in the contract.
157136
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IMap.GetOrDefault(Java.Lang.Object, Java.Lang.Object)' is present in the implementation but not in the contract.
158137
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IMap.Merge(Java.Lang.Object, Java.Lang.Object, Java.Util.Functions.IBiFunction)' is present in the implementation but not in the contract.
159-
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IMap.Of()' is present in the implementation but not in the contract.
160138
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IMap.Of(Java.Lang.Object, Java.Lang.Object)' is present in the implementation but not in the contract.
161139
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IMap.Of(Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object)' is present in the implementation but not in the contract.
162140
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.IMap.Of(Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object, Java.Lang.Object)' is present in the implementation but not in the contract.
@@ -249,3 +227,13 @@ InterfacesShouldHaveSameMembers : Interface member 'Java.Util.Functions.IPredica
249227
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.Functions.IUnaryOperator.Identity()' is present in the implementation but not in the contract.
250228
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.Streams.ICollector.Of(Java.Util.Functions.ISupplier, Java.Util.Functions.IBiConsumer, Java.Util.Functions.IBinaryOperator, Java.Util.Functions.IFunction, Java.Util.Streams.CollectorCharacteristics[])' is present in the implementation but not in the contract.
251229
InterfacesShouldHaveSameMembers : Interface member 'Java.Util.Streams.ICollector.Of(Java.Util.Functions.ISupplier, Java.Util.Functions.IBiConsumer, Java.Util.Functions.IBinaryOperator, Java.Util.Streams.CollectorCharacteristics[])' is present in the implementation but not in the contract.
230+
MembersMustExist : Member 'Android.Telephony.CellInfoCdma.CellIdentity.get()' does not exist in the implementation but it does exist in the contract.
231+
MembersMustExist : Member 'Android.Telephony.CellInfoCdma.CellSignalStrength.get()' does not exist in the implementation but it does exist in the contract.
232+
MembersMustExist : Member 'Android.Telephony.CellInfoGsm.CellIdentity.get()' does not exist in the implementation but it does exist in the contract.
233+
MembersMustExist : Member 'Android.Telephony.CellInfoGsm.CellSignalStrength.get()' does not exist in the implementation but it does exist in the contract.
234+
MembersMustExist : Member 'Android.Telephony.CellInfoLte.CellIdentity.get()' does not exist in the implementation but it does exist in the contract.
235+
MembersMustExist : Member 'Android.Telephony.CellInfoLte.CellSignalStrength.get()' does not exist in the implementation but it does exist in the contract.
236+
MembersMustExist : Member 'Android.Telephony.CellInfoTdscdma.CellIdentity.get()' does not exist in the implementation but it does exist in the contract.
237+
MembersMustExist : Member 'Android.Telephony.CellInfoTdscdma.CellSignalStrength.get()' does not exist in the implementation but it does exist in the contract.
238+
MembersMustExist : Member 'Android.Telephony.CellInfoWcdma.CellIdentity.get()' does not exist in the implementation but it does exist in the contract.
239+
MembersMustExist : Member 'Android.Telephony.CellInfoWcdma.CellSignalStrength.get()' does not exist in the implementation but it does exist in the contract.

0 commit comments

Comments
 (0)