Ana Sayfa / Blog / SPM binary target: closed-source SDK dağıtımı

SPM binary target: closed-source SDK dağıtımı

Müşteriye kapalı kaynak bir SDK vermem gerekiyordu. Eskiden bunu Cocoapods vendored framework olarak yapardım; SPM’e geçtikten sonra binaryTarget ile daha temiz bir akış kuruyorum. Kurulum adımlarını ve karşılaştığım pitfall’ları paylaşayım. XCFramework üretimi Binary target .xcframework bekliyor. Framework’ü iki adımda üretiyorum: xcodebuild archive -scheme MySDK -destination "generic/platform=iOS" -archivePath build/MySDK-iOS SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES xcodebuild archive -scheme MySDK -destination […]

Müşteriye kapalı kaynak bir SDK vermem gerekiyordu. Eskiden bunu Cocoapods vendored framework olarak yapardım; SPM’e geçtikten sonra binaryTarget ile daha temiz bir akış kuruyorum. Kurulum adımlarını ve karşılaştığım pitfall’ları paylaşayım.

XCFramework üretimi

Binary target .xcframework bekliyor. Framework’ü iki adımda üretiyorum:

xcodebuild archive 
  -scheme MySDK 
  -destination "generic/platform=iOS" 
  -archivePath build/MySDK-iOS 
  SKIP_INSTALL=NO 
  BUILD_LIBRARY_FOR_DISTRIBUTION=YES

xcodebuild archive 
  -scheme MySDK 
  -destination "generic/platform=iOS Simulator" 
  -archivePath build/MySDK-iOS-Simulator 
  SKIP_INSTALL=NO 
  BUILD_LIBRARY_FOR_DISTRIBUTION=YES

xcodebuild -create-xcframework 
  -framework build/MySDK-iOS.xcarchive/Products/Library/Frameworks/MySDK.framework 
  -framework build/MySDK-iOS-Simulator.xcarchive/Products/Library/Frameworks/MySDK.framework 
  -output build/MySDK.xcframework

BUILD_LIBRARY_FOR_DISTRIBUTION=YES kritik. Olmadan module stability kaybediyorsun ve farklı Swift sürümleriyle derlenmiş consumer’larda crash oluyor.

Package.swift: remote binary target

let package = Package(
    name: "MySDK",
    platforms: [.iOS(.v16)],
    products: [
        .library(name: "MySDK", targets: ["MySDK"])
    ],
    targets: [
        .binaryTarget(
            name: "MySDK",
            url: "https://sdk.example.com/releases/1.2.0/MySDK.xcframework.zip",
            checksum: "a3b2c1d4..."
        )
    ]
)

Checksum’u swift package compute-checksum MySDK.xcframework.zip ile alıyorsun. Yanlış checksum verirsen resolve adımında hata alıyorsun.

Zip formatı önemli

İlk seferimde tar.gz yollamaya çalıştım; SPM reddetti. Sadece .zip kabul ediyor. Ayrıca zip içinde xcframework doğrudan root’ta olmalı; bir klasörün içinde paketlenmiş şekilde olmamalı:

zip -r MySDK.xcframework.zip MySDK.xcframework

-r flag’i unutulduğunda sadece klasör boş olarak paketleniyor ve hata mesajı yanıltıcı oluyor.

Local test için path-based binary target

Release öncesi consumer’dan SDK’yı test ettirmek için yerel dosyadan yüklüyorum:

.binaryTarget(
    name: "MySDK",
    path: "./artifacts/MySDK.xcframework"
)

Bu şekilde SDK tüketici projesinin yanına kopyalayıp Package.swift dependency’sini local path’e çeviriyorum. Checksum gerektirmiyor.

Sürümleme: git tag şart

SDK consumer’ı .package(url:, from:) ile tüketiyor. Bu semver tag gerektiriyor. Her release’te:

git tag 1.2.0
git push origin 1.2.0

Ve Package.swift içindeki URL + checksum’ı o release’e göre güncelliyorum. Tag atmayı unutursan consumer eski kodu alır, binary yeniyi; inconsistency yaşanır.

Bitcode ve strip sorunu

iOS 17’den sonra bitcode deprecated. Yine de eski Xcode ile build edilmiş SDK’lar bitcode ile geliyorsa App Store upload’ta hata veriyor. Çözüm: archive esnasında ENABLE_BITCODE=NO eklemek. Ayrıca symbol strip için STRIP_INSTALLED_PRODUCT=NO aksi halde crash symbolication zorlaşıyor.

Consumer tarafında debug

Binary target’tan gelen framework’te breakpoint koyamıyorsun. Source-level debug için consumer’a ayrıca .dSYM göndermelisin; release’te bunları zip içinde birlikte paketleyip iç bir S3’te tutuyorum:

MySDK.xcframework.zip
MySDK.xcframework.dSYM.zip

Privacy Manifest

iOS 17 Privacy Manifest gerektiği için SDK içine PrivacyInfo.xcprivacy koymam lazım. Binary target içinde bundle olarak paketlendiğinde consumer app privacy manifest aggregation’da bu dosyayı okuyabiliyor; koymayı unutursan App Store submit’te uyarı alıyorsun.

Hangi durumda binary target’a gitmem

Open-source kütüphane ise kaynak paylaşmak daha iyi; consumer farklı Swift sürümünde derleyebilsin. Binary target sadece kapalı kaynak veya lisans kısıtı olan senaryolarda değer. SDK boyutu çok büyükse Carthage veya manual vendored framework akışı da hâlâ geçerli; ama CI tarafı SPM’te daha az acı.

Son tavsiye

SDK’yı yayınlamadan önce ayrı bir test project açıp SPM üzerinden tüketen bir örnek app yaz. Çoğu integration sorununu consumer perspektifinden görmeden fark etmezsin.

Bu konuda bir projeniz mi var?

Kısa bir özet bırakın, 24 saat içinde size dönüş yapayım.

İletişime Geç