Creating a Swift Package

In my previous post I looked at creating a CircleImage, basically creating a reusable SwiftUI control. Now let’s look at how we might start creating packages to allow us to share such library code.

Creating a Swift Package

From Xcode, select File | New | Swift Package. A very basic package is created (mine’s name MyLibrary) with a Sources/YouPackageName/YourPackageName.swift file containing the following code

struct MyLibrary {
    var text = "Hello, World!"
}

We’ll stick with this simple bit of code but make the struct and the text var public. Also we’ll need to add a public init method or you’ll see an error such as this

initializer is inaccessible due to ‘internal’ protection level

So the new code looks like this

public struct MyLibrary {
    public var text = "Hello, World!"
    
    public init() {
    }
}

Now use Command + B to build the package.

Local Package

To use the package locally, i.e. not having it deployed to a remote repos or the likes.

Within the application that you wish to use the package, simply (using Finder) select the package folder (i..e mine’s MyLibrary) and drag and drop this into your application under the top level project node in the Project Navigator.

Now we can use the code by simply importing it, for example

import MyLibrary

and now within your code

let text = MyLibrary().text

Making our package more useful

Let’s now move the code for our CircleImage into the package, we’ll leave the package name and therefore the component will be renamed, as MyLibrary

Here’s the code

import SwiftUI

@available(iOS 13, *)
public struct MyLibrary: View {
    var image: Image
    var borderColor: Color
    var shadowRadius: CGFloat

    public var body: some View {
        image
            .clipShape(Circle())
            .overlay(Circle().stroke(borderColor, lineWidth: 4))
            .shadow(radius: shadowRadius)
    }
    
    public init(image: Image,
                borderColor: Color = .white,
                shadowRadius: CGFloat = 10) {
        self.image = image
        self.borderColor = borderColor
        self.shadowRadius = shadowRadius
    }
}

In the above we’ve removed the public keyword on the fields and instead relied on the init method to set up any defaults. We also need to mark the code with the @available attribute to state what versions of OSX or iOS is supported, for example Image is available in 13.0 of iOS.

Within the package file Package.swift we also add the platforms value, here’s a snippet of my code, showing where to expect the platforms value

...
    name: "MyLibrary",
    platforms: [
        .macOS(.v10_15),
        .iOS(.v13),
    ],
    products: [
...

and in our application we now simply use something like the following

MyLibrary(image: landmark.image)
   .offset(x: 0, y: -130)
   .padding(.bottom, -130)

We’ll look at using GitHub or the likes to host our package in a subsequent post, but this gives an idea on how to get something up and running.