📦

Start a new Xcode project with Swift Package Manager

Why
  • Better file organization than the default way (files managed by Xcode UI/xcodeproj file)
    • xcodeproj configs are done with Xcode UI rather than specified in a file directly
    • which → changes to xcodeproj is less predictable & prone to merge conflicts
  • Easier modularization than the default way (targets & dependencies managed by Xcode UI/xcodeproj)
    • When code is modularized, better separation is enforced & it’s easier to avoid unnecessary dependencies
    • Easier to reuse a module between different apps/projects
 
Initial setup
  1. Start a new project in Xcode (check create Git repository)
  1. Top bar menu: File → New → Package
      • Set type as Library
      • Set the location to be inside the project folder
      • Set “Add to” to the project
      • Uncheck create Git repository (because the project already has Git)
      • name it App or something → Create
  1. Go to target setting of the top level app target, inside General → Frameworks, Library, and Embedded Content , click + and include the package just created.
  1. Drag the auto-created boilerplate files (e.g. ContentView.swift, ___App.swift) into the Source/App folder in the package
  1. Build & run 🎉
 
On going development
  1. If necessary, do some of the modifications in the Package.swift file
      • Specify min iOS version on the top level in Package, e.g. platforms: [.iOS(.v15)],
      • If an external dependency is necessary:
        • Top bar menu: File → Add Package Dependencies
        • Search for the package
        • From the search result, check the current version, then right click on the package and & copy
          Example:
          notion image
        • Dismiss the window (don’t click “Add Package” button, because we want the package to depend on this library, instead of the Xcode project)
        • In the Package.swift file inside App folder
          • inside top level dependencies, add: .package(url: "<pasted github url for the package>", from: "<version seen from search result>"),
          • inside targets array, for the App target (or any target that needs the dependency), in its dependencies array, add: .product(name: "<library name>", package: "<package name>").
            • package name is often the same as the git repository name
            • the library name can be found in the Package.swift file of the downloaded library. It’s also the name that will be after import in the code.
  1. To add a new module
      • create a new folder inside the package’s Sources folder
      • In the Package.swift file, inside targets array, add a new target for this folder.
        • If the folder is on the top level, making sure the folder name is the same as the target name is enough
        • otherwise use path property to specify the path
      • Include this target in the dependencies of another target that uses it. Can just include a string (target name) there.
  1. To add a new module that is reusable for other apps
      • Similar to the initial setup of the App module, create a new module from top bar menu: File → New → Package
        • can check “create Git repository”
      • This way this new module is its own package and will have its own Package.swift