Add dependencies to binary targets in Swift Package Manager - ios

I want to create a Swift Package with binary targets which has sub dependencies. As the binary targets not support sub dependencies out of the box, I have created a wrapper target that depends on both the binary framework and other dependencies as described here
Package has a target called Logger.
CocoaLumberjack is a dependency of Logger.
Logger I have generated as XCFramwork and hosted in a server as publicly accessible. Below I have added a screenshot of the Xcode project which I used to generate XCFramwork.
Please refer to the Package manifest file.
import PackageDescription
let package = Package(
name: "spmpoc",
products: [
.library(
name: "Logger",
targets: ["LoggerTarget"]),
],
dependencies: [
.package(
name: "CocoaLumberjack",
url: "https://github.com/CocoaLumberjack/CocoaLumberjack.git",
from: "3.6.1"),
],
targets: [
.target(
name: "LoggerTarget",
dependencies: [.target(name: "LoggerWrapper",
condition: .when(platforms: [.iOS]))]
),
.target(
name: "LoggerWrapper",
dependencies: [
.target(name: "Logger", condition: .when(platforms: [.iOS])),
.product(name: "CocoaLumberjack", package: "CocoaLumberjack")
]
),
.binaryTarget(name: "Logger", url: "https://mypath.com/Logger.xcframework.zip", checksum: "mychecksum")
]
)
I am able to add Swift package via Swift Package Manager, but When I try to import Logger module build error occured as ..../Logger.framework/Modules/Logger.swiftmodule/arm64-apple-ios.swiftinterface:4:8: No such module 'CocoaLumberjack'
Could someone please help me to figure out what could be the issue here?
Error
XCFramwork code snapshot for reference
Update:
I have change import to #_implementationOnly import in Logger.swift. Now in the generated .swiftinterface files does not contains the "import CocoaLumberjack" hence, compile error went away. However, app crashing because it is still looking for CocoaLumberjack.framework but its not available. '.../Library/Developer/Xcode/DerivedData/TestSPMApp-gfbagjtzjrrkjuathrrienvklwxs/Build/Products/Debug-iphonesimulator/CocoaLumberjack.framework/CocoaLumberjack' (no such file)
CocoaLumberJack added to Logger framework as a pod dependency. It seems, inside the Pods-Logger.xcconfig file it is referring to CocoaLumberjack.framework. I believe this causes the issue now.

I think the real issue here is that the dependencies don't need to be a part of your modules's public interface. You would need to replace all instances of import for the dependencies in your code to #_implementationOnly import
E.g.
#_implementationOnly import CocoaLumberjack
You can read more about #_implementationOnly here

Related

SPM showing duplicate target name fatalError

I'm facing a problem with my lib using SPM.
I've developed it using a target into the project to test and works fine.
After finish I've added the lib using SPM into a final project using the branch develop and I was able to integrate lib and project.
When I saw that is all right, I made a tag from my lib and import into project using Up To Next Major (tag)
And using this way I'm getting this error:
I've checked all the code, compare Package.swift with other projects, change the name, change de folder and nothing.
Here my Package.swift
import PackageDescription
let package = Package(
name: "GloboUI",
platforms: [
.iOS(.v12)
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "GloboUI", targets: ["GloboUI"]),
],
dependencies: [
.package(url: "https://github.com/rechsteiner/Parchment", exact: "3.1.0"),
.package(url: "https://github.com/onevcat/Kingfisher.git", from: "7.0.0"),
.package(url: "https://github.com/airbnb/lottie-ios.git", from: "4.0.0"),
.package(url: "https://github.com/googleads/swift-package-manager-google-mobile-ads.git", from: "9.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: "GloboUI",
dependencies: [
.product(name: "GoogleMobileAds", package: "swift-package-manager-google-mobile-ads"),
.product(name: "Parchment", package: "Parchment"),
.product(name: "Kingfisher", package: "Kingfisher"),
.product(name: "Lottie", package: "lottie-ios")
],
path: "Sources/GloboUI"
)
]
)
I tried remove and change this path in target, change the target names...a lot of try
Here my folder structure of the lib
I've tried remove package.resolved form the main project, clean derivate data, cache, everything.
But I'm not know what is happening.
Anyone has a clue about this issue?
Regards

