XCFramework เป็นรูปแบบไบนารีของ Apple ที่รวมไลบรารีสำหรับ iOS, macOS, tvOS และ watchOS ไว้ในแพ็คเกจเดียว ออกแบบมาเพื่อแทนที่ .framework และขจัดปัญหา fat binaries เมื่อสร้างสำหรับสถาปัตยกรรมซิมูเลเตอร์และอุปกรณ์ที่แตกต่างกัน ตามข้อมูลจาก Apple WWDC 2019 XCFramework กลายเป็นรูปแบบบังคับสำหรับการจัดส่ง SDK ที่รองรับหลายแพลตฟอร์ม และแทนที่แนวทางเก่าด้วยไบนารีสากลอย่างสมบูรณ์
ประเด็นสำคัญ
XCFramework เป็นรูปแบบการบรรจุสำหรับไลบรารีไบนารีและเฟรมเวิร์กที่ Apple นำเสนอใน WWDC 2019 เป้าหมายหลักคือการสร้างบันเดิลเดียวที่ประกอบด้วยเวอร์ชันที่คอมไพล์แล้วของไลบรารีสำหรับแพลตฟอร์มและสถาปัตยกรรมเป้าหมายทั้งหมด
ก่อน XCFramework นักพัฒนาจะใช้ .framework กับ fat binary ที่รวมหลายสถาปัตยกรรมผ่านยูทิลิตี้ lipo แนวทางนี้ก่อให้เกิดปัญหา: เมื่อสร้างโปรเจกต์สำหรับซิมูเลเตอร์ fat binary จะมีทั้งสถาปัตยกรรมซิมูเลเตอร์และอุปกรณ์ ซึ่งนำไปสู่ข้อผิดพลาดเมื่อส่งบิลด์ไปยัง App Store นักพัฒนาต้องเขียนเฟส Run Script เพื่อลบสถาปัตยกรรมที่ไม่จำเป็น
ตามเอกสารสำหรับนักพัฒนาของ Apple (2024) XCFramework รองรับทุกแพลตฟอร์มในระบบนิเวศของ Apple: iOS, iPadOS, macOS, tvOS, watchOS, visionOS และแอปพลิเคชัน Catalyst แต่ละแพลตฟอร์มได้รับ slice แยกต่างหากภายในแพ็คเกจ ซึ่งขจัดความขัดแย้งทางสถาปัตยกรรมและทำให้การแจกจ่าย SDK ง่ายขึ้น
XCFramework ใช้ในสามสถานการณ์หลัก: การแจกจ่าย SDK แบบปิดให้กับนักพัฒนาบุคคลที่สาม การแจกจ่ายโมดูลเนทีฟสำหรับ Flutter และ React Native และการเผยแพร่ไลบรารีที่ต้องการการคอมไพล์ล่วงหน้า รูปแบบนี้เป็นข้อบังคับสำหรับ SDK ใหม่ทั้งหมดที่เผยแพร่ในระบบนิเวศของ Apple
นักพัฒนาเลือก XCFramework เมื่อไม่สามารถเปิดเผยซอร์สโค้ดได้ เมื่อไลบรารีใช้อัลกอริทึมที่เป็นกรรมสิทธิ์ หรือเมื่อต้องการการป้องกันลิขสิทธิ์ แตกต่างจาก Swift Package Manager ที่ทำงานกับซอร์สโค้ด XCFramework จัดส่งไฟล์ไบนารีที่คอมไพล์แล้ว
ปัญหา fat binary คือไบนารีสากลที่มีหลายสถาปัตยกรรมในไฟล์ Mach-O เดียว เมื่อสร้างแอปสำหรับซิมูเลเตอร์ Xcode จะรวมทั้งสถาปัตยกรรมอุปกรณ์ arm64 และสถาปัตยกรรมซิมูเลเตอร์ x86_64 — App Store ยอมรับเฉพาะสถาปัตยกรรมอุปกรณ์เท่านั้น
วิธีแก้ปัญหาแบบดั้งเดิมรวมถึงการเพิ่มเฟส Run Script ที่เรียก lipo เพื่อลบสถาปัตยกรรมซิมูเลเตอร์ออกจากบิลด์สุดท้าย แนวทางนี้เปราะบางและพังเมื่ออัปเดต Xcode หรือเมื่อมีสถาปัตยกรรมใหม่เกิดขึ้น (เช่น arm64 สำหรับซิมูเลเตอร์บน Apple Silicon)
ตาม Swift.org (2023) ทีม Swift Package Manager พบปัญหานี้ในตอนแรกเมื่อพยายามรองรับการพึ่งพาไบนารี XCFramework แก้ไขในระดับรูปแบบ: แต่ละ slice เป็นโฟลเดอร์แยกต่างหากที่มี Info.plist อธิบายแพลตฟอร์มและสถาปัตยกรรมเป้าหมาย Xcode เลือก slice ที่จำเป็นโดยอัตโนมัติระหว่างการสร้าง โดยไม่ต้องมีการประมวลผลภายหลัง
แต่ละ slice ใน XCFramework มีเพียงหนึ่งการรวมกันของแพลตฟอร์มและสถาปัตยกรรม ตัวอย่างเช่น ios-arm64 มีไบนารีสำหรับอุปกรณ์ iOS เท่านั้น และ ios-x86_64-simulator สำหรับซิมูเลเตอร์ Intel Mac เท่านั้น Xcode เลือก slice ที่ถูกต้องโดยอัตโนมัติ ขจัดความจำเป็นในการใช้สคริปต์ลบสถาปัตยกรรม และลดความเสี่ยงของข้อผิดพลาดในการสร้าง
slice ios-arm64-x86_64-simulator ถูกนำมาใช้เพื่อรองรับ Mac Apple Silicon ก่อนหน้านี้ ซิมูเลเตอร์ต้องการไบนารีแยกต่างหากสำหรับ arm64 (Apple Silicon) และ x86_64 (Intel) XCFramework อนุญาตให้มี fat binary ภายใน slice ซิมูเลเตอร์เดียว — นี่เป็นข้อยกเว้นเดียวที่ fat binary มีความสมเหตุสมผล
แพ็คเกจ XCFramework เป็นไดเรกทอรีที่มีนามสกุล .xcframework ประกอบด้วย Info.plist ในระดับบนสุดและโฟลเดอร์ที่มี slice ไบนารี แต่ละ slice รวมถึงไลบรารี .framework หรือ .a สำหรับแพลตฟอร์มเฉพาะ
MyLibrary.xcframework/
Info.plist
ios-arm64/
MyLibrary.framework/
Info.plist
MyLibrary
ios-x86_64-simulator/
MyLibrary.framework/
Info.plist
MyLibrary
macos-arm64-x86_64/
MyLibrary.framework/
Info.plist
MyLibrary
Info.plist ของแพ็คเกจประกอบด้วยคีย์ AvailableLibraries ซึ่งแสดงรายการ LibraryIdentifier, LibraryPath และ SupportedPlatform สำหรับแต่ละ slice Xcode อ่านไฟล์นี้เมื่อเพิ่ม XCFramework ลงในโปรเจกต์และกำหนดคีย์เส้นทางค้นหาและเฟส Embed Frameworks โดยอัตโนมัติ
แต่ละ slice เป็น .framework ที่สมบูรณ์หรือไลบรารีสแตติกที่มี Info.plist ของตัวเอง สิ่งนี้ช่วยให้ XCFramework รองรับประเภทผสม: ไลบรารีสแตติกสำหรับบางแพลตฟอร์มและเฟรมเวิร์กไดนามิกสำหรับอื่น ๆ แม้ว่าในทางปฏิบัติจะใช้ประเภทเดียวสำหรับทุก slice
การสร้าง XCFramework ทำได้ผ่าน xcodebuild -create-xcframework คำสั่งรับไลบรารี .framework หรือ .a ที่สร้างไว้แล้วสำหรับแต่ละแพลตฟอร์มเป็นอินพุตและรวมเข้าด้วยกันเป็นแพ็คเกจเดียว
กระบวนการประกอบด้วยสองขั้นตอน: ขั้นแรก สร้างไบนารีสำหรับแต่ละแพลตฟอร์มเป้าหมาย จากนั้นบรรจุลงใน XCFramework สำหรับการสร้าง จะใช้แฟลก destination มาตรฐานของ Xcode
# Step 1: build frameworks for each platform
xcodebuild archive -scheme MyLibrary -destination "generic/platform=iOS Simulator"
xcodebuild archive -scheme MyLibrary -destination "generic/platform=iOS"
xcodebuild archive -scheme MyLibrary -destination "generic/platform=macOS"
# Step 2: create XCFramework
xcodebuild -create-xcframework -framework ./iOS/MyLibrary.framework -framework ./iOSSim/MyLibrary.framework -framework ./macOS/MyLibrary.framework -output ./MyLibrary.xcframework
แฟลก -create-xcframework ถูกนำมาใช้ใน Xcode 11 คำสั่งจะสร้างโครงสร้างไดเรกทอรีที่ถูกต้องโดยอัตโนมัติและสร้าง Info.plist พร้อมคำอธิบายของทุกแพลตฟอร์ม หาก .framework ใดเสียหายหรือสร้างด้วยสถาปัตยกรรมที่ผิด xcodebuild จะแสดงข้อผิดพลาดในขั้นตอนการตรวจสอบ
สำหรับ CI/CD จะใช้ สคริปต์เชลล์ ที่ทำให้การสร้างสำหรับทุกแพลตฟอร์มและการสร้าง XCFramework เป็นอัตโนมัติ แนวทางที่นิยมคือตัวห่อในรูปแบบของ Makefile หรือ Fastlane lane ที่มี scheme และพาธเอาต์พุตแบบกำหนดพารามิเตอร์
# build_xcframework.sh - automation script
set -e
SCHEME="MyLibrary"
OUTPUT="./build"
xcodebuild archive -scheme "$SCHEME" -sdk iphonesimulator -archivePath "$OUTPUT/sim.xcarchive"
xcodebuild archive -scheme "$SCHEME" -sdk iphoneos -archivePath "$OUTPUT/dev.xcarchive"
xcodebuild -create-xcframework -framework "$OUTPUT/dev.xcarchive/Products/Library/Frameworks/MyLibrary.framework" -framework "$OUTPUT/sim.xcarchive/Products/Library/Frameworks/MyLibrary.framework" -output "$OUTPUT/MyLibrary.xcframework"
สคริปต์ดังกล่าวทำงานในไปป์ไลน์ CI (GitHub Actions, Bitrise, Jenkins) หลังจากการทดสอบผ่าน XCFramework ที่ได้จะถูกเก็บถาวรและอัปโหลดเป็นสิ่งประดิษฐ์ของรุ่น หรือเผยแพร่ผ่านตัวจัดการการพึ่งพาอย่าง CocoaPods โดยใช้ pod spec
การรวม XCFramework ในโปรเจกต์ Xcode ไม่ต้องการการกำหนดค่าเส้นทางค้นหาด้วยตนเอง เพียงลาก .xcframework ไปยังส่วน Frameworks, Libraries, and Embedded Content ในการตั้งค่า General ของ target
แตกต่างจาก .framework ตรงที่ XCFramework ไม่ต้องการเพิ่มเฟส Run Script เพื่อลบสถาปัตยกรรมซิมูเลเตอร์ Xcode จะกำหนด slice ที่มีอยู่โดยอัตโนมัติและรวมเฉพาะที่จำเป็นสำหรับแผนผังการสร้างปัจจุบัน สำหรับอุปกรณ์จริงจะใช้ slice ios-arm64 สำหรับซิมูเลเตอร์ — ios-arm64-x86_64-simulator หรือ ios-x86_64-simulator
import MyLibrary
func processData() {
// XCFramework resolves the correct slice at build time
let processor = DataProcessor()
let result = processor.analyze(input: "sample")
print(result)
}
สำหรับ CocoaPods การรวมจะทำผ่าน podspec ด้วย vendored_frameworks และรายการแพลตฟอร์มที่รองรับ ตัวจัดการการพึ่งพาจะกำหนดโดยอัตโนมัติว่าโปรเจกต์ต้องการ slice ใด SDK เชิงพาณิชย์หลายตัว — Firebase, Adjust, AppsFlyer — ได้ย้ายไปใช้ XCFramework เพื่อทำให้การติดตั้งง่ายขึ้น
Swift Package Manager และ XCFramework ไม่ได้เป็นคู่แข่งแต่เสริมซึ่งกันและกัน SPM ทำงานกับซอร์สโค้ดและสร้างการพึ่งพาในทุกการสร้างโปรเจกต์ XCFramework ให้ไบนารีพร้อมใช้โดยไม่ต้องคอมไพล์ฝั่งผู้บริโภค
ด้วยการเปิดตัว Swift Package Manager 5.3 Apple เพิ่มการรองรับ การพึ่งพาไบนารี — ตอนนี้ SPM สามารถดาวน์โหลด XCFramework เป็นการพึ่งพาระยะไกล Package.swift ระบุ URL ของสิ่งประดิษฐ์ไบนารีและเช็คซัมสำหรับการตรวจสอบ
ตามเอกสาร Swift Package Manager (2024) การพึ่งพาไบนารีแนะนำสำหรับ SDK ที่ไม่เปิดเผยซอร์สโค้ด หรือสำหรับไลบรารีที่เวลาในการสร้างยาวนานอย่างไม่สมส่วน สำหรับโปรเจกต์โอเพนซอร์ส การแจกจ่ายซอร์สโค้ดผ่าน SPM เป็นที่ต้องการ
| เกณฑ์ | XCFramework | Swift Package Manager |
|---|---|---|
| รูปแบบ | ไบนารี (.xcframework) | ซอร์สโค้ด |
| การป้องกันโค้ด | สมบูรณ์ | ไม่มี |
| เวลาในการสร้าง | น้อยที่สุด (คัดลอก) | ขึ้นอยู่กับปริมาณโค้ด |
| ความยืดหยุ่นของแพลตฟอร์ม | ทุกแพลตฟอร์ม Apple | ขึ้นอยู่กับ Package.swift |
| การรวม | ลากแล้ววางหรือ SPM | Package.swift |
คำถามที่พบบ่อย
.framework เป็นรูปแบบเดิมที่มี fat binary พร้อมสถาปัตยกรรมอุปกรณ์และซิมูเลเตอร์ XCFramework เก็บแต่ละ slice แยกต่างหาก ขจัดความขัดแย้งทางสถาปัตยกรรมระหว่างการสร้าง Apple แนะนำ XCFramework สำหรับโปรเจกต์ใหม่ทั้งหมดและการย้ายโปรเจกต์ที่มีอยู่
CocoaPods รองรับ XCFramework ตั้งแต่เวอร์ชัน 1.9 ใน podspec เพียงระบุ spec.vendored_frameworks และ spec.static_framework ตัวจัดการจะแก้ไขการพึ่งพาโดยอัตโนมัติ โดยพิจารณา slice ที่มีอยู่สำหรับแพลตฟอร์มของโปรเจกต์
Apple ไม่ได้ลบการรองรับ .framework แต่แนะนำ XCFramework สำหรับ SDK ใหม่เท่านั้น เมื่อส่งแอปไปยัง App Store ด้วย fat binary ในรูปแบบเก่า อาจเกิดข้อผิดพลาด Invalid Bundle เนื่องจากสถาปัตยกรรมซิมูเลเตอร์ ซึ่งทำให้ XCFramework เป็นสิ่งจำเป็นในทางปฏิบัติ
เริ่มตั้งแต่ Swift 5.3 การพึ่งพาไบนารีใน SPM ใช้ XCFramework Package.swift ระบุ url และ checksum ของแพ็คเกจไบนารี SPM ดาวน์โหลด ตรวจสอบความสมบูรณ์ และเชื่อมต่อ XCFramework เป็นการพึ่งพาระบบโดยไม่ต้องคอมไพล์ซอร์สโค้ด
visionOS รองรับใน XCFramework ตั้งแต่ Xcode 15 ที่ WWDC 2023 Apple ยืนยันว่ารูปแบบได้ขยายสำหรับ Apple Vision Pro slice สำหรับ visionOS มี SupportedPlatform = xros และรวมสถาปัตยกรรม arm64
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