From 12046220c1252afb0ff63a1bc37795402df11383 Mon Sep 17 00:00:00 2001 From: ema Date: Fri, 27 Jun 2025 07:29:38 +0800 Subject: [PATCH] Add support for Android App Bundle (.aab) files --- .../InfoPanels/ApkInfoPanel.xaml.cs | 50 ++++++++----- .../PackageParsers/Apk/AabInfo.cs | 20 ++++++ .../PackageParsers/Apk/AabParser.cs | 72 +++++++++++++++++++ .../PackageParsers/Apk/ApkInfo.cs | 2 +- .../PackageParsers/Apk/IApkInfo.cs | 55 ++++++++++++++ .../QuickLook.Plugin.AppViewer/Plugin.cs | 8 +-- 6 files changed, 184 insertions(+), 23 deletions(-) create mode 100644 QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Apk/AabInfo.cs create mode 100644 QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Apk/AabParser.cs create mode 100644 QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Apk/IApkInfo.cs diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/InfoPanels/ApkInfoPanel.xaml.cs b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/InfoPanels/ApkInfoPanel.xaml.cs index 484e5bd..46b4dc5 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/InfoPanels/ApkInfoPanel.xaml.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/InfoPanels/ApkInfoPanel.xaml.cs @@ -20,6 +20,7 @@ using QuickLook.Common.Helpers; using QuickLook.Common.Plugin; using QuickLook.Plugin.AppViewer.PackageParsers.Apk; using System; +using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; @@ -63,32 +64,45 @@ public partial class ApkInfoPanel : UserControl, IAppInfoPanel if (File.Exists(path)) { var size = new FileInfo(path).Length; - ApkInfo apkInfo = ApkParser.Parse(path); + IApkInfo info = Path.GetExtension(path).ToLower() switch + { + ".apk" => ApkParser.Parse(path), + ".aab" => AabParser.Parse(path), + _ => throw new NotSupportedException("Extension is not supported."), + }; var last = File.GetLastWriteTime(path); Dispatcher.Invoke(() => { - applicationName.Text = apkInfo.Label; - versionName.Text = apkInfo.VersionName; - versionCode.Text = apkInfo.VersionCode; - abis.Text = string.Join(", ", apkInfo.ABIs ?? []); - packageName.Text = apkInfo.PackageName; - minSdkVersion.Text = apkInfo.MinSdkVersion; - targetSdkVersion.Text = apkInfo.TargetSdkVersion; + applicationName.Text = info.Label; + versionName.Text = info.VersionName; + versionCode.Text = info.VersionCode; + abis.Text = string.Join(", ", info.ABIs ?? []); + packageName.Text = info.PackageName; + minSdkVersion.Text = info.MinSdkVersion; + targetSdkVersion.Text = info.TargetSdkVersion; totalSize.Text = size.ToPrettySize(2); modDate.Text = last.ToString(CultureInfo.CurrentCulture); - permissions.ItemsSource = apkInfo.Permissions; + permissions.ItemsSource = info.Permissions; - if (apkInfo.HasIcon) + if (info.HasIcon) { - using var stream = new MemoryStream(apkInfo.Logo); - var icon = new BitmapImage(); - icon.BeginInit(); - icon.CacheOption = BitmapCacheOption.OnLoad; - icon.StreamSource = stream; - icon.EndInit(); - icon.Freeze(); - image.Source = icon; + try + { + using var stream = new MemoryStream(info.Logo); + var icon = new BitmapImage(); + icon.BeginInit(); + icon.CacheOption = BitmapCacheOption.OnLoad; + icon.StreamSource = stream; + icon.EndInit(); + icon.Freeze(); + image.Source = icon; + } + catch (Exception e) + { + Debug.WriteLine(e); + image.Source = new BitmapImage(new Uri("pack://application:,,,/QuickLook.Plugin.AppViewer;component/Resources/android.png")); + } } else { diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Apk/AabInfo.cs b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Apk/AabInfo.cs new file mode 100644 index 0000000..64ca1e6 --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Apk/AabInfo.cs @@ -0,0 +1,20 @@ +// Copyright © 2017-2025 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +namespace QuickLook.Plugin.AppViewer.PackageParsers.Apk; + +public class AabInfo : ApkInfo; diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Apk/AabParser.cs b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Apk/AabParser.cs new file mode 100644 index 0000000..abb5e93 --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Apk/AabParser.cs @@ -0,0 +1,72 @@ +// Copyright © 2017-2025 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using ICSharpCode.SharpZipLib.Zip; +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; + +namespace QuickLook.Plugin.AppViewer.PackageParsers.Apk; + +public static class AabParser +{ + public static AabInfo Parse(string path) + { + try + { + using var zip = new ZipFile(path); + + var aabReader = new ApkReader.AabReader(); + ApkReader.AabInfo baseInfo = aabReader.Read(path); + AabInfo info = new() + { + VersionName = baseInfo.VersionName, + VersionCode = baseInfo.VersionCode, + TargetSdkVersion = ApiLevel.Create(baseInfo.TargetSdkVersion).ToString(), + Permissions = baseInfo.Permissions, + PackageName = baseInfo.PackageName, + MinSdkVersion = ApiLevel.Create(baseInfo.MinSdkVersion).ToString(), + Icon = baseInfo.Icon, + Icons = baseInfo.Icons, + Label = baseInfo.Label, + Labels = baseInfo.Labels, + Locales = baseInfo.Locales, + Densities = baseInfo.Densities, + ABIs = [.. baseInfo.Abis], + LaunchableActivity = baseInfo.LaunchableActivity, + }; + + if (baseInfo.HasIcon) + { + ZipEntry entry = zip.GetEntry(baseInfo.Icons.Values + .Where(icon => icon.EndsWith(".png", StringComparison.OrdinalIgnoreCase)) + .LastOrDefault()); + using var s = new BinaryReader(zip.GetInputStream(entry)); + info.Logo = s.ReadBytes((int)entry.Size); + } + + return info; + } + catch (Exception e) + { + Debug.WriteLine(e); + } + + return new AabInfo(); + } +} diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Apk/ApkInfo.cs b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Apk/ApkInfo.cs index 807437f..c1afc50 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Apk/ApkInfo.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Apk/ApkInfo.cs @@ -19,7 +19,7 @@ using System.Collections.Generic; namespace QuickLook.Plugin.AppViewer.PackageParsers.Apk; -public class ApkInfo +public class ApkInfo : IApkInfo { public string VersionName { get; set; } diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Apk/IApkInfo.cs b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Apk/IApkInfo.cs new file mode 100644 index 0000000..c20de2f --- /dev/null +++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/PackageParsers/Apk/IApkInfo.cs @@ -0,0 +1,55 @@ +// Copyright © 2017-2025 QL-Win Contributors +// +// This file is part of QuickLook program. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +using System.Collections.Generic; + +namespace QuickLook.Plugin.AppViewer.PackageParsers.Apk; + +public interface IApkInfo +{ + public string VersionName { get; set; } + + public string VersionCode { get; set; } + + public string TargetSdkVersion { get; set; } + + public List Permissions { get; set; } + + public string PackageName { get; set; } + + public string MinSdkVersion { get; set; } + + public string Icon { get; set; } + + public Dictionary Icons { get; set; } + + public byte[] Logo { get; set; } + + public string Label { get; set; } + + public Dictionary Labels { get; set; } + + public bool HasIcon { get; } + + public List Locales { get; set; } + + public List Densities { get; set; } + + public string LaunchableActivity { get; set; } + + public string[] ABIs { get; set; } +} diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Plugin.cs b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Plugin.cs index b3eb1ba..ff16758 100644 --- a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Plugin.cs +++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/Plugin.cs @@ -30,8 +30,8 @@ public class Plugin : IViewer [ // Android ".apk", ".apk.1", // Android Package + ".aab", // Android App Bundle //".aar", // Android Archive - //".aab", // Android App Bundle // Windows ".appx", ".appxbundle", // Windows APPX installer @@ -51,7 +51,7 @@ public class Plugin : IViewer // Ubuntu ".deb", // Debian Package ".appimage", // AppImage Format - ".rpm", // Red Hat Package Manager + ".rpm", // Red Hat Package Manager // Others ".wgt", ".wgtu", // UniApp Widget @@ -75,7 +75,7 @@ public class Plugin : IViewer { context.PreferredSize = Path.GetExtension(ConfirmPath(path)).ToLower() switch { - ".apk" => new Size { Width = 600, Height = 510 }, + ".apk" or ".aab" => new Size { Width = 600, Height = 510 }, ".ipa" => new Size { Width = 560, Height = 510 }, ".hap" => new Size { Width = 560, Height = 500 }, ".msi" => new Size { Width = 560, Height = 230 }, @@ -99,7 +99,7 @@ public class Plugin : IViewer _path = path; _ip = Path.GetExtension(ConfirmPath(path)).ToLower() switch { - ".apk" => new ApkInfoPanel(context), + ".apk" or ".aab" => new ApkInfoPanel(context), ".ipa" => new IpaInfoPanel(context), ".hap" => new HapInfoPanel(context), ".msi" => new MsiInfoPanel(context),