chore (iOS): Adhere to iOS development guidelines

This commit is contained in:
Darkatse 2026-03-18 11:58:09 -04:00
parent fffc1624eb
commit 72bf7a7363
24 changed files with 134 additions and 8 deletions

View file

@ -0,0 +1,105 @@
#!/usr/bin/env swift
import CoreGraphics
import Foundation
import ImageIO
import UniformTypeIdentifiers
struct HexColor {
let red: CGFloat
let green: CGFloat
let blue: CGFloat
init(_ hex: String) {
let sanitized = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
guard sanitized.count == 6, let value = UInt64(sanitized, radix: 16) else {
fatalError("Invalid hex color: \(hex)")
}
red = CGFloat((value >> 16) & 0xFF) / 255.0
green = CGFloat((value >> 8) & 0xFF) / 255.0
blue = CGFloat(value & 0xFF) / 255.0
}
}
func flattenPNG(at url: URL, background: HexColor) throws {
guard let source = CGImageSourceCreateWithURL(url as CFURL, nil),
let image = CGImageSourceCreateImageAtIndex(source, 0, nil) else {
throw NSError(domain: "ios-opaque-app-icons", code: 1, userInfo: [
NSLocalizedDescriptionKey: "Failed to load image at \(url.path)"
])
}
switch image.alphaInfo {
case .alphaOnly, .first, .last, .premultipliedFirst, .premultipliedLast:
break
default:
return
}
let bitmapInfo = CGImageAlphaInfo.noneSkipLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue
guard let context = CGContext(
data: nil,
width: image.width,
height: image.height,
bitsPerComponent: 8,
bytesPerRow: 0,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: bitmapInfo
) else {
throw NSError(domain: "ios-opaque-app-icons", code: 2, userInfo: [
NSLocalizedDescriptionKey: "Failed to create drawing context for \(url.path)"
])
}
context.setFillColor(CGColor(red: background.red, green: background.green, blue: background.blue, alpha: 1))
context.fill(CGRect(x: 0, y: 0, width: image.width, height: image.height))
context.draw(image, in: CGRect(x: 0, y: 0, width: image.width, height: image.height))
guard let flattened = context.makeImage() else {
throw NSError(domain: "ios-opaque-app-icons", code: 3, userInfo: [
NSLocalizedDescriptionKey: "Failed to finalize image for \(url.path)"
])
}
let tempURL = url.deletingLastPathComponent().appendingPathComponent(".\(url.lastPathComponent).tmp")
guard let destination = CGImageDestinationCreateWithURL(tempURL as CFURL, UTType.png.identifier as CFString, 1, nil) else {
throw NSError(domain: "ios-opaque-app-icons", code: 4, userInfo: [
NSLocalizedDescriptionKey: "Failed to create output file for \(url.path)"
])
}
CGImageDestinationAddImage(destination, flattened, nil)
guard CGImageDestinationFinalize(destination) else {
throw NSError(domain: "ios-opaque-app-icons", code: 5, userInfo: [
NSLocalizedDescriptionKey: "Failed to write PNG data for \(url.path)"
])
}
_ = try FileManager.default.replaceItemAt(url, withItemAt: tempURL)
}
let arguments = CommandLine.arguments.dropFirst()
guard let appIconSetArgument = arguments.first else {
fputs("usage: ios-opaque-app-icons.swift <AppIcon.appiconset> [background_hex]\n", stderr)
exit(64)
}
let background = HexColor(arguments.dropFirst().first ?? "FFF3D6")
let appIconSetURL = URL(fileURLWithPath: appIconSetArgument, isDirectory: true)
let fileManager = FileManager.default
guard fileManager.fileExists(atPath: appIconSetURL.path) else {
exit(0)
}
let pngURLs = try fileManager.contentsOfDirectory(
at: appIconSetURL,
includingPropertiesForKeys: nil,
options: [.skipsHiddenFiles]
)
.filter { $0.pathExtension.lowercased() == "png" }
for pngURL in pngURLs {
try flattenPNG(at: pngURL, background: background)
}

View file

@ -55,6 +55,16 @@ run_tauri_ios_xcode_script() {
${ARCHS:?}
}
normalize_ios_app_icons() {
local app_icon_set="$REPO_ROOT/src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset"
xcrun --sdk macosx swift "$SCRIPT_DIR/ios-opaque-app-icons.swift" "$app_icon_set"
}
build_tauri_ios_target() {
run_tauri_ios_xcode_script "$@"
normalize_ios_app_icons
}
if ! ensure_node_on_path; then
echo "error: node was not found in Xcode's PATH." >&2
echo "error: install Node in a stable location, or configure fnm/volta so GUI apps can resolve it." >&2
@ -63,12 +73,12 @@ if ! ensure_node_on_path; then
fi
if command -v pnpm >/dev/null 2>&1; then
run_tauri_ios_xcode_script pnpm
build_tauri_ios_target pnpm
exit 0
fi
if command -v corepack >/dev/null 2>&1; then
run_tauri_ios_xcode_script corepack pnpm
build_tauri_ios_target corepack pnpm
exit 0
fi

10
src-tauri/Info.ios.plist Normal file
View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>NSCameraUsageDescription</key>
<string>TauriTavern uses the camera only to scan LAN Sync pairing QR codes between your devices.</string>
</dict>
</plist>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 758 B

After

Width:  |  Height:  |  Size: 790 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 300 KiB

After

Width:  |  Height:  |  Size: 343 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Before After
Before After

View file

@ -30,7 +30,6 @@ targets:
sources:
- path: Sources
- path: Assets.xcassets
- path: Externals
- path: tauritavern_iOS
- path: assets
buildPhase: resources

View file

@ -18,7 +18,6 @@
AA3812A8AB49B932DA7D1FE2 /* libapp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C11991D4BBA9ED50B2CBD16A /* libapp.a */; };
BE9048F0BE508CFBCBAAE845 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 87CD80661131CB327DEBC646 /* LaunchScreen.storyboard */; };
CD0EE93A72D73C678ED1D675 /* assets in Resources */ = {isa = PBXBuildFile; fileRef = 581C420CD09C276B28F81159 /* assets */; };
EA65CA1E6500175D7775DBA9 /* libapp.a in Resources */ = {isa = PBXBuildFile; fileRef = 3DF579298F528439D611A8DE /* libapp.a */; };
F64A8E669FCED0F94A1592A1 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = E494B2830348E4D8EB0AEEAD /* main.mm */; };
/* End PBXBuildFile section */
@ -847,7 +846,6 @@
88452944535A8DB9D80683ED /* Assets.xcassets in Resources */,
BE9048F0BE508CFBCBAAE845 /* LaunchScreen.storyboard in Resources */,
CD0EE93A72D73C678ED1D675 /* assets in Resources */,
EA65CA1E6500175D7775DBA9 /* libapp.a in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View file

@ -15,9 +15,13 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.5.1</string>
<string>1.5.2</string>
<key>CFBundleVersion</key>
<string>1.5.1</string>
<string>1.5.2</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>NSCameraUsageDescription</key>
<string>TauriTavern uses the camera only to scan LAN Sync pairing QR codes between your devices.</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
@ -41,4 +45,4 @@
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
</plist>