Swift Package Manager - Distribute an already existing Cocoapod - ios

I want to make my already existing Cocoapods available also as Swift Package.
Here's the thing. One of my pods depending on another, so I added this to my Swift package :
// swift-tools-version:5.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Luminous",
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "Luminous",
targets: ["Luminous"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.package(
url: "https://github.com/andrealufino/Deviice.git",
from: "1.30.2"
)
],
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: "Luminous",
dependencies: [],
path: "Sources"),
.testTarget(
name: "LuminousTests",
dependencies: ["Luminous"]),
]
)
My other question is : why the Example folder is included when the package is installed? Here's the pic.
Moreover, last thing, when I build my project in which I added the package, it fails because it cannot find the module for the dependency. The error is No such module Deviice.
I think I added enough details, if you need more, just ask.

I'll answer about the Deviice not found. The other issues are about local paths.
You can see your package as such (In the next comment, "Package" can be understood as library, but also as an executable, for tests purpose often in the case of "sub packages", or "real executables".
let package = Package(
name: "Luminous", // Name of your package
products: [], // What packages people will see relying on internal sub-packages
dependencies: [], // External packages you relies on
targets: [] // Internal "sub-packages", etc.
)
Each target has a dependencies: [], that's where you put the name of either other targets (which are "internal", or public one, that you stated before in dependencies[].
.target(
name: "Luminous",
dependencies: [], //Put here names of either sub packages OR public package you "called before"
path: "Sources")
In your case:
.target(
name: "Luminous",
dependencies: ["Deviice"],
path: "Sources")
Indeed you wrote yourself:
.testTarget(
name: "LuminousTests",
dependencies: ["Luminous"])
So you stated that it depends on the sub package "Luminous", same logic here with Deviice.
You can use as an example the Package of Alamofire+Image. It uses as an external dependency Alamofire, and put it as such.

Related

How to add dependency for xcframeworks in SPM Package

I have created xcframework for.eg. MobileCoreFramework and distributed it through MobileCoreSPM,
here is MobilecoreSPM package,
name: "MobileCoreSPM",
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "MobileCoreSPM",
targets: ["MobileCoreSPM","MobileCoreFramework"]),
],
dependencies: [
],
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: "MobileCoreSPM",
dependencies: ["MobileCoreFramework"]),
.binaryTarget(name: "MobileCoreFramework", path: "Artifacts/MobileCoreFramework.xcframework"),
]
)
then created another XCframework i.e. BillpayFramework which depends on MobileCoreFramework, here when creating BillpayFramework, I used MobileCoreSPM as dependent package and used MobilecoreMethods inside Billpay class, which was working fine.
but when tried to distribute BillpayFramework through BillpaySPM, error is displayed like it x-product 'MobileCoreFramework' required by package 'billpaylib' target 'BillpaySPM' not found.
let package = Package(
name: "BillpaySPM",
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "BillpaySPM",
targets: ["BillpaySPM"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(path: "/Users/com/Documents/POC/Try2/MobileCoreLib"),
],
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: "BillpaySPM",
dependencies: ["BillpayFramework","MobileCoreFramework",
]),
.binaryTarget(name: "BillpayFramework", path: "Artifacts/BillpayFramework.xcframework"),
]
)
And I am trying all this in my machine locally, didnt host it in github yet, hence linked everything through localpath.
Error:
product 'MobileCoreFramework' required by package 'billpaylib' target 'BillpaySPM' not found.
enter image description here
you need to specify the name of the dependent library if it's not identical with package name:
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: "BillpaySPM",
dependencies: [
"BillpayFramework",
.product(name: "MobileCoreFramework", package: "MobileCoreLib"),
]),
...

Swift Package Resolution failed because multiple targets named a same framework

