Don’t forget about Public in “Target Membership” for all platforms. Then let’s update “Build Settings” for each target:

Build Settings > Product Name > Remove the appended prefix.

All platforms will have an identical name, so they are packaged as one product.

Since we changed our plists location, we need to change the paths to them.

Build Settings > Packaking (Info.plist File) > Change the path to “Sources/HelloOpenSource/Supporting Files/Info.plist”.

I recommend to set “Require Only App-Extension-Safe API” to “Yes”. This will allow your framework to be used in extensions like the Today Widget.

Now we have four targets and I don’t like to build their separately to see any warnings / errors. For this purpose we will add general scheme, that builds all targets at once.

Click “New Scheme” > Set target to “None” and input the name > “Ok”.

Press the “+” button on the bottom and choose all platforms.

Now you can build this scheme and see all warnings / errors for all platforms right away!

Let’s add some code! Create a new file — Greeting.swift and choose all platforms. I want to point out, that it’s important to specify correct access level! Since we want to use this code outside our library, we need to add public or open access level. Differences between them is that public you can inherit within module only unlike open. In our case public — is enough.

Tests time!

For SPM we need to create Tests folder, what we already did. Also have to add test target — HelloOpenSourceTests as subfolder.

Then let’s add test targets within Xcode for all platforms. As you may notice, there is no watchOS test target, so you can’t test this by standard way. But you can use PivotalCoreKit for it — Watch Apps: How Do We Test Them? If you know better way, please, let me know. Ok, add iOS, tvOS and macOS test targets only.

As I mentioned early about usual targets, you also have to do the same things with the test targets. Finally you should get the following:

After that set correct plist paths for each test target.

Tests/HelloOpenSourceTests/Info.plist

Add MainTests.swift file with simple test cases. Paying attention on “Target Membership”.

If you look into all schemes list, you will see here a few useless schemes (tests schemes) IMO. It’s time to delete them!

Click “Manage Schemes” and uncheck all test targets. Great, we cleaned up here, but how to run test targets now?

Choose “iOS” scheme > Click “Edit Scheme” > Add test iOS target to “Test” menu item. Now you can run tests by “Command+U”.

Repeat this for all schemes.

In order to run tests on linux, we have to add LinuxMain.swift file.

LinuxMain.swift doesn’t have any target references. So, after that we have to have the following situation:

Let’s go create iOS example for checking that our library works correctly.

Create “Example” folder in the root directory > Create “Single View Application” here.

Now it’s time to create the HelloOpenSource.workspace. When you create it, drag’n drop HelloOpenSource.xcodeproj and HelloOpenSourceExample-iOS.xcodeproj files into the workspace within Xcode.

Then add HelloOpenSource.framework in “Linked Frameworks and Libraries” within Example project.

Whoooh, this works! My Congratulations! :)

In this tutorial we’ve written example only for iOS target, but you can create a big workspace with many examples. Do it!

Dependencies.

After that, when library is ready, we need to create comfortable ways of installing this one.

Carthage

For carthage all what we need is to mark our main schemes as shared (iOS, macOS, tvOS, watchOS). You can mark all schemes as shared, after that they all will be visible in the project, otherwise this schemes leave are local only — xcuserdata.

Swift Package Manager

As I said earlier that we will create another target later. So, it’s an executable target which just says hello to our platform ;)

By convention, a package containing a file named main.swift in its root directory produces an executable.

Also need to create Package.swift file.

Let’s check it. First, we build our library by special command: swift build. Then we can run tests by swift test.

What about our executable target? Awesome!

Cocoapods

Add .HelloOpenSource.podspec file to the root directory. I won’t explain all these .podspec items, I hope everything is understood. For more details check Podspec Syntax Reference.

Also need to add .swift-version file for correct working with Swift 3.

3.0 — content of this file

Next, we need to validate our library. Run pod lib lint. If everything is okay, you should see the following:

There is a similar command — pod spec lint. It validates remote pod, not local. When previous steps are completed, create release tag, which associated with our spec version and push to remote. It’s time to publish our library! For this purpose we will use CocoaPods Trunk.

CocoaPods Trunk is an authentication and CocoaPods API service. To publish new or updated libraries to CocoaPods for public release you will need to be registered with Trunk and have a valid Trunk session on your current device.

So, we need to register a session:

$ pod trunk register gnod94@gmail.com 'Nikita Ermolenko' --description='mac mini'

and final step…

pod trunk push [NAME.podspec] 🚀

Travis.

It’s a hosted, distributed continuous integration service used to build and test software projects hosted at GitHub. It’s free for public repositories.

It looks good, when someone want to contribute to your project, but forgot to change existing tests, for example. In this case travis immediately warning us about it.

You can watch the following, if tests pass… something like this:

Configure it! Go to travis-ci.org and sign in with Github. After that, click on avatar and you should see a list of all your public repos. Turn on the needed repo:

Now we have to configure .travis.yml file. It will be a simple configuration file — just check that tests pass. But you can create notification that notifies you when everything is okay, also can write validation of .podspec file that it’s configured right and so many other cool things, but it’s another article already ;)

Step by step: