Add Swift Package Manager support#10
Add Swift Package Manager support#10douglashill merged 1 commit intodouglashill:swiftpmfrom sebj:swift-package
Conversation
|
Thank you. I'll try to look over this before Swift 5.3 is out. |
|
Just upped the minimum Swift tools version to 5.3 and added support for the localised string assets – tested out in a SPM project, seemed to work well! Created a symbolic link to the KeyboardKit/Localised folder at KeyboardKit/SwiftSources/Localised, as the |
douglashill
left a comment
There was a problem hiding this comment.
Thank you for getting this together. I tested it and everything seems to work.
If possible, I would prefer if we could avoid moving so much stuff around. I think it should work to leave the Swift files alone and just move the Objective-C files into a subdirectory. (I experimented in https://github.com/douglashill/KeyboardKit/tree/swiftpm and I think that approach should work although I didn’t get it all building yet.)
Did you find a way to test SwiftPM locally, or does it seem to be necessary to push to GitHub after each change?
| inputPaths = ( | ||
| "$(SRCROOT)/KeyboardKit/Localised/en.lproj/Localizable.strings", | ||
| "$(SRCROOT)/KeyboardKit/UpdateLocalisedStringKeys.swift", | ||
| "$(SRCROOT)/KeyboardKit/Localised/en.lproj/KeyboardKit.strings", |
There was a problem hiding this comment.
Good spot! This is broken on the main branch.
| 96A241CA2495417600C77B57 /* ScrollViewKeyHandler.swift in Sources */, | ||
| 96A241C22495417600C77B57 /* SelectableCollectionKeyHandler.swift in Sources */, | ||
| 96A241C12495417600C77B57 /* KeyboardTabBarController.swift in Sources */, | ||
| 96A241BD2495417600C77B57 /* ResponderChainDebugging.m in Sources */, |
There was a problem hiding this comment.
It looks like a lot of files have been removed and re-added to the project. Is it possible to move these and retain the existing references in the project. I have some private WIP branches that will likely have conflicts otherwise.
The order of the files has changed. The files are roughly ordered by importance and scope (more general classes like KeyboardApplication near the bottom) so it would be nice to preserve that.
I’m not particularly keen on moving so much stuff around (both on disk and in the Xcode project) because I feel it makes the hierarchy unnecessarily deep for a framework of this size. Could we instead leave all the Swift files where they are and only move the Objective-C files into a subdirectory (called ObjC or something). I would create have this subdirectory on disk, not as a group in the Xcode project. The Swift SwiftPM target could then exclude that directory while the Objective-C SwiftPM target could have its path set to this subdirectory. Do you think this would work?
| @@ -0,0 +1,2 @@ | |||
| #import "BarButtonItem.h" | |||
There was a problem hiding this comment.
These contortions to work with SwiftPM are unfortunate, but I haven’t been able to work out a better way. 😞
For this file, I think it would be a bit nicer to use
#if SWIFT_PACKAGE
#import "BarButtonItem.h"
#else
#import <KeyboardKit/BarButtonItem.h>
#endifin the existing umbrella header rather than added a second alternative umbrella header. That way it matches the pattern used in BarButtonItem.m to deal with this problem.
There was a problem hiding this comment.
You’re completely right – I forked off your swiftpm branch locally and seem to have gotten it working with the single existing umbrella header (left a full comment further below).
| @@ -0,0 +1 @@ | |||
| ../Localised No newline at end of file | |||
There was a problem hiding this comment.
If the Swift source files are changed to stay in their previous location (KeyboardKit rather than KeyboardKit/SwiftSources) then I think this can be removed?
| import Foundation | ||
|
|
||
| #if SWIFT_PACKAGE | ||
| private let keyboardKitBundle = Bundle.module |
There was a problem hiding this comment.
Tangent:
Out of interest I had a look what Bundle.module actually does, and it’s like this:
import class Foundation.Bundle
private class BundleFinder {}
extension Foundation.Bundle {
/// Returns the resource bundle associated with the current Swift module.
static var module: Bundle = {
let bundleName = "KeyboardKit_KeyboardKit"
let candidates = [
// Bundle should be present here when the package is linked into an App.
Bundle.main.resourceURL,
// Bundle should be present here when the package is linked into a framework.
Bundle(for: BundleFinder.self).resourceURL,
// For command-line tools.
Bundle.main.bundleURL,
]
for candidate in candidates {
let bundlePath = candidate?.appendingPathComponent(bundleName + ".bundle")
if let bundle = bundlePath.flatMap(Bundle.init(url:)) {
return bundle
}
}
fatalError("unable to find bundle named KeyboardKit_KeyboardKit")
}()
}So it looks like SwiftPM doesn’t make a framework for KeyboardKit. Instead the KeyboardKit classes are directly in the app bundle and there is a separate (code-free) bundle for the resources.
I might rename rename Marker to BundleFinder to be consistent with how SwiftPM implemented similar functionality.
| name: "KeyboardKit", | ||
| defaultLocalization: "en", | ||
| platforms: [ | ||
| .iOS(.v13) |
There was a problem hiding this comment.
Is there any reason not to set this back to iOS 11 to be consistent with the the Xcode project and CocoaPods?
(Although I’ll probably bump this from 11 to 12 very soon.)
There was a problem hiding this comment.
No reason, this should indeed be iOS 11
| name: "KeyboardKitObjC", | ||
| path: "KeyboardKit/ObjCSources", | ||
| exclude: ["ResponderChainDebugging.m"], | ||
| publicHeadersPath: ""), |
There was a problem hiding this comment.
Is there a reason for this empty string?
| publicHeadersPath: ""), | |
| ), |
There was a problem hiding this comment.
Without explicitly setting this path (i.e. it being the default value of nil), SwiftPM uses the default umbrella directory component of include and appends this value to the target path (KeyboardKit/ObjSources), giving KeyboardKit/ObjCSources/include as the public headers path.
Setting it to an empty string ensures KeyboardKit/ObjCSources is used as the public headers directory.
| path: "KeyboardKit/SwiftSources", | ||
| exclude: ["UpdateLocalisedStringKeys.swift"], |
There was a problem hiding this comment.
What I asked about above is basically like this I think:
| path: "KeyboardKit/SwiftSources", | |
| exclude: ["UpdateLocalisedStringKeys.swift"], | |
| path: "KeyboardKit", | |
| exclude: ["ObjC", "UpdateLocalisedStringKeys.swift"], |
| dependencies: ["KeyboardKitObjC"], | ||
| path: "KeyboardKit/SwiftSources", | ||
| exclude: ["UpdateLocalisedStringKeys.swift"], | ||
| resources: [.process("Localised")]), |
There was a problem hiding this comment.
I think this can be omitted because SwiftPM infers that .lproj directories are localised resources.
There was a problem hiding this comment.
You’re totally right, thanks!
|
|
||
| CocoaPods may not be as well tested as the recommended steps above. Please [open a pull request](https://github.com/douglashill/KeyboardKit/pulls) if you notice any problems. | ||
|
|
||
| ### Swift Package Manager |
There was a problem hiding this comment.
This section can go just above CocoaPods if you like.
|
@douglashill Thanks for the feedback! Makes a lot of sense. Completely agree with your assessment that it’d be better not to move so many files around. I was able to test the Swift Package in a local project by dragging the local repo folder into Xcode’s navigator with a project open, at which point it’s recognised as a package and the library just has to be added to the app target. Seems there’s only a minimal set of changes on top of your |
douglashill
left a comment
There was a problem hiding this comment.
Looks good. Thank you @sebj.
I didn’t want to undercut what you did before but I haven’t worked with SwiftPM before so needed to dig in a bit to learn it. Your original branch was really helpful for me to understand how it all works.
Sorry I’ve been a bit slow getting to this. Lots of stuff going on after WWDC!
|
@douglashill All good, totally understand! Thanks for merging! :) |
(WIP) Added Swift Package Manager support, to resolve #9
As SPM targets can't contain 'mixed' Objective-C and Swift code, I've separated code into two source folders (ObjCSources and SwiftSources), with the main Swift library target depending on the ObjC target. This only requires the ObjC folder be excluded from the Swift target, and vice-versa for the ObjC target.
The other approach would have been to keep the existing file/folder structure, but define each and every file individually as excluded inside the
Package.swiftfile.Remaining issues: