การสร้างภาพหน้าจอ App Store อัตโนมัติสำหรับ SwiftUI โดยไม่ใช้ fastlane (2026)
XCUITest + XCUIScreenshot สำหรับถ่ายแอปที่รันจริง, Swift Testing attachments API ตัวใหม่ที่ทำสิ่งเดียวกันด้วย boilerplate น้อยกว่า และ ImageRenderer สำหรับ render SwiftUI view ตรงเป็น PNG โดยไม่ต้องรัน simulator เลย OSS อย่าง swift-snapshot-testing และ AppScreenshotKit ห่อสิ่งเหล่านั้นไว้อีกชั้น ไม่มีตัวไหนเลยที่จัดวางคารูเซลทางการตลาด — กรอบอุปกรณ์ คำบรรยาย พื้นหลัง คำแปล 50 locale นั่นเป็นขั้นตอนแยกต่างหาก และเป็นจุดที่ Mokbi เข้ามา: มันจัดวางและแปลภาษาภาพหน้าจอที่คุณถ่ายมาแล้ว มันไม่ได้ถ่ายภาพหน้าจอเหล่านั้นsnapshot ของ fastlane คือคำตอบมาตรฐานสำหรับ "สร้างภาพหน้าจอ App Store ของฉันอัตโนมัติ" และก็มีเหตุผลรองรับ — มันเป็นเครื่องมือที่เติบโตเต็มที่และเป็นมิตรกับ CI แต่มันก็เป็น Ruby toolchain, Snapfile, SnapshotHelper.swift ที่คุณต้อง copy ลงใน test target และการตั้งค่าที่ไม่น้อยเลยสำหรับสิ่งที่ลึกๆแล้วเป็นแค่ wrapper บางๆรอบ XCUITest API เดียวกับที่คุณมีอยู่แล้ว ถ้าคุณสร้างแอปด้วย SwiftUI และไม่อยากเพิ่ม Ruby dependency ในโปรเจกต์ iOS คุณสามารถสร้างภาพหน้าจออัตโนมัติได้ด้วย Xcode และ Swift เท่านั้น โพสต์นี้คือแผนที่ตรงไปตรงมาของตัวเลือกแบบ native ในปี 2026 พร้อมโค้ดที่ copy ไปใช้ได้เลย และเส้นแบ่งที่ชัดเจนว่าเครื่องมือไหนทำหน้าที่อะไร สำหรับการเปรียบเทียบแบบตัวต่อตัว ดู Mokbi vs fastlane
มีกรอบความคิดหนึ่งที่ควรทำความเข้าใจก่อน เพราะช่วยลดความสับสนได้มาก: การถ่าย frame (ขับแอปไปสู่สถานะหนึ่งแล้วบันทึก PNG ของสิ่งที่อยู่บนหน้าจอ) กับ การจัดวางภาพหน้าจอ store (frame นั้นอยู่ในม็อกอัพอุปกรณ์ พร้อม headline พื้นหลัง และคำแปล export ออกมาทุกขนาดที่จำเป็น) เป็นปัญหาคนละอย่างกัน ทุกอย่างในโพสต์นี้แก้ปัญหาแรก ไม่มีข้อไหนแก้ปัญหาที่สอง
ทำไมถึงข้าม fastlane ไปเลย?
fastlane ไม่มีอะไรผิดปกติ เหตุผลที่นักพัฒนาเลือกใช้แนวทาง native เป็นเรื่องปฏิบัติจริง ไม่ใช่อุดมการณ์:
- ไม่มี Ruby เข้ามาเกี่ยวข้อง fastlane คือ Ruby gem ที่มีปัญหาเวอร์ชันของตัวเอง (Bundler, gem conflict, CI พังเป็นครั้งคราวหลัง Ruby อัปเดต) ถ้าโปรเจกต์ของคุณเป็น Swift ล้วนอยู่แล้ว นั่นคือ runtime ทั้งชุดที่คุณต้องดูแลเพิ่มสำหรับงานเดียว
- คุณมี test target อยู่แล้ว
snapshotสร้าง UI test ให้เบื้องหลัง ถ้าคุณเขียน UI test อยู่แล้ว การถ่ายภาพหน้าจอก็แค่เพิ่มอีกสองบรรทัด — ไม่ต้องใช้เครื่องมือใหม่ - SwiftUI เปลี่ยนสมการ ด้วย
ImageRendererคุณ render หน้าจอเป็น PNG ได้โดยไม่ต้องเปิดแอปเลย ซึ่ง fastlane ทำไม่ได้ — มันต้องขับ simulator เสมอ - ชิ้นส่วนที่ต้องเคลื่อนไหวใน CI น้อยลง
xcodebuild testธรรมดาที่ผลิตภาพหน้าจอออกมาเข้าใจง่ายกว่า fastlane lane ที่เรียกxcodebuildแล้วประมวลผล results bundle ต่อ
อีกด้านหนึ่ง: fastlane รวมส่วนที่น่ารำคาญ (ดึง attachment ออกจาก .xcresult bundle จัดระเบียบตาม locale × device สร้าง HTML preview และอัปโหลดผ่าน deliver) ไว้ในคำสั่งเดียว ถ้าเลือกไปทาง native งาน plumbing ในการรวบรวมนั้นจะกลายเป็นหน้าที่ของคุณ นั่นคือการแลกเปลี่ยนทั้งหมดของการตัดสินใจนี้ และควรตัดสินใจอย่างมีสติ
ตัวเลือกที่ 1: XCUITest + XCUIScreenshot (ถ่ายแอปที่รันจริง)
นี่คือรากฐานที่ fastlane เองสร้างขึ้นมาจาก UI test target เปิดแอปจริงของคุณใน simulator ขับเคลื่อนด้วย finder/tap API แบบเดียวกับ UI test ทั่วไป และ XCUIScreen.main ถ่ายทั้งหน้าจออุปกรณ์ที่ความละเอียดจริง คุณห่อภาพหน้าจอนั้นด้วย XCTAttachment และตั้ง lifetime = .keepAlways เพื่อให้ Xcode เก็บมันไว้แม้ test จะผ่าน (ค่าเริ่มต้นจะทิ้ง attachment เมื่อสำเร็จ)
// ScreenshotUITests.swift — runs in a UI test target
import XCTest
final class ScreenshotUITests: XCTestCase {
func testCaptureCarouselScreens() {
let app = XCUIApplication()
// A launch argument your app reads to seed demo data + hide
// anything that would make a noisy screenshot (debug banners, etc).
app.launchArguments += ["-FASTLANE_SNAPSHOT", "NO", "-SCREENSHOT_MODE", "YES"]
app.launch()
// Drive the app to the state you want, then capture the WHOLE screen.
snapshot("01_Home")
app.buttons["openLibrary"].tap()
snapshot("02_Library")
}
private func snapshot(_ name: String) {
// XCUIScreen.main captures the full device screen at native
// resolution — exactly what App Store Connect wants.
let shot = XCUIScreen.main.screenshot()
let attachment = XCTAttachment(screenshot: shot)
attachment.name = name
attachment.lifetime = .keepAlways // or Xcode discards it when the test passes
add(attachment)
}
}ภาพหน้าจอจะอยู่ใน .xcresult bundle คุณดึงออกมาหลังรันเสร็จ — ไม่ว่าจะเปิด result bundle ใน Xcode แล้วลากออกมา หรือใช้เครื่องมืออย่าง xcparse / xc-screenshot ใน CI ที่เดินผ่าน bundle แล้วเขียน PNG ที่ตั้งชื่อแล้วลงโฟลเดอร์ ขั้นตอนการดึงข้อมูลนี้คือสิ่งที่ fastlane ทำให้คุณอัตโนมัติพอดี และเป็นสิ่งหลักที่คุณต้องรับผิดชอบเองเมื่อเลือกทาง native
การแปลภาษาโดยไม่ต้องแก้โค้ด เทคนิคเจ๋งๆตรงนี้คือ Xcode test plan: สร้าง test plan เดียว เพิ่ม configuration ต่อภาษา/ภูมิภาค (แต่ละอันตั้งค่าภาษาแอป + ภูมิภาค) แล้ว test เดียวกันจะรันหนึ่งครั้งต่อ configuration คุณจะได้ภาพหน้าจอที่แปลภาษาแล้ว — UI แอป render ในแต่ละ locale — โดยไม่ต้องแตะโค้ด test เลย รันบน simulator คลาส iPhone ขนาด 6.9 นิ้วและ simulator คลาส iPad ขนาด 13 นิ้วเพื่อให้ได้ความละเอียดที่ App Store Connect ต้องการ
ข้อดีและข้อเสีย:
- พิกเซลของแอปจริง view ที่รันจริง — ฟอนต์ ธีม ข้อมูล dynamic ทั้งหมด native — ที่ความละเอียดของ simulator เป๊ะๆ
- ไม่มี fastlane ไม่มี Ruby Xcode + Swift ล้วนๆ รันภายใต้
xcodebuild testได้ใน CI ทุกที่ - Locale เป็น config ของ test plan ไม่ใช่โค้ด เพิ่ม configuration ต่อภาษาแล้วรันใหม่ ไม่ต้องแตกโค้ด Swift ตาม locale
- คุณต้องดูแลการดึงข้อมูลเอง การดึง PNG ออกจาก
.xcresultbundle เป็นหน้าที่ของคุณ (script ครั้งเดียวแต่เป็นงานจริง) - ต้นทุนการบำรุงรักษา finder (
buttons["openLibrary"], การแตะ) พังเมื่อ UI เปลี่ยน เหมือน UI test ทั่วไป
ตัวเลือกที่ 2: Swift Testing attachments (เวอร์ชันสมัยใหม่ที่เบากว่า)
Swift Testing (framework แบบ macro ของ Apple ที่มาพร้อม Xcode 26) เพิ่ม Attachment API ที่ทำสิ่งเดียวกับ XCTAttachment แต่พิธีรีตองน้อยกว่าและเรียกใช้ง่ายกว่า คุณยังคงขับแอปด้วย XCUIApplication และถ่ายด้วย XCUIScreen.main.screenshot() — สองอย่างนี้อยู่ใน XCUITest — แต่บันทึกภาพด้วย Attachment.record(...) จากฟังก์ชัน @Test Attachment API ไม่สนใจว่าภาพถูกสร้างขึ้นมาอย่างไร มันรับ image type ที่ conform ได้ทุกแบบและเขียนลงใน result bundle ของ test
// ScreenshotTests.swift — Swift Testing (Xcode 26+)
import Testing
import XCTest // still needed for XCUIApplication / XCUIScreen
@MainActor
struct ScreenshotTests {
@Test func homeAndLibrary() async throws {
let app = XCUIApplication()
app.launchArguments += ["-SCREENSHOT_MODE", "YES"]
app.launch()
// Attachment.record attaches to THIS test's result bundle.
let home = XCUIScreen.main.screenshot()
Attachment.record(home.image, named: "01_Home.png")
app.buttons["openLibrary"].tap()
let library = XCUIScreen.main.screenshot()
Attachment.record(library.image, named: "02_Library.png")
}
}ในเชิงหน้าที่แล้ว นี่ถ่ายพิกเซลของแอปจริงชุดเดียวกับตัวเลือกที่ 1 — มันเป็นการถ่ายหน้าจอพื้นฐานตัวเดียวกัน สิ่งที่คุณได้เพิ่มคือ ergonomics ของ Swift Testing ที่สะอาดกว่า (test แบบมีพารามิเตอร์, async เป็นค่าเริ่มต้น, ไม่ต้อง subclass XCTestCase) ถ้าโปรเจกต์ของคุณย้ายไปใช้ Swift Testing แล้ว สิ่งที่คุณไม่รอดพ้นก็คือขั้นตอนการดึงข้อมูลแบบเดียวกัน: PNG ยังคงอยู่ใน result bundle และยังต้องดึงออกมาเพื่ออัปโหลด ใช้ตัวเลือกนี้เมื่อคุณใช้ Swift Testing อยู่แล้ว มิฉะนั้นตัวเลือกที่ 1 ให้ผลลัพธ์เหมือนกันทุกประการ
ตัวเลือกที่ 3: ImageRenderer (ไม่ต้องรัน simulator เลย)
นี่คือตัวเลือกที่ fastlane ทำไม่ได้โดยโครงสร้าง ImageRenderer (SwiftUI, iOS 16+ / macOS 13+) รับ SwiftUI view แล้ว render hierarchy ของมันตรงเป็น UIImage / CGImage — ไม่ต้องเปิดแอป ไม่ต้อง automate UI ของ simulator ไม่มี finder ให้พัง คุณให้ view ที่ตั้งขนาดตามพิกเซล App Store เป๊ะๆ แล้วอ่าน PNG byte กลับมา
// Render a SwiftUI view straight to a PNG — no simulator UI run.
import SwiftUI
@MainActor
func renderScreen() -> Data? {
let view = HomeScreen() // your real SwiftUI screen
.frame(width: 1320, height: 2868) // 6.9-inch iPhone, exact pixels at 1x
let renderer = ImageRenderer(content: view)
renderer.scale = 1 // size is already in target pixels
renderer.isOpaque = true // App Store rejects alpha channels
#if canImport(UIKit)
return renderer.uiImage?.pngData()
#else
guard let cg = renderer.cgImage else { return nil }
let rep = NSBitmapImageRep(cgImage: cg)
return rep.representation(using: .png, properties: [:])
#endif
}มีสองสิ่งที่สำคัญสำหรับ output ที่ส่งขึ้น store ตั้ง isOpaque = true — App Store Connect จะปฏิเสธภาพหน้าจอที่มี alpha channel และการ render แบบทึบแสงช่วยหลีกเลี่ยงปัญหานั้น และระวังเรื่อง scale: ถ้าคุณตั้งขนาด view เป็น point แทนที่จะเป็นพิกเซลเป้าหมาย ให้ตั้ง renderer.scale ตาม scale ของอุปกรณ์เพื่อไม่ให้ output เบลอ ถ้าคุณตั้งขนาด frame เป็นพิกเซลเป้าหมายเป๊ะๆ (แบบด้านบน) ให้คง scale ไว้ที่ 1
ข้อควรระวังใหญ่คือสิ่งที่ ImageRenderer render ไม่ได้ มัน render SwiftUI ไม่ใช่ view ที่อิง UIKit/AppKit: web view, map view, media player, camera preview และ system control บางตัวจะออกมาเป็น placeholder สำหรับหน้าจอ SwiftUI ที่สะอาดและแน่นอนตายตัว มันยอดเยี่ยมมาก — เร็วทันที ไม่ต้องมี UI ขนาดพอดีเป๊ะ รันได้ทุกที่รวมถึงบนอุปกรณ์จริง สำหรับหน้าจอที่ฝัง platform view คุณต้องกลับไปใช้ตัวเลือกที่ 1–2 เพื่อถ่าย output ของ compositor จริง
- เร็วที่สุดแบบทิ้งห่าง มิลลิวินาทีต่อภาพ ไม่ต้อง boot simulator ไม่ต้องขับ UI เยี่ยมมากใน CI
- ขนาดเป๊ะแบบง่ายๆ ตั้งขนาด frame เป็น 1320 × 2868 (หรือขนาดที่ต้องการ) แล้วนั่นคือ output ของคุณ — ไม่ต้องเดา "resize ให้ตรงกับ App Store"
- คุณกำหนด state เอง เพราะไม่มีแอปที่รันจริง คุณส่ง mock data เข้า view โดยตรง — แน่นอนตายตัว ไม่ต้องใช้ launch argument สำหรับ seed ข้อมูล demo
- SwiftUI เท่านั้น view ที่อิง platform จะ render เป็น placeholder ตรวจสอบหน้าจอของคุณก่อนจะเชื่อผลลัพธ์
ตัวเลือกที่ 4: OSS ที่ห่อสิ่งข้างต้น
มีโปรเจกต์ open-source สองตัวที่ถูกพูดถึงบ่อยมาก แก้ปัญหาที่ใกล้เคียงกัน
pointfree/swift-snapshot-testing คือ library snapshot ของ SwiftUI ที่นิยมที่สุด และควรทำความเข้าใจให้ชัดเจนเรื่องจุดประสงค์ของมัน: มันสร้างมาสำหรับ regression testing ไม่ใช่สำหรับผลิต asset ของ store การรันครั้งแรกจะบันทึก PNG อ้างอิงและ fail โดยตั้งใจ การรันครั้งถัดๆไปจะ diff กับ reference นั้นเพื่อจับวันที่ padding หรือฟอนต์เปลี่ยนแล้วทำให้ UI ของคุณขยับ
// pointfree/swift-snapshot-testing — built for regression, not store assets.
import SnapshotTesting
import SwiftUI
import Testing
@MainActor
struct HomeSnapshotTests {
@Test func home_iPhone16ProMax() {
let view = HomeScreen()
// First run records the reference PNG and FAILS on purpose;
// later runs diff against it. To re-record: record: .all
assertSnapshot(of: view, as: .image(layout: .device(config: .iPhone13ProMax)))
}
}คุณสามารถนำภาพ reference ที่บันทึกไว้มาใช้เป็นภาพหน้าจอ raw ได้ และ strategy แบบ .image(layout: .device(...)) ก็ render ที่ขนาดอุปกรณ์จริง — แต่นั่นขัดกับความเข้มงวดของเครื่องมือ (มันต้องการ match แบบ pixel-perfect ความแตกต่างของ antialiasing ระหว่างเครื่องทำให้เกิด failure แบบ flaky) ใช้มันเพื่อป้องกัน regression ของ UI ไม่ใช่เป็น pipeline ภาพหน้าจอหลักของคุณ
AppScreenshotKit (โดย shitamori1272) สร้างมาเพื่องานนี้โดยเฉพาะ คุณประกาศ SwiftUI view ด้วย macro @AppScreenshot ระบุคลาสอุปกรณ์และ locale ห่อหน้าจอจริงของคุณด้วย DeviceView เพื่อให้ render อยู่ในกรอบอุปกรณ์ของ Apple แล้ว export จากฟังก์ชัน Swift Testing มันจัดระเบียบ output เป็นโครงสร้างแบบ Screenshots/<locale>/<device>/ ที่สะอาดตา
// AppScreenshotKit — declarative SwiftUI screenshots, runs under Swift Testing.
import AppScreenshotKit
import SwiftUI
@AppScreenshot(.iPhone69Inch(), options: .locale([Locale(identifier: "en_US")]))
struct HomeShot: View {
var body: some View {
DeviceView { HomeScreen() } // your real screen, wrapped in a device frame
}
}
// In a test target:
import AppScreenshotKitTestTools
import Testing
@Test @MainActor
func exportScreens() throws {
let out = URL(fileURLWithPath: "Screenshots")
let exporter = AppScreenshotExporter(option: .file(outputURL: out))
try exporter.export(HomeShot.self) // → Screenshots/en_US/iPhone_6_9_inch/...
}เครื่องมือที่เกี่ยวข้องในพื้นที่นี้ก็ควรรู้จักไว้: CLI อย่าง storescreens ขับเคลื่อน pipeline App Store Connect ทั้งหมด (ถ่ายด้วย XCUITest ข้าม simulator แบบขนาน render ในกรอบพร้อมคำบรรยาย อัปโหลด metadata ผ่าน API ของ Apple) จาก config file เดียว เครื่องมือเหล่านี้มีประโยชน์จริงถ้าคุณต้องการ chain เดียวที่ idempotent และเป็นมิตรกับ CI พวกมันก็มาพร้อมความคิดเห็นของตัวเองเรื่อง layout ของคำบรรยายด้วย — ซึ่งเป็นรอยต่อที่ editor แบบภาพเฉพาะทางมักจะชนะสำหรับพื้นที่ทางการตลาด
ส่วนที่ไม่มีข้อไหนข้างต้นทำ: การจัดวาง + การแปลภาษา 50 ภาษา
นี่คือย่อหน้าที่ตรงไปตรงมาและมีขอบเขตชัดเจน ทุกตัวเลือกข้างต้นผลิตframe แบบเปล่าๆ — UI แอปของคุณที่ความละเอียดอุปกรณ์ (หรือกับ AppScreenshotKit และเพื่อนๆ ก็เป็น frame อยู่ในม็อกอัพอุปกรณ์ธรรมดา) คารูเซล App Store ที่เพิ่ม conversion ไม่ใช่ frame เปล่าๆ: มันคือ frame อยู่ในม็อกอัพอุปกรณ์ที่มีสไตล์ บนพื้นหลัง ใต้ headline สั้นๆ มักเป็นลำดับหลายพาเนล ซ้ำในทุก locale ที่คุณเจาะจง ขั้นตอนการจัดวางนั้นคือสิ่งที่ Mokbi มีไว้เพื่อทำ คุณนำ frame ที่ถ่ายมา (จาก XCUITest, ImageRenderer, simulator หรือที่ไหนก็ตาม) วางลงใน browser editor เพิ่มกรอบอุปกรณ์ คำบรรยาย และพื้นหลัง แปลคำบรรยายข้ามภาษา App Store สูงสุด 50 ภาษาด้วยคลิกเดียว แล้ว batch export ทุกขนาดที่จำเป็น ออกแบบฟรีพร้อม watermark preview ส่วน export และการเผยแพร่แบบไม่จำกัดมาพร้อมกับการสมัครสมาชิก — Solo ที่ €29.99/mo (1 แอป) หรือ Studio ที่ €49.99/mo (สูงสุด 5 แอป) ไม่มีการซื้อแบบครั้งเดียว เพื่อให้ชัดเจนเรื่องขอบเขต: Mokbi ไม่ได้ถ่ายภาพหน้าจอต้นฉบับ — มันไม่ได้รันแอปของคุณหรือ render view ของคุณ การถ่ายภาพยังคงเป็นหน้าที่ของเครื่องมือ Swift แบบ native ข้างต้น Mokbi จัดวางและแปลภาษาสิ่งที่เครื่องมือเหล่านั้นผลิตออกมา
เวิร์กโฟลว์ SwiftUI แบบผสมผสานที่เป็นจริง
- ถ่าย source frame แบบ native สำหรับหน้าจอ SwiftUI ที่แน่นอนตายตัว ให้ render ด้วย
ImageRendererที่ขนาดพิกเซลเป๊ะๆ (ตัวเลือกที่ 3) — เร็วที่สุดและไม่ต้องใช้ simulator สำหรับหน้าจอที่มี platform view หรือที่คุณต้องการ state ที่รันจริง ให้เขียนการถ่ายแบบ XCUITest (ตัวเลือกที่ 1) หรือ Swift Testing (ตัวเลือกที่ 2) แล้วรันบน simulator คลาส iPhone ขนาด 6.9 นิ้วและคลาส iPad ขนาด 13 นิ้ว - แปลภาษาการถ่ายถ้าคุณต้องการ เพิ่ม configuration ของ test plan ต่อภาษาเพื่อให้ UI แอป render ในแต่ละ locale หรือส่ง locale เข้า view ที่คุณส่งให้
ImageRendererวิธีนี้แปลภาษาพิกเซลของแอป — ไม่ใช่ headline ทางการตลาดของคุณ - จัดวางคารูเซลทางการตลาด วาง frame ลงใน Mokbi เพิ่มกรอบ/คำบรรยาย/พื้นหลังที่มีสไตล์ สร้างลำดับหลายพาเนล นี่คือขั้นตอนที่เครื่องมือ native ทำไม่ได้
- แปลคำบรรยายและ export แปล headline ด้วยคลิกเดียวข้าม locale App Store เป้าหมายของคุณ แล้ว batch export ทุกขนาดที่จำเป็น
- เมื่อ UI เปลี่ยนครั้งต่อไป ถ่ายใหม่และเปิดใหม่ รัน renderer หรือ UI test ใหม่ เปิดโปรเจกต์ Mokbi ที่บันทึกไว้ใหม่ สลับ frame export ใหม่ การจัดวางและคำแปลถูกเก็บรักษาไว้
เมื่อไหร่ที่ควรข้าม automation ไปเลย
ถ้าคุณส่งหนึ่งถึงสาม release ต่อปี การสร้างระบบภาพหน้าจอ — ไม่ว่าจะเป็นแบบ native หรือ fastlane — จะกินเวลามากกว่าที่มันเคยประหยัดได้ รันแอปใน iOS Simulator ที่คลาสอุปกรณ์ที่ถูกต้อง ไปยังแต่ละหน้าจอ กด command ถ่ายภาพหน้าจอของ simulator (มันถ่ายที่ความละเอียดอุปกรณ์เป๊ะๆ) แล้วคุณจะได้ PNG ที่พร้อมขึ้น App Store ภายในสิบนาที จากนั้นจัดวางและแปลภาษาครั้งเดียวแล้วไปต่อ automation ข้างต้นคุ้มค่าพอดีเมื่อ "ถ่ายใหม่ด้วยมือ" หยุดเป็นงานสิบนาที — การ release บ่อยๆ, หลาย locale หรือหลายแอปในพอร์ตโฟลิโอ จับคู่เครื่องมือให้ตรงกับจังหวะการ release ของคุณ ไม่ใช่ตามสิ่งที่ดูเข้มงวดน่าเชื่อถือ ตรรกะเดียวกันนี้ใช้ได้กับแพลตฟอร์มอื่นด้วย ดู เวอร์ชัน React Native ของปัญหานี้ และ การเปรียบเทียบ fastlane vs no-code ในภาพกว้าง
ไม่ว่าจะถ่ายด้วยวิธีไหน ตรวจสอบ target ให้แน่ใจก่อน export: ดูขนาดพิกเซลเป๊ะๆและกฎ format (PNG/JPEG, RGB, ไม่มี alpha channel) จาก คู่มือขนาดภาพหน้าจอ App Store Apple ปฏิเสธขนาดที่คลาดเคลื่อนแม้แต่หนึ่งพิกเซลโดยไม่ผ่อนผัน ดังนั้นการตรวจสอบนี้คุ้มค่าสามสิบวินาที