diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/IpaInfoPanel.xaml b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/IpaInfoPanel.xaml
new file mode 100644
index 0000000..a5415b9
--- /dev/null
+++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/IpaInfoPanel.xaml
@@ -0,0 +1,261 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/IpaInfoPanel.xaml.cs b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/IpaInfoPanel.xaml.cs
new file mode 100644
index 0000000..067910f
--- /dev/null
+++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/IpaInfoPanel.xaml.cs
@@ -0,0 +1,98 @@
+// 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 QuickLook.Common.ExtensionMethods;
+using QuickLook.Common.Helpers;
+using QuickLook.Common.Plugin;
+using QuickLook.Plugin.AppViewer.ApkPackageParser;
+using QuickLook.Plugin.AppViewer.IpaPackageParser;
+using System.Globalization;
+using System.IO;
+using System.Reflection;
+using System.Threading.Tasks;
+using System.Windows.Controls;
+using System.Windows.Media.Imaging;
+
+namespace QuickLook.Plugin.AppViewer;
+
+public partial class IpaInfoPanel : UserControl, IAppInfoPanel
+{
+ private ContextObject _context;
+
+ public IpaInfoPanel(ContextObject context)
+ {
+ _context = context;
+
+ DataContext = this;
+ InitializeComponent();
+
+ string translationFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Translations.config");
+ applicationNameTitle.Text = TranslationHelper.Get("APP_NAME", translationFile);
+ versionNameTitle.Text = TranslationHelper.Get("APP_VERSION_NAME", translationFile);
+ versionCodeTitle.Text = TranslationHelper.Get("APP_VERSION_CODE", translationFile);
+ packageNameTitle.Text = TranslationHelper.Get("PACKAGE_NAME", translationFile);
+ minimumOSVersionTitle.Text = TranslationHelper.Get("APP_MIN_OS_VERSION", translationFile);
+ platformVersionTitle.Text = TranslationHelper.Get("APP_TARGET_OS_VERSION", translationFile);
+ totalSizeTitle.Text = TranslationHelper.Get("TOTAL_SIZE", translationFile);
+ modDateTitle.Text = TranslationHelper.Get("LAST_MODIFIED", translationFile);
+ permissionsGroupBox.Header = TranslationHelper.Get("PERMISSIONS", translationFile);
+ }
+
+ public void DisplayInfo(string path)
+ {
+ var name = Path.GetFileName(path);
+ filename.Text = string.IsNullOrEmpty(name) ? path : name;
+
+ _ = Task.Run(() =>
+ {
+ if (File.Exists(path))
+ {
+ var size = new FileInfo(path).Length;
+ IpaInfo ipaInfo = IpaParser.Parse(path);
+ var last = File.GetLastWriteTime(path);
+
+ Dispatcher.Invoke(() =>
+ {
+ applicationName.Text = ipaInfo.DisplayName;
+ versionName.Text = ipaInfo.VersionName;
+ versionCode.Text = ipaInfo.VersionCode;
+ packageName.Text = ipaInfo.Identifier;
+ deviceFamily.Text = ipaInfo.DeviceFamily;
+ minimumOSVersion.Text = ipaInfo.MinimumOSVersion;
+ platformVersion.Text = ipaInfo.PlatformVersion;
+ totalSize.Text = size.ToPrettySize(2);
+ modDate.Text = last.ToString(CultureInfo.CurrentCulture);
+ permissions.ItemsSource = ipaInfo.Permissions;
+
+ if (ipaInfo.Logo != null)
+ {
+ using var stream = new MemoryStream(ipaInfo.Logo);
+ var icon = new BitmapImage();
+ icon.BeginInit();
+ icon.CacheOption = BitmapCacheOption.OnLoad;
+ icon.StreamSource = stream;
+ icon.EndInit();
+ icon.Freeze();
+ image.Source = icon;
+ }
+
+ _context.IsBusy = false;
+ });
+ }
+ });
+ }
+}
diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/IpaPackageParser/IpaInfo.cs b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/IpaPackageParser/IpaInfo.cs
new file mode 100644
index 0000000..2b8be51
--- /dev/null
+++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/IpaPackageParser/IpaInfo.cs
@@ -0,0 +1,43 @@
+// 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.Linq;
+
+namespace QuickLook.Plugin.AppViewer.IpaPackageParser;
+
+public class IpaInfo
+{
+ public string DisplayName { get; set; }
+
+ public string VersionName { get; set; }
+
+ public string VersionCode { get; set; }
+
+ public string Identifier { get; set; }
+
+ public string MinimumOSVersion { get; set; }
+
+ public string PlatformVersion { get; set; }
+
+ public string DeviceFamily { get; set; }
+
+ public string[] Permissions { get; set; } = [];
+
+ public byte[] Logo { get; set; }
+
+ public bool HasIcon => Logo?.Any() ?? false;
+}
diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/IpaPackageParser/IpaParser.cs b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/IpaPackageParser/IpaParser.cs
new file mode 100644
index 0000000..3f52c3e
--- /dev/null
+++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/IpaPackageParser/IpaParser.cs
@@ -0,0 +1,41 @@
+// 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.Linq;
+
+namespace QuickLook.Plugin.AppViewer.IpaPackageParser;
+
+public static class IpaParser
+{
+ public static IpaInfo Parse(string path)
+ {
+ IpaReader reader = new(path);
+
+ return new IpaInfo()
+ {
+ DisplayName = reader.DisplayName,
+ VersionName = reader.ShortVersionString,
+ VersionCode = reader.Version,
+ Identifier = reader.Identifier,
+ DeviceFamily = reader.DeviceFamily,
+ MinimumOSVersion = reader.MinimumOSVersion,
+ PlatformVersion = reader.PlatformVersion,
+ Permissions = [.. reader.InfoPlistDict.Keys.Where(key => key.StartsWith("NS") && key.EndsWith("UsageDescription"))],
+ Logo = reader.Icon,
+ };
+ }
+}
diff --git a/QuickLook.Plugin/QuickLook.Plugin.AppViewer/IpaPackageParser/IpaReader.cs b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/IpaPackageParser/IpaReader.cs
new file mode 100644
index 0000000..8cfe598
--- /dev/null
+++ b/QuickLook.Plugin/QuickLook.Plugin.AppViewer/IpaPackageParser/IpaReader.cs
@@ -0,0 +1,187 @@
+// 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.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+namespace QuickLook.Plugin.AppViewer.IpaPackageParser;
+
+public class IpaReader
+{
+ private ZipFile zip;
+ private string appRoot;
+
+ public Dictionary InfoPlistDict { get; set; }
+
+ public Dictionary ItunesMetadataDic { get; set; }
+
+ public string DisplayName { get; set; }
+
+ public string ShortVersionString { get; set; }
+
+ public string Version { get; set; }
+
+ public string Identifier { get; set; }
+
+ public byte[] Icon { get; set; }
+
+ public string IconName { get; set; }
+
+ public string DeviceFamily { get; set; }
+
+ public string MinimumOSVersion { get; set; }
+
+ public string PlatformVersion { get; set; }
+
+ public IpaReader(string path)
+ {
+ Open(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read));
+ }
+
+ public IpaReader(Stream stream)
+ {
+ Open(stream);
+ }
+
+ protected void Dispose()
+ {
+ zip?.Close();
+ zip = null;
+ }
+
+ private void Open(Stream stream)
+ {
+ zip = new ZipFile(stream);
+ byte[] infoPlistData = null;
+
+ // Info.plist
+ {
+ foreach (ZipEntry entry in zip)
+ {
+ Match m = Regex.Match(entry.Name, @"(Payload/.*\.app/)Info\.plist");
+
+ if (m.Success)
+ {
+ appRoot = m.Groups[1].Value;
+ ZipEntry infoPlist = zip.GetEntry(appRoot);
+ using var s = new BinaryReader(zip.GetInputStream(entry));
+ infoPlistData = s.ReadBytes((int)entry.Size);
+ break;
+ }
+ }
+ if (Plist.ReadPlist(infoPlistData) is Dictionary dict)
+ {
+ InfoPlistDict = dict;
+ }
+ }
+ {
+ if (InfoPlistDict.TryGetValue("CFBundleDisplayName", out object value) && value is string stringValue)
+ {
+ DisplayName = stringValue;
+ }
+ }
+ {
+ if (InfoPlistDict.TryGetValue("CFBundleShortVersionString", out object value) && value is string stringValue)
+ {
+ ShortVersionString = stringValue;
+ }
+ }
+ {
+ if (InfoPlistDict.TryGetValue("CFBundleVersion", out object value) && value is string stringValue)
+ {
+ Version = stringValue;
+ }
+ }
+ {
+ if (InfoPlistDict.TryGetValue("CFBundleIdentifier", out object value) && value is string stringValue)
+ {
+ Identifier = stringValue;
+ }
+ }
+ {
+ if (InfoPlistDict.TryGetValue("MinimumOSVersion", out object value) && value is string stringValue)
+ {
+ MinimumOSVersion = $"iOS {stringValue}";
+ }
+ }
+ {
+ if (InfoPlistDict.TryGetValue("DTPlatformVersion", out object value) && value is string stringValue)
+ {
+ PlatformVersion = $"iOS {stringValue}";
+ }
+ }
+ {
+ if (InfoPlistDict.TryGetValue("UIDeviceFamily", out object familyNode) && familyNode is IEnumerable