How to Incorporate Swift Package Manager to an Existing Xcode Project

Use swift package manager on existing xcode project

Swift Package Manager is a standalone tool which allows managing dependencies and building projects without Xcode. It can generate Xcode projects for you with swift package generate-xcodeproj.

However, at the moment, Swift Package Manager only has support for building projects for macOS and Linux platforms. The only way to build projects for iOS, tvOS and watchOS is using Xcode, which includes the SDKs needed for these platforms.

There are ways to use Swift Packages Manager to manage dependencies for iOS/tvOS/watchOS, but it is not easy and requires manual work. If you are interested, take a look at https://github.com/j-channings/swift-package-manager-ios

Other than that, I'd recommend using Carthage or CocoaPods.

Update for Xcode 11

Swift Package Manager is now integrated into Xcode 11. You can add your package by going to "File" then "Swift Packages" then "Add Package Dependency..." Paste the repository's URL into the field above then click "next". Xcode will walk you through the rest of the steps. You can learn more at this WWDC talk.

Exporting Package.swift for Swift Package Manager from existing Xcode project

There are no a menu command or utility to convert application to a static library, dynamic framework or swift package since they are different types of projects with different settings etc.

If you want to export a part of your project as a swift package you should make next steps manually:

1. Create Package.swift file in the root of your project

import PackageDescription

let package = Package(
name: “MyLib”,
products: [
.library(name: "MyLib", targets: ["MyLib"])
],
targets: [
.target(name: "MyLib"),
],
...
)

2. Make folder with subfolder ./Sources/MyLib under the projects’s root.

By default swift package structure requires to put all your sources files under Sources/LibraryName folder but you can change it below.

NOTE: you can simplify first two steps by using swift package init and it creates Package.swift, Sources and Test folders etc.

3. Include source files

a) Move the needed files to share from their current locations to MyLib folder.

For instance:

./Classes/MyEntity.swift -> ./Sources/MyLib/MyEntity.swift

Also you have to update locations of the moved files in your Xcode project to leave it compilable.

b) Use path, sources and exclude to point needed source files to your package from their current locations:

.target(name: "MyLib", path: "Classes"),

NOTE: Don't forget to make your classes public to access to them after import your package:

public class MyEntity {
...
}

After all you will have two working projects - old XCode's one and new Swift package.

4. REPL

Now you can use command line interpreter with your swift package:

swift run --repl
import MyLib
let entity = MyEntity()
...

Using Swift Package Manager (SPM) for Existing [iPhone App] XCode Project (Having Swift + Objective C Files)

As far as I know you can't use SPM right now within iOS apps.

You can use it in hosted environments for example if you are hosting a web application with Vapor on a Mac or on Linux.

Add forked Swift Package in Xcode project

I finally worked around this limitation by manually editing both the project.pbxproj and Packages.resolved files, so that they point to the specific commit in the fork of the repository.

To do this, close Xcode and then open the two files with a plain text editor.

In the project.pbxproj file, change the url of the repo and the parameters needed to correctly specify the version rule. In my case, I wrote the hash of the commit I needed:

/* Begin XCRemoteSwiftPackageReference section */
7902F77227C64GF9001583F1 /* XCRemoteSwiftPackageReference "Cuckoo" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/ajpallares/Cuckoo";
requirement = {
kind = revision;
revision = a9d239ff1bb93fe0204f8285d513f3139b51fbbb;
};
};

Do the same for the Packages.resolved file:

{
"package": "Cuckoo",
"repositoryURL": "https://github.com/ajpallares/Cuckoo",
"state": {
"branch": null,
"revision": "a9d239ff1bb93fe0204f8285d513f3139b51fbbb",
"version": "null"
}

Obviously, this is not the ideal solution but at least it works ¯\(ツ)

In fact, this seems to be an intended limitation of Swift Package Manager. See:

  • https://forums.swift.org/t/dependency-mirroring-and-forking/13902
  • https://forums.swift.org/t/replace-dependency-in-graph-with-a-fork/39718


Related Topics



Leave a reply



Submit