Add package dependency on library product

How can I add a 3rd party package as a dependency to my package with which I distribute an xcframework?
So, I have my product:
products: [
.library(
name: "MY-FRAMEWORK",
targets: ["MY-FRAMEWORK", "SOME-3RD-PARTY-XCFRAMEWORK"]
)
]
my dependency, which I require:
dependencies: [
.package(url: "URL-TO-3RD-PARTY-PACKAGE", revision: "VERSION")
]
and my targets:
targets: [
.binaryTarget(
name: "MY-FRAMEWORK",
path: "PATH-TO-MY-FRAMEWORK"
),
.binaryTarget(
name: "SOME-3RD-PARTY-XCFRAMEWORK",
path: "PATH-TO-SOME-3RD-PARTY-XCFRAMEWORK"
)
]
While compiling, the Package expresses his concern of me not using the dependency in any of the declared targets, which is true. Also, when trying to integrate my package to an application, I get an error that it cannot be imported due to some errors.
1. No such module '3RD-PARTY-PACKAGE'
2. Failed to build module 'MY-FRAMEWORK' for importation due to the errors above; the textual interface may be broken by project issues or a compiler bug.
Now, How can I use a package dependency for my library with SPM?
Ok, so for the last 2 days I was searching and trying to find a solution to my problem and I stumbled over this post. Looks like SPM truly does not support dependencies on binary targets. So, in order to make it work I was forced to create a wrapper target within the Package.
I've created a group in the Package named 'Wrapper' and added two
files: one .h file into an include group and one .m file in the root, both of
them empty (just a comment with why I did this).
Added a new target, which is the 'Wrapper' in which I added the package dependency and any 3rd party binary targets I had.
Updated my library to use the 'Wrapper' as a target.
And that was it. Bellow, you can see the Package.swift file:
let package = Package(
name: "MY-FRAMEWORK",
products: [
.library(
name: "MY-FRAMEWORK",
targets: ["MY-FRAMEWORK", "Wrapper"]
)
],
dependencies: [
.package(name: "3RD-PARTY-PACKAGE", url: "URL-TO-3RD-PARTY-PACKAGE", revision: "VERSION")
],
targets: [
// .binaryTarget doesn't support package dependencies so we use a wrapper to fix this
.target(
name: "Wrapper",
dependencies: [
"SOME-3RD-PARTY-XCFRAMEWORK", "3RD-PARTY-PACKAGE"
],
path: "Wrapper"
),
.binaryTarget(
name: "MY-FRAMEWORK",
path: "MY-FRAMEWORK.xcframework"
)
.binaryTarget(
name: "SOME-3RD-PARTY-XCFRAMEWORK",
path: "PATH-TO-SOME-3RD-PARTY-XCFRAMEWORK.xcframework"
)
]
)
and also the project structure:
Hope it will help somebody in the future. All credits must be given to the original post I followed. Without it, I would have still be stuck and searching the web. Cheers mate!
// edit: You can also have just one swift file into the 'Wrapper' group, not only the two .h and .m files.

How can I include/bundle other Swift Package dependencies in a Swift Package that only contains binaryTargets (XCFrameworks)?