I have 2 local Swift Packages: LibA and LibB.
Both LibA and LibB depends on a same framework(AmazonIVSPlayer).
I want to add both of the into my Project but I got the below error:
Multiple targets named 'AmazonIVSPlayer' in LibA and LibB
the Package.swift of both libraries are like below:
import PackageDescription
let package = Package(
name: "LibA",
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "LibA",
targets: ["LibA","AmazonIVSPlayern"]),
],
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: "LibA",
dependencies: []),
.binaryTarget(
name: "AmazonIVSPlayer",
url: "https://player.live-video.net/1.8.1/AmazonIVSPlayer.xcframework.zip",
checksum: "8256f9f580fdb09b156afad43cd17dd120091c794e848b27aad83c1a098ecc7f")
]
)
I read
Swift Package Manager: "multiple targets named..."
Swift Package Manager (SPM) and Cocoapod Dependency Conflict
Swift packages and conflicting dependencies
https://forums.swift.org/t/multiple-target-issue-with-spm/16696
https://www.reddit.com/r/swift/comments/d4wwbk/question_about_dependency_conflicts_in_swift
Since none of them offer any solution and all posts are old, I am wondering is there any new way to solve this issue?
I am also searching for a solution for this problem. The only way I found to work around this, is to create a git repository, put the xcframework (in your case AmazonIVSPlayer) there and a Package.swift. The Package.swift in the newly created repo would look like that:
let package = Package(
name: "AmazonIVSPlayer",
products: [
.library(
name: "AmazonIVSPlayer",
targets: ["AmazonIVSPlayer"]
)
],
targets: [
.binaryTarget(name: "AmazonIVSPlayer", path: "AmazonIVSPlayer.xcframework")
]
)
Then remove the binaryTarget from LibA and LibB and add the following to the dependencies:
.package(url: "https://github.com/foo/bar.git", from: "1.8.1")
Don't forget to create a tag for the version number.
Then add the following to the target dependencies:
.product(name: "AmazonIVSPlayer", package: "bar"),
That way you can use AmazonIVSPlayer in LibA and LibB and can add both Libs to the same project without getting an error. Not the easiest solution, but the only one which works for me.
The error you are getting indicating that you are using two products that have module that conflicts with another products module name. The solution you could try:
If the module causing the name conflict are same (contain the same code and files), then you can create a separate package for the module, in this case a separate package for AmazonIVSPlayer could be created:
import PackageDescription
let package = Package(
name: "AmazonIVSPlayer",
products: [
.library(
name: "AmazonIVSPlayer",
targets: ["AmazonIVSPlayern"]),
],
dependencies: [],
targets: [
.binaryTarget(
name: "AmazonIVSPlayer",
url: "https://player.live-video.net/1.8.1/AmazonIVSPlayer.xcframework.zip",
checksum: "8256f9f580fdb09b156afad43cd17dd120091c794e848b27aad83c1a098ecc7f")
]
)
Alternatively, you can combine the package manifest of LibA and LibB into a single package and expose both of them as multiple products:
import PackageDescription
let package = Package(
name: "LibAB",
products: [
.library(
name: "LibA",
targets: ["LibA","AmazonIVSPlayern"]),
.library(
name: "LibB",
targets: ["LibB","AmazonIVSPlayern"]),
],
dependencies: [],
targets: [
.target(
name: "LibA",
dependencies: []),
.target(
name: "LibB",
dependencies: []),
.binaryTarget(
name: "AmazonIVSPlayer",
url: "https://player.live-video.net/1.8.1/AmazonIVSPlayer.xcframework.zip",
checksum: "8256f9f580fdb09b156afad43cd17dd120091c794e848b27aad83c1a098ecc7f")
]
)
Now for the scenarios where both modules are actually different, with swift 5.7 you will be able to differentiate them with module aliases. So with your current package description, when consuming:
targets: [
.executableTarget(
name: "App",
dependencies: [
.product(name: "LibA", package: "LibA"),
.product(name: "LibB", package: "LibB", moduleAliases: ["AmazonIVSPlayer": "AmazonIVSPlayerFromLibB"]),
])
]
When importing module you have to provide the alias name that you have specified:
import AmazonIVSPlayer // imports from LibA
import AmazonIVSPlayerFromLibB // imports from LibB
I've just edited project.pbxproj, and find the target that has the framework added with SPM inside packageProductDependencies list, and I've copied that line to the target that's missing that.
Something like:
name = "Target 1";
38D300792549B0C600FDEFA8 /* UIKit Extensions */,
Copied that line of the framework in the other target
name = "Target 2";
38D300792549B0C600FDEFA8 /* UIKit Extensions */,

Firebase [Swift Package Manager]: no such module FirebaseRemoteConfig

