-
Notifications
You must be signed in to change notification settings - Fork 536
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[XABT] Use ZipArchive to build APKs. (#9623)
It would appear we no longer require features not available in `System.IO.Compression.ZipArchive` in order to build `.apk`/`.aab` files. Additionally, it appears that `ZipArchive` is noticeably faster than our current usage of `LibZipSharp`. Switch the `BuildArchive` task to preferring `ZipArchive` over `LibZipSharp` when possible for building APKs. The `LibZipSharp` implementation is maintained as a fallback and in case future new `.apk`/`.aab` requirements necessitate its use. Archive sizes for `.apk` increase 1.3%-2.7% which seems acceptable. `.aab` sizes remain roughly the same, likely because `bundletool` repacks them. ### Implementation Notes - `netstandard2.0` does not expose API for examining a `CRC` or `CompressionMethod` of an existing entry in a Zip file, though both `net472` and `net9.0` have private fields. As such, we use reflection to access these private fields. If the runtime we are using does not have these fields, we will fall back to using `LibZipSharp` as we do now. - Abstract our required Zip API to `IZipArchive` so that we can switch between `System.IO.Compression.ZipFile` and `LibZipSharp` as needed. - Due to a bug on .NET Framework where uncompressed files are stored as `Deflate` with a compression level of `0` instead of being stored as `Store`, if we detect that we need to store uncompressed files we will fall back to `LibZipSharp`. This seems to be an uncommon scenario that is not hit by any of our default flows. - Can force fallback to `LibZipSharp` with `$(_AndroidUseLibZipSharp)`=`true`. ### Performance Measurements of the `BuildArchive` task when using the `android` template for initial and incremental build scenarios. #### Debug - FastDev | Scenario | `main` | This PR | | --------------- | ------- | ------- | | Full | 2.428 s | 339 ms | | NoChanges | not run | not run | | ChangeResource | 34 ms | 19 ms | | AddResource | 23 ms | 17 ms | | ChangeCSharp | not run | not run | | ChangeCSharpJLO | not run | not run | | Archive Size | 5,390,140 bytes | 5,537,596 bytes | #### Debug - EmbedAssembliesInApk | Scenario | `main` | This PR | | --------------- | -------- | ------- | | Full | 34.856 s | 4.313 s | | NoChanges | not run | not run | | ChangeResource | 33.385 s | 4.165 s | | AddResource | 32.206 s | 3.963 s | | ChangeCSharp | 32.060 s | 3.979 s | | ChangeCSharpJLO | 33.161 s | 3.997 s | | Archive Size | 76,653,152 bytes | 77,710,097 bytes | #### Release | Scenario | `main` | This PR | | --------------- | ------- | ------- | | Full | 2.195 s | 387 ms | | NoChanges | not run | not run | | ChangeResource | 134 ms | 73 ms | | AddResource | 685 ms | 182 ms | | ChangeCSharp | 705 ms | 142 ms | | ChangeCSharpJLO | 703 ms | 149 ms | | Archive Size | 6,917,153 bytes | 6,917,319 bytes | CI build that falls back to `LibZipSharp` to ensure it still passes our tests: https://devdiv.visualstudio.com/DevDiv/_build/results?buildId=10720142
- Loading branch information
Showing
6 changed files
with
468 additions
and
107 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
src/Xamarin.Android.Build.Tasks/Utilities/UtilityExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
using System; | ||
using System.IO; | ||
using System.IO.Compression; | ||
using Xamarin.Tools.Zip; | ||
|
||
namespace Xamarin.Android.Tasks; | ||
|
||
static class UtilityExtensions | ||
{ | ||
public static System.IO.Compression.CompressionLevel ToCompressionLevel (this CompressionMethod method) | ||
{ | ||
switch (method) { | ||
case CompressionMethod.Store: | ||
return System.IO.Compression.CompressionLevel.NoCompression; | ||
case CompressionMethod.Default: | ||
case CompressionMethod.Deflate: | ||
return System.IO.Compression.CompressionLevel.Optimal; | ||
default: | ||
throw new ArgumentOutOfRangeException (nameof (method), method, null); | ||
} | ||
} | ||
|
||
public static CompressionMethod ToCompressionMethod (this System.IO.Compression.CompressionLevel level) | ||
{ | ||
switch (level) { | ||
case System.IO.Compression.CompressionLevel.NoCompression: | ||
return CompressionMethod.Store; | ||
case System.IO.Compression.CompressionLevel.Optimal: | ||
return CompressionMethod.Deflate; | ||
default: | ||
throw new ArgumentOutOfRangeException (nameof (level), level, null); | ||
} | ||
} | ||
|
||
public static FileMode ToFileMode (this ZipArchiveMode mode) | ||
{ | ||
switch (mode) { | ||
case ZipArchiveMode.Create: | ||
return FileMode.Create; | ||
case ZipArchiveMode.Update: | ||
return FileMode.Open; | ||
default: | ||
throw new ArgumentOutOfRangeException (nameof (mode), mode, null); | ||
} | ||
} | ||
} |
Oops, something went wrong.