I am creating Swift Packages from various Objective-C Frameworks (via use of XCFrameworks).
I successfully created the SPs, but have run into an issue when it comes to the other SP dependencies it relies on.
If I only add the WrapperPackage to my DemoApp, the compiler fails due to missing the SubDependencyPackage frameworks.
If I add the SubDependencyPackage via SPM to the DemoApp, it compiles just fine.
Is it possible / How can I...
properly bundle the "sub-dependencies" (SubDependencyPackage) into the Swift Package (WrapperPackage) so that in the DemoApp I only need to add WrapperPackage via SPM and all dependencies are resolved?
Workflow
DemoApp adds WrapperPackage as a SPM dependency.
WrapperPackage contains 2 XCFrameworks.
The 2 XCFrameworks were generated from 2 Objective-C Frameworks.
The Objective-C Frameworks have "sub-dependencies" of a separate Swift Package (SubDependencyPackage).
DemoApp
|
--WrapperPackage (XCFrameworks)
|
--SubDependencyPackage (XCFramework Dependencies)
WrapperPackage.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: "WrapperPackage",
platforms: [.iOS(.v13)],
products: [
.library(name: "ObjectiveCFramework1", targets: ["ObjectiveCFramework1"]),
.library(name: "ObjectiveCFramework2", targets: ["ObjectiveCFramework2"]),
],
dependencies: [
.package(name: "SubDependencyPackage.git", url: "git#github.com:user/SubDependencyPackage.git", .branch("main")),
],
targets: [
.binaryTarget(name: "ObjectiveCFramework1", path: "XCFrameworks/ObjectiveCFramework1.xcframework"),
.binaryTarget(name: "ObjectiveCFramework2", path: "XCFrameworks/ObjectiveCFramework2.xcframework"),
]
)

Swift Package Manager - Exclude dependency

I'm having a second thought using multiple products inside SPM. Here is the thing.
I’ll provide two products in the package. One is “Tool” and the other one is “ToolNetworking”.
The first one has some swift classes, nothing special, no dependencies at all.
The second one also has some swift logic, but a dependency on Alamofire lib.
Here is the config:
// swift-tools-version:5.1
import PackageDescription
let package = Package(
name: "Tool",
platforms: [.iOS(.v11)],
products: [
.library(name: “Tool", targets: [“Tool"]),
.library(name: “ToolNetworking", targets: [“ToolNetworking"])
],
dependencies: [
.package(url: "https://github.com/Alamofire/Alamofire.git", .exact("5.1.0"))
],
targets: [
.target(
name: "Tool",
path: "Sources",
exclude: ["Networking"]
),
.target(
name: "ToolNetworking",
dependencies: ["Tool", "Alamofire"],
path: "Sources",
sources: ["Networking"]
)
],
swiftLanguageVersions: [.v5]
)
When I want to install the package, I can choose between the two. If I select ToolNetworking, it will also install Alamofire dependency.
For Tool product I only want SPM to install my code, no dependencies. Here is my question. How can I exclude Alamofire when I install only Tool product since I didn't define a dependencies field?
Thanks
A first step would be to upgrade to Swift 5.2. The Swift Package Manager shipped with Swift 5.2 starts to implement exactly this behaviour (as described in SE-0226).
However, since it's not fully implemented yet, it could be that Xcode will still check out Alamofire. It should not link it in the end, though. So if you only use the Tool product, the resulting binary will not have any traces of Alamofire inside it :-)

import jwt from swift cocoa touch framework

I am working on swift cocoa touch framework to create reusable framework from mobile application.
my framework need to use jwt project from https://github.com/vapor/jwt.git
i tried to create Package.swift and then add .package(url:"https://github.com/vapor/jwt.git", from: "3.0.0") and then run swift package resolve
in my code, i import jwt library like this
import JWT
import Foundation
but i got the error No such module 'JWT'
i am newbie on swift, can someone help please?
my Package.swift is here
// swift-tools-version:4.2
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "edoc-sdk-swift",
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
name: "edoc-sdk-swift",
targets: ["edoc-sdk-swift"]),
],
dependencies: [
.package(url:"https://github.com/vapor/jwt.git", from: "3.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 which this package depends on.
.target(
name: "edoc-sdk-swift",
dependencies: ["JWT"]),
.testTarget(
name: "edoc-sdk-swiftTests",
dependencies: ["edoc-sdk-swift"]),
]
)
You should check two things:
Module name is JWT, not jwt.
Check that your .target in Package.swift contains "JWT" in dependencies
thanks all guys for the feedback.
now i can solve the problem, and i write the solution to this blog
https://piggyman007.blogspot.com/2018/12/create-swift-framework-and-include-some.html

Resources