Section 4/151 menit

4. Swift Package Manager: Cara Kerja Mendalam

4. Swift Package Manager: Cara Kerja Mendalam

Package.swift Anatomy

swift
// Package.swift — letakkan di root package/project

// swift-tools-version menentukan format Package.swift yang digunakan
// swift-tools-version: 6.0

import PackageDescription

let package = Package(
    name: "MyLibrary",
    defaultLocalization: "id",  // Bahasa default untuk localizable resources
    
    platforms: [
        .iOS(.v16),
        .macOS(.v13),
        .watchOS(.v9),
        .tvOS(.v16),
        .visionOS(.v1)
    ],
    
    products: [
        // Library yang di-export
        .library(name: "MyLibrary", targets: ["MyLibrary"]),
        
        // Executable (untuk CLI tools)
        // .executable(name: "mytool", targets: ["MyTool"]),
        
        // Plugin
        // .plugin(name: "MyPlugin", targets: ["MyPlugin"]),
    ],
    
    dependencies: [
        // Remote dengan version range
        .package(
            url: "https://github.com/Alamofire/Alamofire",
            from: "5.9.0"           // >= 5.9.0, < 6.0.0
        ),
        
        // Exact version
        .package(
            url: "https://github.com/onevcat/Kingfisher",
            exact: "7.11.0"
        ),
        
        // Branch (untuk development)
        .package(
            url: "https://github.com/apple/swift-async-algorithms",
            branch: "main"
        ),
        
        // Commit hash (untuk reproducible build)
        .package(
            url: "https://github.com/nicklockwood/SwiftFormat",
            revision: "0.54.3"
        ),
        
        // Local path (untuk library internal yang di-develop paralel)
        .package(path: "../MyInternalLib"),
        
        // Version range eksplisit
        .package(
            url: "https://github.com/realm/SwiftLint",
            "0.55.0"..<"1.0.0"
        ),
    ],
    
    targets: [
        .target(
            name: "MyLibrary",
            dependencies: [
                "Alamofire",
                .product(name: "Kingfisher", package: "Kingfisher"),
                // Conditional dependency
                .product(name: "AsyncAlgorithms", package: "swift-async-algorithms",
                         condition: .when(platforms: [.iOS, .macOS]))
            ],
            path: "Sources/MyLibrary",
            resources: [
                .process("Resources"),         // Auto-detect type
                .copy("Assets/static-asset"),  // Copy as-is
            ],
            swiftSettings: [
                .enableUpcomingFeature("StrictConcurrency"),
                .enableExperimentalFeature("AccessLevelOnImport"),
            ]
        ),
        
        .testTarget(
            name: "MyLibraryTests",
            dependencies: ["MyLibrary"],
            path: "Tests/MyLibraryTests"
        ),
        
        // Binary target: pre-compiled framework
        .binaryTarget(
            name: "SomeClosedSourceSDK",
            url: "https://example.com/SDK-1.0.xcframework.zip",
            checksum: "abc123..."
        ),
        
        // Build tool plugin
        .plugin(
            name: "GenerateCode",
            capability: .buildTool(),
            dependencies: ["CodeGenerator"]
        ),
    ]
)

Package.resolved: Lock File SPM

swift
// Package.resolved — auto-generated, HARUS di-commit ke Git
{
  "pins": [
    {
      "identity": "alamofire",
      "kind": "remoteSourceControl",
      "location": "https://github.com/Alamofire/Alamofire",
      "state": {
        "revision": "f455c2975872ccd2d9c81594c658af65716e9b9a",
        "version": "5.9.1"
      }
    },
    {
      "identity": "kingfisher",
      "kind": "remoteSourceControl",
      "location": "https://github.com/onevcat/Kingfisher",
      "state": {
        "revision": "...",
        "version": "7.11.0"
      }
    }
  ],
  "version": 3
}

SPM Command Line

swift
# Resolve: download/update semua dependencies sesuai Package.resolved
swift package resolve

# Update: update ke versi terbaru yang diizinkan, update Package.resolved
swift package update

# Update satu package spesifik
swift package update Alamofire

# Build
swift build
swift build -c release  # Release build

# Test
swift test
swift test --filter MyLibraryTests.NetworkTests

# Clean build artifacts
swift package clean

# Reset cache packages (nuclear option)
swift package reset

# Generate Xcode project dari Package.swift (deprecated tapi masih berguna)
swift package generate-xcodeproj

# List dependencies
swift package show-dependencies
swift package show-dependencies --format json | jq .

# Audit untuk security vulnerabilities
swift package audit

# Describe package structure
swift package describe --type json