Swift Package Manager Problem With Bundle IDs - swift

I'm pretty sure that SPM has the ability to fix this issue, but I am having a hard time finding it. I am quite sure that "I'm not holding it right."
I'm quite new to SPM, and am still struggling with its syntax and methodology.
Maybe all that needs to happen, is for someone to direct me to the appropriate PackageDescription docs (which I can't seem to find).
I am in the process of switching an app I developed over to use SPM for a few libraries that I also wrote. It has been using Carthage, and the libraries were added as simple source files (they are all single-source-file dependencies).
Everything works great...except that I get an App Store Upload rejection.
It does not like the bundle IDs for the embedded libraries. They have underscores in the project name, and I should replace those with dashes.
These libraries (this one, this one, and this one), are not really designed to be delivered as libraries. They are really single source files. It looks like SPM builds them into a library, but I don't really provide an Info.plist for the build.
Can anyone give me any guidance over how I can control the bundle IDs, while leaving the module names the same?
For the record, here are the errors I get:

OK. I figured it out.
First, the docs for SPM...leave something to be desired. I had to find this out by trial-and-error (LOTS of error).
In the Package.swift file, I had this (for one of my dependencies):
// swift-tools-version:5.2
import PackageDescription
let package = Package(
name: "RVS_Generic_Swift_Toolbox",
products: [
.library(
name: "RVS_Generic_Swift_Toolbox",
type: .dynamic,
targets: ["RVS_Generic_Swift_Toolbox"]),
],
targets: [
.target(
name: "RVS_Generic_Swift_Toolbox",
path: "./src")
]
)
Apparently, SPM uses the .library.name property as the BundleID. If I changed it, like so:
// swift-tools-version:5.2
import PackageDescription
let package = Package(
name: "RVS_Generic_Swift_Toolbox",
products: [
.library(
name: "RVS-Generic-Swift-Toolbox",
type: .dynamic,
targets: ["RVS_Generic_Swift_Toolbox"]),
],
targets: [
.target(
name: "RVS_Generic_Swift_Toolbox",
path: "./src")
]
)
Then, it would allow the upload, and I would still be able to do the import RVS_Generic_Swift_Toolbox.
Also, there's a bad cache issue. I had to delete EVERYTHING to make sure that the proper version was loaded.

Related

swift-package: unable to add json to the package manifest

I just can't believe how unintuitive this process is and how complicated and convoluted #apple has made this normally simple process.
I've been spending the past 2 hours trying to add a test suite json file for some offline tests on my new package. I tried looking at the official apple way and another source on the internet but nothing works.
I'm just trying to add the following:
.target(
name: "testJSON",
resources: [
.copy("test.json")
]
)
In the package manifest, which is below:
let package = Package(
name: "SwiftHorizons",
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "SwiftHorizons",
targets: ["SwiftHorizons"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "SwiftHorizons",
dependencies: []),
.testTarget(
name: "SwiftHorizonsTests",
dependencies: ["SwiftHorizons"]),
]
)
The file is in the sources folder at the moment. I tried putting it in the test folder, just the file itself, everywhere. None work, either give me an error message or none but when running the test suite, 0 tests are run.
This is the most stupid non work morning I have ever experienced with an apple product.

How to create an SPM package based on ObjC code?

I'd like to create a SwiftPackageManager library based on Objective-C code but I can't seem to grasp what I'm missing.
My latest change to just vanilla ObjC interface .h file inside the include folder was to add an extra C header that includes de ObjC but still had no success. What am I missing?
The Package.swift file is the default generated one and from what I read it should automatically generate the module map from the include folder.
My swift-tools-version is 5.5
Figured it out.
I added a modulemap that specifies my ObjC header and it worked
Not sure if it is the correct way to do it since the include folder should already do this automatically.
So just had the same issue. (my 5 cent)
This is may Package.swift:
// swift-tools-version: 5.7
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "AlgorithmSDK",
platforms: [
.iOS(.v13)
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages. , "AlgorithmSDKObjc"
.library(
name: "AlgorithmSDK",
targets: ["AlgorithmSDK","AlgorithmSDKObjc" ]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "AlgorithmSDK",
dependencies: []),
.testTarget(
name: "AlgorithmSDKTests",
dependencies: ["AlgorithmSDK"]),
.target(
name: "AlgorithmSDKObjc",
dependencies: [],
publicHeadersPath:"include"),//<----- This path is relative to the target! (and can be ignored)
]
)
With the structure:
The publicHeadersPath should be publicHeadersPath:"include" OR ignored according to docs (it seems that it takes it relative to target and not the root). I don't think we should touch module.modulemap for such a simple structure

Swift Package - How to exclude files in root git directory from the actual Swift Package?

