fix (ios): Add dark and tinted app icon variants
|
|
@ -178,3 +178,50 @@ iOS 上“文件选择 / 文件导出”必须交给系统级能力完成:
|
|||
iOS 外测/内测分发裁剪与能力分级已落地为 iOS-only 的 `ios_policy` 运行时系统(可被导入 `tauritavern-settings.json` 覆盖 profile/能力边界,且 iOS 上 fail-fast、桌面端忽略)。
|
||||
|
||||
- 当前实现快照:`docs/CurrentState/iOSPolicy.md`
|
||||
|
||||
## 6. iOS 18+ App Icon 外观变体
|
||||
|
||||
### 6.1 现象
|
||||
|
||||
iOS 深色图标模式下,App 放入文件夹后可能出现“文件夹外仍是普通图标,打开文件夹后变成深色图标”的不一致表现。
|
||||
|
||||
### 6.2 根因
|
||||
|
||||
iOS 18+ 支持 Home Screen 图标的 `Any` / `Dark` / `Tinted` 外观。若 AppIcon 只提供传统多尺寸 `Any` 图标,系统会自动生成深色/着色效果;文件夹缩略图和展开文件夹可能走不同缓存或渲染路径,从而出现外观不一致。
|
||||
|
||||
### 6.3 当前方案
|
||||
|
||||
`AppIcon.appiconset` 改为 Xcode single-size 1024px 源图,并显式提供:
|
||||
|
||||
- `AppIcon-Light.png`:基础 `Any` 图标,不透明背景。
|
||||
- `AppIcon-Dark.png`:深色图标,透明背景,交给系统深色底承载。
|
||||
- `AppIcon-Tinted.png`:着色图标,透明背景,灰度前景。
|
||||
|
||||
维护入口:
|
||||
|
||||
- 生成脚本:`scripts/generate-ios-app-icon-variants.swift`
|
||||
- 构建期校验/展平:`scripts/ios-opaque-app-icons.swift`
|
||||
- 资产目录:`src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset`
|
||||
|
||||
重新生成:
|
||||
|
||||
```sh
|
||||
xcrun --sdk macosx swift scripts/generate-ios-app-icon-variants.swift \
|
||||
src-tauri/icons/icon.png \
|
||||
src-tauri/gen/apple/Assets.xcassets/AppIcon.appiconset
|
||||
```
|
||||
|
||||
回归验证:
|
||||
|
||||
```sh
|
||||
xcrun actool --compile /tmp/tt-appicon \
|
||||
--platform iphonesimulator \
|
||||
--minimum-deployment-target 16.0 \
|
||||
--app-icon AppIcon \
|
||||
--output-partial-info-plist /tmp/tt-appicon/partial.plist \
|
||||
src-tauri/gen/apple/Assets.xcassets
|
||||
|
||||
xcrun assetutil --info /tmp/tt-appicon/Assets.car
|
||||
```
|
||||
|
||||
输出应包含 `UIAppearanceDark` 与 `ISAppearanceTintable`。若未来重新运行 `tauri icon`,必须重新生成并保留这三个 appearance 变体。
|
||||
|
|
|
|||
|
|
@ -51,10 +51,12 @@ powershell -ExecutionPolicy Bypass -File .\scripts\export-sillytavern-migration.
|
|||
校验前端宿主层文件规模和依赖边界,避免 Host Kernel 持续膨胀。对应 `pnpm run check:frontend`。
|
||||
- `tauri-ios-xcode-script.sh`
|
||||
包装 `tauri ios xcode-script`,补齐 Xcode GUI 构建环境中的 PATH / Node / pnpm,并在构建后处理 iOS 图标。
|
||||
- `generate-ios-app-icon-variants.swift`
|
||||
从 `src-tauri/icons/icon.png` 生成 iOS `Any` / `Dark` / `Tinted` 三个 1024px App Icon 源图。
|
||||
- `ios-policy.mjs`
|
||||
iOS Dev/Build 包装脚本:为构建过程注入 `TAURITAVERN_IOS_POLICY_PROFILE`,并在 `ios_internal_full` / `ios_external_beta` 构建时自动使用 `--export-method app-store-connect`。
|
||||
- `ios-opaque-app-icons.swift`
|
||||
将 iOS App Icon PNG 展平为不透明背景,供 `tauri-ios-xcode-script.sh` 调用。
|
||||
校验 iOS App Icon appearance 变体,并只将基础 `Any` 图标展平为不透明背景,供 `tauri-ios-xcode-script.sh` 调用。
|
||||
- `ci/setup-macos-signing.sh`
|
||||
GitHub Actions / CI 中的 macOS 签名初始化脚本,用于导入证书、创建 keychain 与写入 Apple API Key 路径。
|
||||
- `guardrails/frontend-lines-baseline.json`
|
||||
|
|
|
|||
189
scripts/generate-ios-app-icon-variants.swift
Executable file
|
|
@ -0,0 +1,189 @@
|
|||
#!/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 loadImage(at url: URL) throws -> CGImage {
|
||||
guard let source = CGImageSourceCreateWithURL(url as CFURL, nil),
|
||||
let image = CGImageSourceCreateImageAtIndex(source, 0, nil) else {
|
||||
throw NSError(domain: "generate-ios-app-icon-variants", code: 1, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Failed to load source icon at \(url.path)"
|
||||
])
|
||||
}
|
||||
|
||||
return image
|
||||
}
|
||||
|
||||
func writePNG(_ image: CGImage, to url: URL) throws {
|
||||
guard let destination = CGImageDestinationCreateWithURL(url as CFURL, UTType.png.identifier as CFString, 1, nil) else {
|
||||
throw NSError(domain: "generate-ios-app-icon-variants", code: 2, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Failed to create output file at \(url.path)"
|
||||
])
|
||||
}
|
||||
|
||||
CGImageDestinationAddImage(destination, image, nil)
|
||||
guard CGImageDestinationFinalize(destination) else {
|
||||
throw NSError(domain: "generate-ios-app-icon-variants", code: 3, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Failed to write PNG at \(url.path)"
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
func aspectFitRect(sourceWidth: Int, sourceHeight: Int, targetSize: Int) -> CGRect {
|
||||
let target = CGFloat(targetSize)
|
||||
let sourceAspect = CGFloat(sourceWidth) / CGFloat(sourceHeight)
|
||||
let targetAspect: CGFloat = 1
|
||||
|
||||
if sourceAspect > targetAspect {
|
||||
let height = target / sourceAspect
|
||||
return CGRect(x: 0, y: (target - height) / 2, width: target, height: height)
|
||||
}
|
||||
|
||||
let width = target * sourceAspect
|
||||
return CGRect(x: (target - width) / 2, y: 0, width: width, height: target)
|
||||
}
|
||||
|
||||
func renderIcon(source: CGImage, size: Int, background: HexColor?) throws -> CGImage {
|
||||
let bitmapInfo: UInt32
|
||||
if background == nil {
|
||||
bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue
|
||||
} else {
|
||||
bitmapInfo = CGImageAlphaInfo.noneSkipLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue
|
||||
}
|
||||
|
||||
guard let context = CGContext(
|
||||
data: nil,
|
||||
width: size,
|
||||
height: size,
|
||||
bitsPerComponent: 8,
|
||||
bytesPerRow: size * 4,
|
||||
space: CGColorSpaceCreateDeviceRGB(),
|
||||
bitmapInfo: bitmapInfo
|
||||
) else {
|
||||
throw NSError(domain: "generate-ios-app-icon-variants", code: 4, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Failed to create drawing context"
|
||||
])
|
||||
}
|
||||
|
||||
let bounds = CGRect(x: 0, y: 0, width: size, height: size)
|
||||
if let background {
|
||||
context.setFillColor(CGColor(red: background.red, green: background.green, blue: background.blue, alpha: 1))
|
||||
context.fill(bounds)
|
||||
} else {
|
||||
context.clear(bounds)
|
||||
}
|
||||
|
||||
context.interpolationQuality = .high
|
||||
context.draw(source, in: aspectFitRect(sourceWidth: source.width, sourceHeight: source.height, targetSize: size))
|
||||
|
||||
guard let rendered = context.makeImage() else {
|
||||
throw NSError(domain: "generate-ios-app-icon-variants", code: 5, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Failed to finalize icon image"
|
||||
])
|
||||
}
|
||||
|
||||
return rendered
|
||||
}
|
||||
|
||||
func renderTintedIcon(source: CGImage, size: Int) throws -> CGImage {
|
||||
let bytesPerPixel = 4
|
||||
let bytesPerRow = size * bytesPerPixel
|
||||
let byteCount = bytesPerRow * size
|
||||
guard let data = calloc(byteCount, MemoryLayout<UInt8>.size) else {
|
||||
throw NSError(domain: "generate-ios-app-icon-variants", code: 6, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Failed to allocate image buffer"
|
||||
])
|
||||
}
|
||||
defer { free(data) }
|
||||
|
||||
let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue
|
||||
guard let context = CGContext(
|
||||
data: data,
|
||||
width: size,
|
||||
height: size,
|
||||
bitsPerComponent: 8,
|
||||
bytesPerRow: bytesPerRow,
|
||||
space: CGColorSpaceCreateDeviceRGB(),
|
||||
bitmapInfo: bitmapInfo
|
||||
) else {
|
||||
throw NSError(domain: "generate-ios-app-icon-variants", code: 7, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Failed to create tinted drawing context"
|
||||
])
|
||||
}
|
||||
|
||||
context.clear(CGRect(x: 0, y: 0, width: size, height: size))
|
||||
context.interpolationQuality = .high
|
||||
context.draw(source, in: aspectFitRect(sourceWidth: source.width, sourceHeight: source.height, targetSize: size))
|
||||
|
||||
let pixels = data.assumingMemoryBound(to: UInt8.self)
|
||||
for offset in stride(from: 0, to: byteCount, by: bytesPerPixel) {
|
||||
let alpha = Double(pixels[offset + 3]) / 255.0
|
||||
guard alpha > 0 else {
|
||||
continue
|
||||
}
|
||||
|
||||
let red = min(255.0, Double(pixels[offset]) / alpha)
|
||||
let green = min(255.0, Double(pixels[offset + 1]) / alpha)
|
||||
let blue = min(255.0, Double(pixels[offset + 2]) / alpha)
|
||||
let luma = (0.299 * red) + (0.587 * green) + (0.114 * blue)
|
||||
let premultipliedLuma = UInt8(max(0, min(255, Int((luma * alpha).rounded()))))
|
||||
|
||||
pixels[offset] = premultipliedLuma
|
||||
pixels[offset + 1] = premultipliedLuma
|
||||
pixels[offset + 2] = premultipliedLuma
|
||||
}
|
||||
|
||||
guard let rendered = context.makeImage() else {
|
||||
throw NSError(domain: "generate-ios-app-icon-variants", code: 8, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Failed to finalize tinted icon image"
|
||||
])
|
||||
}
|
||||
|
||||
return rendered
|
||||
}
|
||||
|
||||
let arguments = CommandLine.arguments.dropFirst()
|
||||
guard arguments.count >= 2 else {
|
||||
fputs("usage: generate-ios-app-icon-variants.swift <source_icon> <AppIcon.appiconset> [light_background_hex]\n", stderr)
|
||||
exit(64)
|
||||
}
|
||||
|
||||
let sourceURL = URL(fileURLWithPath: arguments[arguments.startIndex])
|
||||
let appIconSetURL = URL(fileURLWithPath: arguments[arguments.index(after: arguments.startIndex)], isDirectory: true)
|
||||
let lightBackground = HexColor(arguments.dropFirst(2).first ?? "FFFAF2")
|
||||
let iconSize = 1024
|
||||
let source = try loadImage(at: sourceURL)
|
||||
|
||||
try FileManager.default.createDirectory(at: appIconSetURL, withIntermediateDirectories: true)
|
||||
|
||||
try writePNG(
|
||||
try renderIcon(source: source, size: iconSize, background: lightBackground),
|
||||
to: appIconSetURL.appendingPathComponent("AppIcon-Light.png")
|
||||
)
|
||||
try writePNG(
|
||||
try renderIcon(source: source, size: iconSize, background: nil),
|
||||
to: appIconSetURL.appendingPathComponent("AppIcon-Dark.png")
|
||||
)
|
||||
try writePNG(
|
||||
try renderTintedIcon(source: source, size: iconSize),
|
||||
to: appIconSetURL.appendingPathComponent("AppIcon-Tinted.png")
|
||||
)
|
||||
|
|
@ -5,6 +5,20 @@ import Foundation
|
|||
import ImageIO
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
struct AppIconSet: Decodable {
|
||||
let images: [AppIconImage]
|
||||
}
|
||||
|
||||
struct AppIconImage: Decodable {
|
||||
let filename: String?
|
||||
let appearances: [AppIconAppearance]?
|
||||
}
|
||||
|
||||
struct AppIconAppearance: Decodable {
|
||||
let appearance: String
|
||||
let value: String
|
||||
}
|
||||
|
||||
struct HexColor {
|
||||
let red: CGFloat
|
||||
let green: CGFloat
|
||||
|
|
@ -22,6 +36,62 @@ struct HexColor {
|
|||
}
|
||||
}
|
||||
|
||||
func loadAppIconSet(at url: URL) throws -> AppIconSet {
|
||||
let contentsURL = url.appendingPathComponent("Contents.json")
|
||||
let data = try Data(contentsOf: contentsURL)
|
||||
return try JSONDecoder().decode(AppIconSet.self, from: data)
|
||||
}
|
||||
|
||||
func luminosityValues(for image: AppIconImage) -> Set<String> {
|
||||
Set((image.appearances ?? [])
|
||||
.filter { $0.appearance == "luminosity" }
|
||||
.map(\.value))
|
||||
}
|
||||
|
||||
func requireIconVariantFiles(
|
||||
appIconSet: AppIconSet,
|
||||
appIconSetURL: URL,
|
||||
fileManager: FileManager
|
||||
) throws -> Set<String> {
|
||||
var primaryFilenames = Set<String>()
|
||||
var darkFilenames = Set<String>()
|
||||
var tintedFilenames = Set<String>()
|
||||
|
||||
for image in appIconSet.images {
|
||||
guard let filename = image.filename else {
|
||||
continue
|
||||
}
|
||||
|
||||
let values = luminosityValues(for: image)
|
||||
if values.isEmpty {
|
||||
primaryFilenames.insert(filename)
|
||||
}
|
||||
if values.contains("dark") {
|
||||
darkFilenames.insert(filename)
|
||||
}
|
||||
if values.contains("tinted") {
|
||||
tintedFilenames.insert(filename)
|
||||
}
|
||||
}
|
||||
|
||||
if primaryFilenames.isEmpty || darkFilenames.isEmpty || tintedFilenames.isEmpty {
|
||||
throw NSError(domain: "ios-opaque-app-icons", code: 6, userInfo: [
|
||||
NSLocalizedDescriptionKey: "AppIcon.appiconset must define Any, Dark, and Tinted icon variants"
|
||||
])
|
||||
}
|
||||
|
||||
for filename in primaryFilenames.union(darkFilenames).union(tintedFilenames) {
|
||||
let fileURL = appIconSetURL.appendingPathComponent(filename)
|
||||
guard fileManager.fileExists(atPath: fileURL.path) else {
|
||||
throw NSError(domain: "ios-opaque-app-icons", code: 7, userInfo: [
|
||||
NSLocalizedDescriptionKey: "AppIcon.appiconset references missing icon file: \(filename)"
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
return primaryFilenames
|
||||
}
|
||||
|
||||
func flattenPNG(at url: URL, background: HexColor) throws {
|
||||
guard let source = CGImageSourceCreateWithURL(url as CFURL, nil),
|
||||
let image = CGImageSourceCreateImageAtIndex(source, 0, nil) else {
|
||||
|
|
@ -85,7 +155,7 @@ guard let appIconSetArgument = arguments.first else {
|
|||
exit(64)
|
||||
}
|
||||
|
||||
let background = HexColor(arguments.dropFirst().first ?? "FFF3D6")
|
||||
let background = HexColor(arguments.dropFirst().first ?? "FFFAF2")
|
||||
let appIconSetURL = URL(fileURLWithPath: appIconSetArgument, isDirectory: true)
|
||||
let fileManager = FileManager.default
|
||||
|
||||
|
|
@ -93,12 +163,20 @@ guard fileManager.fileExists(atPath: appIconSetURL.path) else {
|
|||
exit(0)
|
||||
}
|
||||
|
||||
let appIconSet = try loadAppIconSet(at: appIconSetURL)
|
||||
let primaryIconFilenames = try requireIconVariantFiles(
|
||||
appIconSet: appIconSet,
|
||||
appIconSetURL: appIconSetURL,
|
||||
fileManager: fileManager
|
||||
)
|
||||
|
||||
let pngURLs = try fileManager.contentsOfDirectory(
|
||||
at: appIconSetURL,
|
||||
includingPropertiesForKeys: nil,
|
||||
options: [.skipsHiddenFiles]
|
||||
)
|
||||
.filter { $0.pathExtension.lowercased() == "png" }
|
||||
.filter { primaryIconFilenames.contains($0.lastPathComponent) }
|
||||
|
||||
for pngURL in pngURLs {
|
||||
try flattenPNG(at: pngURL, background: background)
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 790 B |
|
Before Width: | Height: | Size: 2 KiB |
|
Before Width: | Height: | Size: 2 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 2 KiB |
|
Before Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 343 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 313 KiB |
|
After Width: | Height: | Size: 254 KiB |
|
After Width: | Height: | Size: 194 KiB |
|
|
@ -1,116 +1,38 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-20x20@2x.png",
|
||||
"scale" : "2x"
|
||||
"filename" : "AppIcon-Light.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-20x20@3x.png",
|
||||
"scale" : "3x"
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "AppIcon-Dark.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-29x29@2x-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-29x29@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-40x40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-40x40@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60x60@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60x60@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-20x20@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-20x20@2x-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-29x29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-29x29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-40x40@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-40x40@2x-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-76x76@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-76x76@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-83.5x83.5@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "AppIcon-512@2x.png",
|
||||
"scale" : "1x"
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "tinted"
|
||||
}
|
||||
],
|
||||
"filename" : "AppIcon-Tinted.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,4 +67,4 @@
|
|||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
</plist>
|
||||