After I read the instructions listed here for how to add Firebase as a dependency to a Swift package, I couldn't get it to work, here's my Package.swift manifest:
import PackageDescription
let package = Package(
name: "MyPackage",
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "MyPackage",
targets: ["MyPackage"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
.package(name: "Firebase",
url: "https://github.com/firebase/firebase-ios-sdk.git",
.upToNextMajor(from: "8.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: "MyPackage",
dependencies: [.product(name: "FirebaseRemoteConfig", package: "Firebase")]),
.testTarget(
name: "MyPackageTests",
dependencies: ["MyPackage"]),
]
)
the package graph resolves without problems, but when I try to add my own code in Sources/MyPackage.swift starting with import FirebaseRemoteConfig the compiler complains with:
No such model 'FirebaseRemoteConfig'.
what's went wrong with my setup ?
I figured out the solution, but unfortunately it's not documented on Firebase Docs, I have to add the .platforms array in the Package.swift manifest specifying a version that supports FirebaseRemoteConfig, for example:
platforms: [
.iOS(.v13)
]

Import local SPM Library in local SPM package

I have a local SPM package that contains 2 libraries, and I want to import one of those libraries in another local SPM package :
File containing the libraries:
let package = Package(
name: "LocationService",
platforms: [.iOS(.v13)],
products: [
.library(
name: "LocationService",
type: .dynamic,
targets: ["LocationService"]),
.library(
name: "LocationLiveClient",
type: .dynamic,
targets: ["LocationLiveClient"]),
],
targets: [
.target(
name: "LocationService",
dependencies: []),
.target(
name: "LocationLiveClient",
dependencies: ["LocationService"],
path: "Sources/LocationLiveClient"),
]
)
File importing the libraries:
let package = Package(
name: "HomePage",
products: [
.library(
name: "HomePage",
type: .dynamic,
targets: ["HomePage"])
],
dependencies: [
.package(path: "../RouterService"),
.package(path: "../LocationService/Sources/LocationLiveClient"),
],
targets: [
.target(
name: "HomePage",
dependencies: ["RouterService", "LocationLiveClient"])
]
)
There are a couple of issues to resolve here.
(If a requirement of your design is to use 'dynamic' linking, then this approach may not work for you.)
type: .dynamic:
Unless you absolutely need to guarantee how library linking is achieved, it is recommended that you leave this as the default value of nil (just remove the line). This allows the swift package manager to determine how to best link the libraries (the default being 'static').
.package(path: "../LocationService/Sources/LocationLiveClient"),
LocationLiveClient is a product & target of the LocationService package. In the dependencies here, a reference to the package as a whole should be made. So change this to .package(path: "../LocationService"),
dependencies: ["RouterService", "LocationLiveClient"])
Once the change to depend on the whole location service package, the compiler needs a little extra information. You can update your target dependencies to specifically use the LocationLiveClient library in the LocationService package: .product(name: "LocationLiveClient", package: "LocationService").
With those changes in place you end up with a Package definition like this:
let package = Package(
name: "HomePage",
products: [
.library(
name: "HomePage",
targets: ["HomePage"]),
],
dependencies: [
.package(path: "../RouterService"),
.package(path: "../LocationService"),
],
targets: [
.target(
name: "HomePage",
dependencies: [
"RouterService",
.product(name: "LocationLiveClient", package: "LocationService")
]
),
]
)
You should then be able to import LocationLiveClient as expected.
Side note: Assuming your 'LocationService' package has the following folder structure, then you can safely remove path: "Sources/LocationLiveClient" from your LocationLiveClient target definition.
LocationService
-> Sources
-> LocationService
-> LocationLiveClient

How do I declare the Siesta Swift package as a dependency of another Swift package?

I'm trying to use the Swift package Siesta as a dependency for the package I'm building and reference it in my package code. I've identified how to import the package into my project in my Package.swift file which is simple enough:
dependencies: [
.package(url: "https://github.com/bustoutsolutions/siesta", from: "1.5.1")
],
This causes the package to be copied into my package just fine. The problem I'm having is actually linking it up to my package so I can import it and reference it in code. I know I need to actually link it up to my target
I've read some other package files and because the package name for Siesta is like this
let package = Package(
name: "Siesta",
And the products it declares are like this
products: [
.library(name: "Siesta", targets: ["Siesta"]),
.library(name: "SiestaUI", targets: ["SiestaUI"]),
.library(name: "Siesta_Alamofire", targets: ["Siesta_Alamofire"]),
],
I should be able to just do this in my package file's target to use it
.target(
name: "MyTarget",
dependencies: [.product(name: "Siesta", package: "Siesta")]),
But when I try to build my package, I get an error:
/Users/blahblah/Desktop/MyPackage/Package.swift: unknown package 'Siesta' in dependencies of target 'MyTarget'
And not only that, all the targets for my single run scheme on my package go missing and I can't build again without discarding all my local version control changes. What's going on here?
With Swift tools version 5.2 you have to provide a name argument when declaring your package dependency.
.package(name: "Siesta", url: "https://github.com/bustoutsolutions/siesta", from: "1.5.1")
A working example of a Package.swift file:
// swift-tools-version:5.2
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "MyPackage",
products: [
.library(
name: "MyLibrary",
targets: ["MyTarget"]),
],
dependencies: [
// make sure to provide a `name` argument here
.package(name: "Siesta", url: "https://github.com/bustoutsolutions/siesta", from: "1.5.1")
],
targets: [
.target(
name: "MyTarget",
dependencies: [
.product(name: "Siesta", package: "Siesta")
]),
]
)
Source: https://forums.swift.org/t/package-names-in-swift-5-2/34886/6

Resources