I am creating a Swift Package that is essentially a wrapper for multiple XCFrameworks generated from Objective-C frameworks so they can be installed via SPM.
Everything works fine as far as creating the SP and ability to add it as a dependency to an app. But I have a bunch non-essential files included in the SP's repository that I don't want to include in the actual SP - i.e. They shouldn't show up in Xcode's navigator when the SP is added as a dependency.
(These consist of the source Obj-C Frameworks, README, Changelog, Xcode Workspace for demo app, Script files for generating the XCFrameworks, etc).
Is this even possible?
Or will SPM always checkout the entire repo and make all files visible to the user?
I have tried using various permutations of the Target specifiers: source, path, exclude but to no avail.
Here is the closest I can get with a valid manifest, but when I check out the SP in a dummy Xcode app, I can still see all the files from the repo included:
// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "WrapperSwiftPackage",
platforms: [.iOS(.v13)],
products: [
.library(name: "WrapperSwiftPackage", targets: ["WrapperSwiftPackage"])
],
dependencies: [],
targets: [
.target(
name: "WrapperSwiftPackage",
dependencies: [
"ObjCFramework1",
"ObjCFramework2"
],
path: "", // Set to root directory so we can exclude files below
exclude: [
"CHANGELOG.md",
"Dangerfile.swift",
"README.md",
"Workspace.xcworkspace",
"Scripts/generate-xcframework.sh",
"Scripts/link_git_hooks.sh",
"Objective-C Frameworks/"
],
sources: [
"Sources/WrapperSwiftPackage/main.swift",
"XCFrameworks/ObjCFramework1.xcframework",
"XCFrameworks/ObjCFramework2.xcframework"
]
),
.binaryTarget(name: "ObjCFramework1", path: "XCFrameworks/ObjCFramework1.xcframework"),
.binaryTarget(name: "ObjCFramework2", path: "XCFrameworks/ObjCFramework2.xcframework")
]
)
Not sure if that isn't a bug though, but I've accidentaly came up to one solution for this.
If you put an empty Package.swift (I mean, one like this):
// swift-tools-version:5.5
import PackageDescription
let package = Package()
into one of project subfolders, then even though SPM is checking the subfolder out, it's excluded from Xcode navigator, and thus, from the project visibility.
I would like to know if that's a bug or is it documented somewhere, every hint is appreciated.
Works with local and remote dependencies.

Swift Package manifest property 'defaultLocalization' not set

Experimenting with Swift Packages, I created a new package. Source files and resources from an existing Xcode project framework target were moved over into the new structure.
Attempting to build, the transcript shows an error:
manifest property 'defaultLocalization' not set; it is required in the presence of localized resources
How can this be solved so I can create a Swift package?
This is explained in WWDC2020 session 10169.
At around eleven and a half minutes into the video, Anders Bertelrud, Apple engineer Developer Tools introduces the topic. An example is shown using Xcode 12 to add a default localisation parameter to the package manifest.
This declares the language I'm using during development and will be
used as the fallback localization at runtime if no better match is
available. This is needed for any package that contains resources.
An example manifest including the defaultLocalization parameter can be seen as follows:
// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "MyPackageUI",
defaultLocalization: "en",
platforms: [
.iOS(.v13)
],
products: [
.library(
name: "MyPackageUI",
targets: ["MyPackageUI"]),
],
targets: [
.target(
name: "MyPackageUI",
dependencies: []),
.testTarget(
name: "MyPackageUITests",
dependencies: ["MyPackageUI"]),
]
)

How to use Swift Package Manager's binaryTarget?

I'm trying to use Swift Package Manager's binaryTarget to include the Stripe xcframework available here https://github.com/stripe/stripe-ios/releases/tag/v19.3.0. The package manager doesn't complain, and lets me link to it, but I can't import it im. I've made a sample repo to show it here https://github.com/martyu/StripePackageTest. Am I missing something?
First of all, your example is not testable because you have forgotten to provide a version tag, so this is not a real package.
Second, and more important, I think you have a misconception about how a package works as a binary target. You seem to think that your Swift Package can contain code that sees the XCFramework. (That's why you are trying to import in the framework module in the Sources code of the package.) That's wrong. It's the app that imports the framework module. The package is merely a way of distributing the framework.
In other words, you can write a source code package or a framework-bearing package. One package cannot be both.
But of course you can write a source code package that depends on a framework-bearing package.
First, you don't need a version tag for it to be "real package". You can specify package dependencies via commit SHA and branch as well. Also you can add local package repos in xcode via file://. Note, this is NOT the same as a local dev override.
I didn't have much luck with swift build but I did get it to work fine by creating an app in Xcode and adding the package to it. I think this is what #matt is getting at. You need to import it into a project (xcode, or another SP) and then xcode will assemble all the dependencies when it ~~builds~~ feels like it.
Here's the modified Package.swift I used. I changed the name to Example (as that's presumably the SDK you are building which depends on Stripe). You can include "Stripe" in the Example library's targets if you want it embedded in its framework. Otherwise the client app just needs to import it as well (via the tickboxes when you add it in Xcode, or via dependencies in another Package.swift).
// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Example",
platforms: [
.iOS(.v11)
],
products: [
.library(
name: "Example",
type: .dynamic,
targets: ["Example"]),
.library(
name: "Stripe",
targets: ["Stripe"])
],
dependencies: [],
targets: [
// I thought this was defining the Stripe binaryTarget...
.binaryTarget(name: "Stripe",
url: "https://github.com/stripe/stripe-ios/releases/download/v19.3.0/Stripe.xcframework.zip",
checksum: "fe459dd443beee5140018388fd6933e09b8787d5b473ec9c2234d75ff0d968bd"),
// ... and then linking it to the Example project here via "dependencies" ...
.target(name: "Example", dependencies: ["Stripe"], path: "Sources")
// ... so when I'm in "Example" files, I thought I'd be able to import "Stripe" to them
]
)