Create a Universal Swift Framework for iOS, OS X, watchOS, and tvOS

In fact, macOS and iOS use the same programming language, but also have a number of common frameworks, common libraries, in the development of dual-platform applications, model and a lot of logic can be common, so there is a need for code sharing. Recently, I was working on an application with both macOS and iOS clients. I found this article in Medium and thought it was good, so I translated it.

Xcode 7.2 provides support for creating the Swift Framework for any platform (iOS, OS X, watchOS, tvOS).

However, Xcode does not provide the ability to create a common framework that supports multiple platforms at the same time.

The Universal Framework is one of the best ways to publish open libraries. In fact, thanks to the package management tool Carthage, developers who want to release a multiplatform library just need to make sure it compiles. Libraries that meet this need only require the developer to configure the corresponding Git URL in Carthage.

However, this method still lacks pleasure. Apple seems intent on replacing this monotonous process with Swift Package Manager, but it still has a long way to go in Beta. Here’s a step-by-step guide to creating a generic framework. I’ve explored it myself, but I’ve also referenced others. You will complete today’s tutorial in less than a few minutes.

Let ‘s go.

Step 1

Create a new Xcode project from the template and select:

iOS -> Framework & Library -> Cocoa Touch Framework

Step 2

Give your project a name and add “_iOS” after the name. Note that “Include Unit Tests Box” has been checked.

NOTE: Do not include “-” in your project name, as this will produce a target with the same name and a dash is an illegal name.

Don’t worry, we’ll change the project name later, and you can even come back and add dashes (although the iOS Target name will remain the same).

Step 3

From the Xcode top menu, go to File -> New -> Target

Step 4

Select the framework template for the platform you want to support. For example, we chose macOS:

OS X -> Framework & Library -> Cocoa Framework

Step 5

We then name the project as before, adding “_Mac” to the end of the project name:

Step 6

Repeat Steps 4 and 5 to add each platform you want to support

Step 7

Now we’ll start refactoring the framework of the project:

1, delete the “_Mac” folder and select “Move to Trash”

2. Open Finder, go to the project folder, and delete the “_Mac” folder.

3. Rename “ProjectName_iOS” to “CommonSource” and “ProjectName_iOSTests” to “CommonTests” in the current folder.

4. Go back to Xcode and delete those empty folders

5. Pull the CommonSource folder into the project and do not select any ‘Add to Target’.

6. Now rename the project, remove the “_iOS” suffix and change it to whatever name you want. Of course you can keep naming it that way.

If yes, it will remind you whether to Rename the project content. Select “Don’t Rename”.

7. Delete the extension name of projectname_ios. h

8. Now pull the CommonTests folder into the project. Again, don’t select any “Add to Target”

9. Close the Xcode project and delete the suffix “_iOS” from the project folder name. Your folder should look like this:

Step 8

So far, we have refactored the project structure.

Next we need to fix the target Memberships for the two files. Open up Xcode again.

1. Select CommonSource -> projectName. h file and in the configuration on the right hand side, select the unmarked Target Memberships and mark them as Public.

2, Select CommonTests -> swiftygmail_iostests. swift, also marked.

In this case, the file will report an error, you need to rename the reference library, delete the suffix “_iOS”

Before

After

Step 9

Select both targets in Build Setting, go to Packaging -> info.plist file and change it to CommonSource/ info.plist

Step 10

Select both targets in Build Setting, go to Packaging -> Product Name and change it to your project Name (no suffix).

(Optional) Step 11: Support Carthage

If you want to support Carthage for your framework, you need to change your Schemes to Shared

1. In the top left corner of the Xcode window click on current Scheme and then on Manage Schemes

2. Now mark each scheme as Shared

Pull in the damn source code.

OK, you are done with this article!

You can compile and test if your library supports the platform you want

When you add new source code, make sure it gets pulled to every platform you want. The same is true for unit test code.

The above text is translated.

The following is a summary of my step pits in the process of use to make a supplement.

Xcode 9 bugs

When you are using Xcode 9 with version 9A235 and drag the file into the project, even if you check Add to Taeget, the file is still not added correctly. In this case, you need to manually Add the file to the right of file -> project.

When creating the Swift framework, public methods must be marked as public. Details can be found in this article: Creating and Distributing iOS Frameworks

3. It is often necessary to determine the platform to reference the correct framework, such as Cocoa for macOS versus UIKit for iOS. In addition to references, some logic may also be judged. Swift and OC have different codes. Here is an example:

OC:
#if TARGET_OS_IPHONE
    #import <UIKit/UIKit.h>
#elif TARGET_OS_MAC
    #import <Cocoa/Cocoa.h>
#endif
Swift:
#if os(iOS)
    import UIKit
#elseif os(OSX)
    import Cocoa
#endifCopy the code

4. The model of Core Data cannot be shared in the framework, so the model cannot be loaded. What I do now is to put the model in the main project. (Please let me know if you have a better solution, thanks ~)


For more personal sharing, check out my less-updated tech blog, iOSHub. And then there’s the non-technical ChanTalk.