diff --git a/.github/skills/update-androidsdk-packages/SKILL.md b/.github/skills/update-androidsdk-packages/SKILL.md index eb782b62fb0..a6f455abb9c 100644 --- a/.github/skills/update-androidsdk-packages/SKILL.md +++ b/.github/skills/update-androidsdk-packages/SKILL.md @@ -19,7 +19,7 @@ lives in two files: Google republishes tool revisions on their own cadence; this skill brings those two files back in sync with Google's *current stable* releases with a minimal, reviewable diff — matching the shape of PR #12371, which did exactly this (build-tools/platform-tools/cmdline-tools/cmake/emulator/sources/platform revisions all bumped, hashes recomputed, and per-arch macOS cmdline-tools support added when Apple Silicon archives showed up). -## Two hard rules — read these before touching anything +## Seven hard rules — read these before touching anything **1. Never touch the Android NDK.** `_XAAndroidNdkRelease`, `_XAAndroidNdkPkgRevision`, and every `XAAndroidNdkHash*` property in `Configuration.props`, plus the `android-ndk-r$(_XAAndroidNdkRelease)-*` @@ -44,6 +44,37 @@ nothing else in the catalog needed updating this run. Silence here is a bug: the rule is that a human decides whether/when to onboard a new API level, and they can't decide on something they were never told about. +**3. Preserve the sources package for every shipped stable platform.** Source archives are additive, +not a single "latest" package: `sources;android-37.0` and `sources;android-37.1` install into distinct +SDK directories and both are needed when both platform levels are marked `IsLatestStable`. Never +replace or remove an existing `source-NN.N_rMM.zip` entry when a new stable platform source appears. +Keep one `_AndroidSdkPackage` entry and one version-specific hash property per stable platform level, +and preserve the full API level in `Destination` (`sources\android-37.0` uses the historical +`sources\android-37` directory; `sources\android-37.1` uses `sources\android-37.1`). + +**4. Stable means Google's stable channel.** Never select an emulator or other tool from a +development, canary, beta, or preview channel merely because its revision sorts higher. Require +`channel-0` for emulator updates. If a package's channel metadata and release labeling disagree, +do not update it unattended; report the ambiguity instead. + +**5. Command-line tools are a coordinated product dependency.** Do not update only the bootstrap +pins. A command-line-tools bump must also update +`src/Xamarin.Installer.Build.Tasks/Xamarin.Installer.Common.props` and the matching latest entry in +`src/Xamarin.Installer.AndroidSDK/Feeds/AndroidManifestFeed_d18.0.xml`, including every published +host/architecture archive. Confirm `CodeGenerator.targets` tracks the property file that supplies +`AndroidCommandLineToolsVersion`. If the automated workflow is not authorized to change every +required file, stop and report the coordinated update instead of opening a partial PR. + +**6. Never execute an unverified downloader to accept licenses.** License acceptance must not run +the `android` bootstrapper, `sdkmanager`, or any payload fetched at execution time. Preserve all +existing valid fingerprints, add the pinned expected fingerprint under a cross-process lock, write +atomically, validate every line as a 40-character SHA-1 fingerprint, and create the acceptance +marker only after validation succeeds. + +**7. Extraction outputs identify the exact archive.** Packages for different hosts or architectures +may share a destination. Their incremental output stamp must include both archive identity and +expected SHA-256; `source.properties` alone is not a safe extraction sentinel. + ## Workflow ### 1. Read the current catalog @@ -69,14 +100,11 @@ dotnet run .github/skills/update-androidsdk-packages/scripts/fetch_repo_package. (These are C# file-based apps, matching the `ci_failures.cs` convention used by the `ci-status` skill — first run restores/builds, so allow a few extra seconds.) -The script sorts matches by revision (newest first) and flags anything whose path/display-name -looks like a preview build. **Treat that flag as a hint, not ground truth** — Google's -`channelRef` metadata is not a reliable stable/preview signal by itself (some genuinely-stable -packages carry a non-zero channel id, and freshly-promoted stable packages can briefly still show -old channel numbers). Cross-check the display name and version string yourself: a real stable -release reads like `36.0.1` or `28c`, not `37.0.0-rc1`, `2025.09.15-alpha01`, or anything with -`beta`/`canary`/`preview` in it. When genuinely unsure whether a release is stable, prefer the -previous confirmed-stable revision over guessing. +The script sorts matches by revision (newest first) and reports each package's channel. Require +`channel-0` for emulator updates and reject version/display names containing `alpha`, `beta`, +`canary`, `dev`, `preview`, or `rc`. For other package families, a non-zero channel or conflicting +metadata is ambiguous: keep the previous confirmed-stable revision and report it rather than +guessing. Reference `references/package-catalog.md` for the mapping between each `androidsdk.targets` entry, its manifest `path`, and its `Configuration.props` properties — it documents the current package @@ -126,11 +154,15 @@ one shared macOS zip still covers both). extension-level suffix too when Google has published one for an API level that already uses it (e.g. `platform-34-ext7_r02` → `platform-34-ext12_r01`) — do not introduce an extension suffix for an API level that never had one, or vice versa, without a clear reason from the manifest. -- The `source-NN_r0M.zip` sources package and `XAAndroidSourcesHash` should track whichever API level - is `IsLatestStable="true"` in `_PlatformPackage` (the `` uses the integer API level, - e.g. `\sources\android-37`, even when the catalog entry is `platform-37.0_r01`). Update both the - zip name/Destination and the hash - together if the latest stable API level's source archive changed. +- Keep a `source-NN.N_r0M.zip` package for every API level marked `IsLatestStable` in + `_PlatformPackage`. Treat a newly published stable source as an addition, not a replacement. + Give each archive a version-specific hash property such as `XAAndroidSourcesHash37_0`, and use + the platform's distinct SDK directory as `Destination` (`37.0` historically maps to + `\sources\android-37`; `37.1` maps to `\sources\android-37.1`). Update an existing entry in place + only when Google publishes a newer revision for that same API level. +- When command-line tools changes, update the shipped product version and feed entry described in + hard rule 5 in the same change. Do not leave bootstrap and product dependency versions split. +- Keep archive/hash-specific extraction stamps intact when adding host or architecture variants. ### 5. Validate before finishing @@ -153,8 +185,9 @@ dotnet build src/androidsdk/androidsdk.csproj --no-restore -v:minimal -t:_AddPla Also check: - **XML validity** — both edited files still parse (`dotnet build` will fail loudly on malformed XML, but a quick sanity check like `powershell -Command "[xml](Get-Content src/androidsdk/androidsdk.targets)"` catches issues faster). -- **Diff cleanliness** — `git status` and `git diff` should show changes *only* in `Configuration.props` and `src/androidsdk/androidsdk.targets`. This skill's scope is package pins, not the generated-package-xml template (`package.xml.in`) — if a routine refresh seems to require touching that file too, stop and flag it rather than including it, since automated runs of this skill (e.g. the `skill-runner` workflow) are only authorized to change the two files above. No stray temp files from hashing (the `sha256_of_url.cs` script cleans up after itself; double check if you downloaded anything manually instead). -- **The two hard rules above** — diff the NDK properties and the `_PlatformPackage` item count/API-level set against `git diff` to confirm neither was touched/expanded. +- **Diff cleanliness** — no unrelated files or stray temp downloads. Routine families remain scoped to `Configuration.props` and `src/androidsdk/androidsdk.targets`; command-line-tools updates additionally require the two shipped-product files in hard rule 5. Never edit `package.xml.in` during a routine refresh. +- **The seven hard rules above** — diff the NDK properties and the `_PlatformPackage` item count/API-level set, verify every `IsLatestStable` platform has its own sources package, verify selected releases are stable, and verify extraction outputs remain archive/hash-specific. +- **Command-line tools compatibility** — test with `licenses/android-sdk-license` and `.licenses-accepted` absent, with a pre-existing unrelated valid fingerprint, and with malformed content. Confirm the expected pinned fingerprint is created, the unrelated fingerprint is preserved, malformed content fails, writes are atomic/locked, and Gradle recognizes the Build Tools and platform licenses. No license-acceptance path may execute a network-capable Android CLI. - **Formatting** — match the existing tab indentation and column alignment in both files (several `_PlatformPackage`/`_AndroidSdkPackage` lines are hand-aligned with extra spaces before ``/`` — preserve that style rather than reformatting the whole block). ### 6. Summarize what changed diff --git a/.github/skills/update-androidsdk-packages/evals/evals.json b/.github/skills/update-androidsdk-packages/evals/evals.json index 2c129bea97d..1fd69286fb2 100644 --- a/.github/skills/update-androidsdk-packages/evals/evals.json +++ b/.github/skills/update-androidsdk-packages/evals/evals.json @@ -24,6 +24,30 @@ "prompt": "our CI machines are on an old command-line tools version (19.0 / 13114758_latest) and I keep seeing warnings that a newer cmdline-tools package is available with separate mac_arm64/mac_x86_64 downloads now — can you get us current, and check whether Android platform 36.1 has a newer revision published too?", "expected_output": "CommandLineToolsFolder/CommandLineToolsVersion bumped to the current stable release, with the command-line tools _AndroidSdkPackage split into a mac_x86_64 item (gated on _IsArm64Apple != 'true') and a new mac_arm64 item (gated on _IsArm64Apple == 'true') backed by a new XACmdlineToolsHashMacOSArm64 property, following the existing emulator/system-image pattern for _IsArm64Apple. The existing platform-36.1_r01 _PlatformPackage entry is checked against the manifest and its revision/hash updated in place if a newer one exists (no new API level added). Validation runs the BootstrapTasks build before the androidsdk.csproj build.", "assertions": [] + }, + { + "id": 5, + "prompt": "Both platform 37.0 and 37.1 are marked IsLatestStable in androidsdk.targets. Refresh the Android sources packages to the current revisions.", + "expected_output": "Both source-37.0 and source-37.1 _AndroidSdkPackage entries remain present with separate version-specific SHA-256 properties. The 37.0 package installs to sources/android-37 and the 37.1 package installs to sources/android-37.1. Updating 37.1 never removes or overwrites the 37.0 package.", + "assertions": [] + }, + { + "id": 6, + "prompt": "Update command-line tools from 19.0 to a release where sdkmanager says --licenses is deprecated and exits successfully without creating the SDK license files.", + "expected_output": "Bootstrap pins, Xamarin.Installer.Common.props, and the installer manifest feed are updated together for every host/architecture. License acceptance invokes neither sdkmanager nor the network-capable Android CLI bootstrapper: it atomically adds the pinned expected fingerprint under a cross-process lock while preserving existing valid fingerprints and rejecting malformed files. Validation starts without either license file, then repeats with an unrelated valid fingerprint and malformed content, and confirms Gradle accepts the pinned Build Tools and platform licenses.", + "assertions": [] + }, + { + "id": 7, + "prompt": "The manifest lists emulator 37.2.5 on channel-2 and emulator 37.1.11 on channel-0. Refresh us to the newest emulator.", + "expected_output": "Emulator 37.1.11 is selected because channel-0 is required for emulator updates. The newer 37.2.5 development-channel package is explicitly rejected. All four stable host/architecture archives are hashed and pinned.", + "assertions": [] + }, + { + "id": 8, + "prompt": "Add a new macOS arm64 command-line-tools archive. It extracts to the same SDK directory as the x64 archive, so source.properties can stay as the shared output stamp.", + "expected_output": "The arm64 archive may share the destination, but source.properties is rejected as the sole incremental output. Extraction uses a stamp containing archive identity and expected SHA-256 so switching architectures or hashes forces replacement with the correct package.", + "assertions": [] } ] } diff --git a/.github/skills/update-androidsdk-packages/references/package-catalog.md b/.github/skills/update-androidsdk-packages/references/package-catalog.md index 0b31b232d02..667fef1ab9b 100644 --- a/.github/skills/update-androidsdk-packages/references/package-catalog.md +++ b/.github/skills/update-androidsdk-packages/references/package-catalog.md @@ -9,14 +9,14 @@ drift as the skill is used. |---|---|---|---|---| | build-tools | `build-tools` | `XABuildToolsVersion`, `XABuildToolsFolder` | `XABuildToolsHashMacOS/Linux/Windows` | `build-tools_r$(XABuildToolsVersion)_{macosx,linux,windows}.zip` | | platform-tools | `platform-tools` | `XAPlatformToolsVersion` | `XAPlatformToolsHashMacOS/Linux/Windows` | `platform-tools_r$(XAPlatformToolsVersion)-{darwin,linux,win}.zip` | -| cmdline-tools | `cmdline-tools` | `CommandLineToolsFolder`, `CommandLineToolsVersion` | `XACmdlineToolsHashMacOS`, `XACmdlineToolsHashMacOSArm64`, `XACmdlineToolsHashLinux/Windows` | `commandlinetools-{mac_x86_64,mac_arm64,linux,win}-$(CommandLineToolsVersion).zip` — macOS is arch-split; other hosts are one zip | +| cmdline-tools | `cmdline-tools` | `CommandLineToolsFolder`, `CommandLineToolsVersion`; shipped `AndroidCommandLineToolsVersion` in `src/Xamarin.Installer.Build.Tasks/Xamarin.Installer.Common.props` | `XACmdlineToolsHashMacOS`, `XACmdlineToolsHashMacOSArm64`, `XACmdlineToolsHashLinux/Windows` | `commandlinetools-{mac_x86_64,mac_arm64,linux,win}-$(CommandLineToolsVersion).zip`; also update the latest entry in `src/Xamarin.Installer.AndroidSDK/Feeds/AndroidManifestFeed_d18.0.xml` | | cmake | `cmake;` | `AndroidCmakeVersion` | `XACmakeHashMacOS/Linux/Windows` | `cmake-$(AndroidCmakeVersion)-{darwin,linux,windows}.zip` | | emulator | `emulator` | `EmulatorVersion`, `EmulatorPkgRevision` | `XAEmulatorHashMacOSx64`, `XAEmulatorHashMacOSArm64`, `XAEmulatorHashLinux/Windows` | `emulator-{darwin_x64,darwin_aarch64,linux_x64,windows_x64}-$(EmulatorVersion).zip`; also drives a synthesized `package.xml` via `package.xml.in` | | API 29 system image | `sys-img/android` manifest, `path="system-images;android-29;default;{x86_64,arm64-v8a}"` | (fixed `x86_64-29_r08*`/`arm64-v8a-29_r08` filenames — check manifest for a newer `rNN` if refreshing) | `XASystemImageHashMacOSx64/MacOSArm64/Linux/Windows` | `{x86_64,arm64-v8a}-29_r08{-darwin,-linux,-windows,}.zip` under `sys-img/android/` | | m2repository | `extras;android;m2repository` | (embedded in filename, e.g. `_r47`) | `XAAndroidM2RepositoryHash` | `android_m2repository_r47.zip`, host-agnostic | | docs | `docs` | (embedded in filename, e.g. `-24_r01`) | `XAAndroidDocsHash` | `docs-24_r01.zip`, host-agnostic | -| sources | `sources;android-NN` (tracks the latest stable platform) | (embedded in filename) | `XAAndroidSourcesHash` | `source-_r0M.zip`, `Destination` embeds the API level too | -| platform APIs | `platforms;android-NN` | n/a — `_PlatformPackage` item's `Include` *is* the version string | `Hash` metadata per `_PlatformPackage` item | `_PlatformPackage` item group near the top of the file; one `IsLatestStable="true"` entry drives default install + the sources package above | +| sources | `sources;android-NN.N` (one per stable shipped platform) | (embedded in filename) | Version-specific, e.g. `XAAndroidSourcesHash37_0` | One `source-NN.N_r0M.zip` entry per `IsLatestStable` platform; preserve each distinct `Destination` (`37.0` historically uses `sources\android-37`, while `37.1` uses `sources\android-37.1`) | +| platform APIs | `platforms;android-NN` | n/a — `_PlatformPackage` item's `Include` *is* the version string | `Hash` metadata per `_PlatformPackage` item | `_PlatformPackage` item group near the top of the file; every `IsLatestStable="true"` entry drives default install and requires a corresponding sources package | | **Android NDK — OUT OF SCOPE** | `ndk` | `_XAAndroidNdkRelease`, `_XAAndroidNdkPkgRevision` | `XAAndroidNdkHashMacOS/Linux/Windows` | `android-ndk-r$(_XAAndroidNdkRelease)-$(_NdkHostTag).zip` — **never edit as part of this skill** | ## Notes on Apple Silicon archives @@ -30,6 +30,18 @@ an `'$(_IsArm64Apple)' != 'true'` item for the existing x86_64/generic macOS arc property. Don't add an arm64-specific branch speculatively for families where Google still ships one universal/x86_64-only macOS archive. +Every extraction output stamp must include the selected archive identity and SHA-256. Multiple +architectures can intentionally share a destination, so `source.properties` alone must never be +used as the incremental output. + +## Notes on stable channels and licenses + +Emulator updates must come from `channel-0`; a higher development-channel revision is not stable. +Command-line-tools updates are incomplete unless bootstrap pins, shipped product versions, and feed +archives all move together. License acceptance must remain deterministic and offline: preserve +valid existing fingerprints and atomically add the pinned expected SHA-1 under a cross-process +lock. Never invoke the command-line tools' `android` bootstrapper or another mutable downloader. + ## Notes on platform extension levels Some platform API levels ship as a numbered "extension" (e.g. `platform-34-ext12_r01`) rather than diff --git a/Configuration.props b/Configuration.props index 16c7932f302..c364d4659d6 100644 --- a/Configuration.props +++ b/Configuration.props @@ -106,17 +106,18 @@ EE39AD5967E95C2A07F04DBCBDE96B1A0C916BA376096DB5D2F498B7727A5D1D D230F13842F60F782A8645F9C813F8F845BF36089EA7289F28C48F17979313F1 45F4D63113E895EBDE0C90F194099A4676B6AC653BD28D54314A9E022BBC1A99 - 5673201E6F3869F418EEED3B5CB6C4BE7401502BD0AAE1B12A29D164D647A54E - 7EC965280A073311C339E571CD5DE778B9975026CFCBE79F2B1CDCB1E15317EE - 98B565CB657B012DAE6794CEFC0F66AE1EFB4690C699B78A614B4A6A3505B003 + 7E601C04E7173754B3D051A87BB4C3A8243C65A9D7BFA9356ED6499FB8953FA3 + 58DA8F215781CC0208743E88B65AE259780C55E7EB40E50373D377CF369232D6 + 0877A1D048FE4A24EFE2EFF536CA4223F7ADEB58648BB81909D33C446918CFA8 + E5885E2E59038C0778A85FC19F01DE7CE7C567C105553F7617B936B1E0E87B2B 130B80221ABDA282B96E3669CEF5DCCF0D916E988E08051F5DACCDD03360A1AC 46BDA18F0F3C28A55F88DA4BA05FEC21ABE3D9BCA0A78A8B18D444987B3DC817 3A78AD82A3F3E9E613E255618D2ACF1B3C4BDB24EF6E1F9341227CF6FC492A89 - 3029489D4B2F868DC5347AA27B1E52FB48D6D28ABD51278E3FBEC2EE73201EDF - EDA85B9BFFD0926B7A01EA334A30AB41827F573CBDE8F7F97FCD8C5B38F039F6 - 58BFDF0572F06EC007A7287154CDC6B2EBFEA947D07A1E26A0F6B5E1A39E9191 - 9F2855BFE98E80728E61D45B0EA72BA22F64952C9330559FA4E2CD3698A32231 + C1A3890F95B8868198918FAD05FFCA16FA20404D93547BA545FF5A5867EE7005 + 22530DE9363F34EA945ECB5CAD74523ABD4B615F27F3C1A9899EFB183EA9E144 + 95771E0AE431897B2A4BD2D97FA095F29A8B0624A7B216BAF529F9306161C266 + 5FF441F3B12ACE9B13E9CF96FB0007D233967718652A8110705E995AC47BFEB7 B5C3FDA1F4B4931C30518D342E4AD5F7464945E0CDCED3538D4FF2E12F7BF201 7FD1610E16A69AC2E202278E82077DE134CE404FE099D872019F69F3A340ACDD @@ -125,7 +126,9 @@ A3F91808DCE50C1717737DE90C18479ED3A78B147E06985247D138E7AB5123D0 68DB2690CB92E4EE5373AC9B792642C90717D8F417D83ECCEA48781171B3182A - A853F452B8BA94933EB56ED4E0F622991F9D6DE6E0AC19923AA47414D79B9129 + A853F452B8BA94933EB56ED4E0F622991F9D6DE6E0AC19923AA47414D79B9129 + F63736E27B0D283298116DA8BCE2C024DE28C7E4081044B30716FCB6E0FA13F1 + 24333f8a63b6825ea9c5514f83c2829b004d1fee <_XAAndroidNdkRelease>28c @@ -180,12 +183,12 @@ avdmanager.bat $(AndroidSdkFullPath)\tools $(AndroidToolPath)\bin - 19.0 - 13114758_latest + 23.0 + 16111833_latest $(AndroidSdkFullPath)\cmdline-tools\$(CommandLineToolsFolder)\bin - 15004761 - 36.4.10 + 15917651 + 37.1.11 $(AndroidSdkFullPath)\emulator emulator emulator.exe diff --git a/build-tools/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/EnsureAndroidSdkLicense.cs b/build-tools/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/EnsureAndroidSdkLicense.cs new file mode 100644 index 00000000000..3a5bc5ebb77 --- /dev/null +++ b/build-tools/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/EnsureAndroidSdkLicense.cs @@ -0,0 +1,106 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Xamarin.Android.Tools.BootstrapTasks +{ + public sealed class EnsureAndroidSdkLicense : Task + { + [Required] + public string LicenseDirectory { get; set; } = ""; + + [Required] + public ITaskItem [] LicenseHashes { get; set; } = []; + + public int LockTimeoutSeconds { get; set; } = 60; + + public bool ValidateOnly { get; set; } + + public override bool Execute () + { + Directory.CreateDirectory (LicenseDirectory); + + var licenseFile = Path.Combine (LicenseDirectory, "android-sdk-license"); + var lockFile = Path.Combine (LicenseDirectory, ".android-sdk-license.lock"); + using (AcquireLock (lockFile)) { + var licenses = new List (); + if (File.Exists (licenseFile)) { + foreach (var line in File.ReadAllLines (licenseFile)) { + var license = line.Trim (); + if (license.Length == 0) + continue; + if (!IsSha1 (license)) { + Log.LogError ($"Android SDK license file '{licenseFile}' contains invalid fingerprint '{license}'."); + return false; + } + if (!licenses.Contains (license, StringComparer.OrdinalIgnoreCase)) + licenses.Add (license); + } + } + + foreach (var item in LicenseHashes) { + var license = item.ItemSpec.Trim (); + if (!IsSha1 (license)) { + Log.LogError ($"Android SDK license fingerprint '{license}' is not a 40-character SHA-1 hash."); + return false; + } + if (ValidateOnly && !licenses.Contains (license, StringComparer.OrdinalIgnoreCase)) { + Log.LogError ($"Android SDK license file '{licenseFile}' does not contain expected fingerprint '{license}'."); + return false; + } + if (!ValidateOnly && !licenses.Contains (license, StringComparer.OrdinalIgnoreCase)) + licenses.Add (license); + } + + if (licenses.Count == 0) { + Log.LogError ("At least one Android SDK license fingerprint is required."); + return false; + } + + if (!ValidateOnly) + WriteAtomically (licenseFile, licenses); + } + + return !Log.HasLoggedErrors; + } + + FileStream AcquireLock (string lockFile) + { + var timer = Stopwatch.StartNew (); + while (true) { + try { + return new FileStream (lockFile, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); + } catch (IOException) when (timer.Elapsed < TimeSpan.FromSeconds (LockTimeoutSeconds)) { + Thread.Sleep (100); + } + } + } + + static bool IsSha1 (string value) + { + return value.Length == 40 && value.All (character => + (character >= '0' && character <= '9') || + (character >= 'a' && character <= 'f') || + (character >= 'A' && character <= 'F')); + } + + static void WriteAtomically (string destination, IEnumerable lines) + { + var temporaryFile = Path.Combine (Path.GetDirectoryName (destination) ?? "", $".{Path.GetFileName (destination)}.{Guid.NewGuid ():N}.tmp"); + try { + File.WriteAllText (temporaryFile, string.Concat (lines.Select (line => line + "\n")), new UTF8Encoding (encoderShouldEmitUTF8Identifier: false)); + File.Move (temporaryFile, destination, overwrite: true); + } finally { + File.Delete (temporaryFile); + } + } + } +} diff --git a/src/androidsdk/androidsdk.targets b/src/androidsdk/androidsdk.targets index 4768da3cf37..9e631c49614 100644 --- a/src/androidsdk/androidsdk.targets +++ b/src/androidsdk/androidsdk.targets @@ -16,9 +16,7 @@ obj\$(Configuration)\ <_AndroidRepositoryUrl>https://dl.google.com/android/repository/ - <_SdkManagerDir>$(AndroidSdkFullPath)\cmdline-tools\$(CommandLineToolsFolder)\bin - <_SdkManagerPath Condition=" '$(HostOS)' == 'Windows' ">$(_SdkManagerDir)\sdkmanager.bat - <_SdkManagerPath Condition=" '$(HostOS)' != 'Windows' ">$(_SdkManagerDir)\sdkmanager + <_AndroidSdkLicenseFile>$(AndroidSdkFullPath)\licenses\android-sdk-license <_LicensesAcceptedFile>$(AndroidSdkFullPath)\licenses\.licenses-accepted @@ -53,6 +51,7 @@ + - <_AndroidSdkPackage Include="commandlinetools-mac-$(CommandLineToolsVersion).zip" Condition=" '$(HostOS)' == 'Darwin' "> + + <_AndroidSdkPackage Include="commandlinetools-mac_x86_64-$(CommandLineToolsVersion).zip" Condition=" '$(HostOS)' == 'Darwin' and '$(_IsArm64Apple)' != 'true' "> $(XACmdlineToolsHashMacOS) $(AndroidSdkFullPath)\cmdline-tools\$(CommandLineToolsFolder) + <_AndroidSdkPackage Include="commandlinetools-mac_arm64-$(CommandLineToolsVersion).zip" Condition=" '$(_IsArm64Apple)' == 'true' "> + $(XACmdlineToolsHashMacOSArm64) + $(AndroidSdkFullPath)\cmdline-tools\$(CommandLineToolsFolder) + <_AndroidSdkPackage Include="commandlinetools-linux-$(CommandLineToolsVersion).zip" Condition=" '$(HostOS)' == 'Linux' "> $(XACmdlineToolsHashLinux) $(AndroidSdkFullPath)\cmdline-tools\$(CommandLineToolsFolder) @@ -240,9 +243,13 @@ $(AndroidSdkFullPath)\docs <_AndroidSdkPackage Include="source-37.0_r02.zip"> - $(XAAndroidSourcesHash) + $(XAAndroidSourcesHash37_0) $(AndroidSdkFullPath)\sources\android-37 + <_AndroidSdkPackage Include="source-37.1_r01.zip"> + $(XAAndroidSourcesHash37_1) + $(AndroidSdkFullPath)\sources\android-37.1 + + Outputs="%(_AndroidSdkPackage.Destination)\.extracted-%(_AndroidSdkPackage.Identity)-%(_AndroidSdkPackage.Hash)"> <_StripComponents>%(_AndroidSdkPackage.StripComponents) <_StripComponents Condition=" '$(_StripComponents)' == '' ">1 @@ -373,6 +381,7 @@ /> + - - + + + + +