Tips around resources of Swift Package Manager for library creators for iOS

Introduction

Recently, many iOS app libraries support Swift Package Manager (Swift PM). Xcode 11 has more support for Swift PM, making it easier to deploy From Swift 5.3, resources other than code can be managed by Swift PM.

Nowadays, I think many people are using it with the feeling that it can be used normally.

For me, it is quite big that it became possible to automatically manage the library with Xcode because it was incorporated into Xcode. Now I'm basically introducing the library with Swift PM.

It's a Swift PM that can be used very conveniently like that, but what about the creator? From the experience of supporting Swift PM in some libraries, I felt that I have a strong habit around resources.

Therefore, I will summarize the points that did not actually go smoothly as tips.

Tips

Limited types of resources are automatically entered

In the first place, if you create `` `Package.swiftin a project that includes resources, how do you specify the resources ...?, But you don't have to specify anything.targetofsourceless thanxcassetsOrstoryboard```If you put in such things, it will be put in without permission when you install the library on xcode.

let package = Package(
    name: "HogeLibrary",
    platforms: [
        .iOS(.v14)
    ],
    products: [
        .library(name: "HogeLibrary", targets: ["HogeLibrary"])
    ]
    targets: [
        .target(name: "HogeLibrary", path: "Sources")
    ]
)

However, only a small part of it will come in without permission, for example, json files are not included. What should I do with such files?

Need to be added.


```swift
targets: [
    .target(name: "HogeLibrary", path: "Sources", resources: [.copy("./hoge.json")])
]

If you're having trouble getting resources, try something like this.

mlmodel needs to be compiled

If you think that it is okay if it is a resource that is specially treated like iOS, you will stumble in an unexpected place. In my case, it became a hassle when supporting a library that has `` `.mlmodel``` for SwiftPM.

.mlmodel cannot be automatically installed as a library in SwiftPM.


 So, what to do, you need to compile to `` `.mlmodelc``` in advance.

xcrun coremlcompiler compile HogeModel.mlmodel HogeModel.mlmodelc


 And as with json, specify it as `` `resources```.

```swift
targets: [
    .target(name: "HogeLibrary", path: "Sources", resources: [.copy("./HogeModel.mlmodelc")])
]

However, inconvenience occurs here.

.Introducing it as mlmodelc is IF.Automatic generation of swift class etc. is not done on the introduction side.


 Therefore, if you want to insert `` `.mlmodel``` in SwiftPM, copy the Swift class that will be the IF of the automatically generated mlmodel once and pass `` `.mlmodelc``` to that class. Need to be.

 It's a bit of a hassle when you need to modify your code to accommodate a particular package manager.

## Bundle specification needs to be separated by Swift Flag
 Having the above ``` .mlmodel``` as a library may be a special case.
 Usually, I think that there are many storyboards and xibs, so you may think that you do not have to think about anything in particular, but that is not the case.

 It's nice that the Storyboard comes in automatically, but when I try to initialize the Storyboard with the `` `UIStorybard``` class, it crashes.

 The reason is that SwiftPM needs to specify a Bundle dedicated to SwiftPM.
 When creating a library, you should be careful not to use the ``` .main``` bundle.
 Therefore, I think that many people use the following initializers.

- [Bundle.init(for:)](https://developer.apple.com/documentation/foundation/bundle/1417717-init)
- [Bundle.init(identifier:)](https://developer.apple.com/documentation/foundation/bundle/1411929-init)

 In the case of SwiftPM, these will return nil. So what to do is use ↓ instead.

- Bundle.moudle

 You might wonder, "It's not listed in the [API docs](https://developer.apple.com/documentation/foundation/bundle), but what is this?"
 This is a Static variable dedicated to SwiftPM, which is used to get the resources installed via Package.swift.

- [Bundling Resources with a Swift Package](https://developer.apple.com/documentation/swift_packages/bundling_resources_with_a_swift_package)

 Since it is for SwiftPM only, an error will occur even if you call it directly on Xcode. When using it, do as ↓.

```swift
#if SWIFT_PACKAGE
      return Bundle.module
#else
      return Bundle(for: HogeViewController.self)
#endif

This area is also a little troublesome because it requires rewriting the code for Swift PM.

Module must be specified on Storyboard

This is just a messy guy to deal with. In SwiftPM, if you do not explicitly specify the ↓ part on Storyboard / XIB, the property of IBOutlet will be nil. If defined as an IUO (as is the case in most cases), any omission will cause a crash.

スクリーンショット 2020-12-17 21.10.26.png

Let's respond politely.

You must add inherit module from target on Storyboard

I named all of them Modules! Perfect! It's still useless. Let's check all the `Inherit Module From Target` below it. Failure to do so will also cause a crash.

スクリーンショット 2020-12-17 21.12.13.png

Let's deal with this carefully as well.

Summary

In addition, there are some small points such as the settings are not reflected when creating as a dynamic framework from xcode. I'm used to this area, but when I try it, I may feel that "that ...? SwiftPM may be a little unwieldy ...".

However, as a user, it is very easy to introduce SwiftPM compatible libraries, so I would be grateful if more and more libraries are supported! I think (laughs)

Recommended Posts

Tips around resources of Swift Package Manager for library creators for iOS
[Swift] Acquisition of IDFA on iOS14