, , . , , , . — SPM, .
, : “ SPM?”. . , SPM :
SPM .xcodeproj ( );
. , , ;
Linux/Windows;
xcode .
?
Package.swift , , .
, :
import PackageDescription
let package = Package(
// 1.
name: "Resources",
// 2. ,
platforms: [
.iOS(.v11),
],
// 3. ,
// , Firebase SPM
products: [
.library(
name: "Resources",
//
// nil - SPM
// .static
type: .dynamic,
targets: ["Resources"]),
],
// 4. ,
// , targets
dependencies: [
// name - ( 1), ,
.package(name: "R.swift.Library", url: "https://github.com/mac-cain13/R.swift.Library", .branch("master")),
//
.package(path: "../Core")
],
targets: [
//
//
// Sources/_
// Sources, "path:"
.target(
name: "Resources",
dependencies: [
//
// name( 3), package( 1)
.product(name: "RswiftDynamic", package: "R.swift.Library")
],
resources: [
//
// Sources/_/___
// ,
.process("Resources")
])
]
)
, ( , ). workspace, drag and drop Project navigator.
, , . swift-tools-version:5.3, Xcode Version 12.2
1. .
SPM. - . : , .
2. SPM .
, , , . , - , : , (, checkout) .
3. R.swift SPM.
.xcodeproject , R.swift , .
XcodeGen . swift package generate-xcodeproj, .xcodeproj SPM.
, . , , R.swift. , :
error: [R.swift] Project file at 'file:///Users/.../Resources.xcodeproj/' could not be parsed, is this a valid Xcode project file ending in *.xcodeproj?
XcodeEdit — R.swift . exec , .xcodeproj. :
pathtoexec/XcodeEdit-Example Resources.xcodeproj
Fatal error: 'try!' expression unexpectedly raised an error: XcodeEdit_Example.AllObjectsError.fieldMissing(key: "buildRules"): file XcodeEdit_Example/main.swift, line 21
:
sed -i '' -e 's/isa = "PBXNativeTarget";/isa = "PBXNativeTarget";buildRules = ();/' Resources.xcodeproj/project.pbxproj
, . generate-xcodeproj . R.swift .xcodeproj/.pbproject, .
ruby gem xcodeproj, . , .xcodeproj XcodeGen.
XcodeGen:
# xcodeproj
name: Resources
targets:
Resources:
# ,
type: framework
platform: iOS
# Root folder
sources:
- Sources
.xcodeproj :
xcodegen generate --spec Resources.yml
.xcodeproj , R.swift:
# xcodeproj
generateXcodeProject() {
xcodegen generate --spec Resources.yml
}
# buildSettings xcodebuild , ,
#
getBuildSettings() {
xcodebuild -project "Resources.xcodeproj" -target "Resources" -showBuildSettings > buildSettings.txt
}
# enviroment R.swift
parseEnvironmentVariables() {
export SRCROOT="$(cat buildSettings.txt | grep -m1 "SRCROOT" | sed 's/^.*= //' )"
export TARGET_NAME="$(cat buildSettings.txt | grep -m1 "TARGET_NAME" | sed 's/^.*= //' )"
export PROJECT_FILE_PATH="$(cat buildSettings.txt | grep -m1 "PROJECT_FILE_PATH" | sed 's/^.*= //' )"
export TARGET_NAME="$(cat buildSettings.txt | grep -m1 "TARGET_NAME" | sed 's/^.*= //' )"
export PRODUCT_BUNDLE_IDENTIFIER="$(cat buildSettings.txt | grep -m1 "PRODUCT_BUNDLE_IDENTIFIER" | sed 's/^.*= //' )"
export PRODUCT_MODULE_NAME="$(cat buildSettings.txt | grep -m1 "PRODUCT_MODULE_NAME" | sed 's/^.*= //' )"
export TEMP_DIR="$(cat buildSettings.txt | grep -m1 "TEMP_DIR" | sed 's/^.*= //' )"
export BUILT_PRODUCTS_DIR="$(cat buildSettings.txt | grep -m1 "BUILT_PRODUCTS_DIR" | sed 's/^.*= //' )"
export DEVELOPER_DIR="$(cat buildSettings.txt | grep -m1 "DEVELOPER_DIR" | sed 's/^.*= //' )"
export SOURCE_ROOT="$(cat buildSettings.txt | grep -m1 "SOURCE_ROOT" | sed 's/^.*= //' )"
export SDKROOT="$(cat buildSettings.txt | grep -m1 "SDKROOT" | sed 's/^.*= //' )"
export PLATFORM_DIR="$(cat buildSettings.txt | grep -m1 "PLATFORM_DIR" | sed 's/^.*= //' )"
export INFOPLIST_FILE="$(cat buildSettings.txt | grep -m1 "INFOPLIST_FILE" | sed 's/^.*= //' )"
export SCRIPT_INPUT_FILE_COUNT=1
export SCRIPT_INPUT_FILE_0="$TEMP_DIR/rswift-lastrun"
export SCRIPT_OUTPUT_FILE_COUNT=1
export SCRIPT_OUTPUT_FILE_0="$SRCROOT/Sources/Resources/Generated/R.generated.swift"
}
#
rswift() {
R.swift generate --accessLevel public "$SCRIPT_OUTPUT_FILE_0"
}
# R.swift
# Bundle.module - SPM,
replaceRSwiftHostingBundle() {
sed -i '' -e 's/Bundle(for: R.Class.self)/Bundle.module/' ./Sources/Resources/Generated/R.generated.swift
}
mkdir Sources/Resources/Generated
generateXcodeProject
getBuildSettings
parseEnvironmentVariables
rswift
replaceRSwiftHostingBundle
4. Cocoapods SPM .
, Pod fat , SPM . proxy - XCFramework. Pod, SPM — , XCFramework .
Pod .framework, -.
, XCFramework. fat , Pod- 2 — . . , XCFramework arm64 x86_64. , lipo -info pathtoframework
.
# 2
cp -a YandexMapsMobile YandexMapsMobile_sim
cp -a YandexMapsMobile YandexMapsMobile_device
cd YandexMapsMobile_sim/YandexMapsMobile.framework/Versions/A
# fat
lipo -thin x86_64 YandexMapsMobile -output YandexMapsMobile_x86_64
# universal framework-a
#
# (i386), thin
# create
lipo -create YandexMapsMobile_x86_64 -output YandexMapsMobile_sim
rm -rf YandexMapsMobile YandexMapsMobile_x86_64
mv YandexMapsMobile_sim YandexMapsMobile
cd ../../../..
# ,
cd YandexMapsMobile_device/YandexMapsMobile.framework/Versions/A
lipo -thin arm64 YandexMapsMobile -output YandexMapsMobile_arm64
lipo -create YandexMapsMobile_arm64 -output YandexMapsMobile_device
rm -rf YandexMapsMobile YandexMapsMobile_arm64
mv YandexMapsMobile_device YandexMapsMobile
cd ../../../..
# xcframework
xcodebuild -create-xcframework -framework YandexMapsMobile_sim/YandexMapsMobile.framework -framework YandexMapsMobile_device/YandexMapsMobile.framework -output YandexMapsMobile.xcframework
XCFramework, binaryTarget. , :
let package = Package(
name: "YandexMapsMobileWrapper",
platforms: [
.iOS(.v11),
],
products: [
.library(
name: "YandexMapsMobileWrapper",
type: .static,
// XCFramework
targets: ["YandexMapsMobileWrapper"]),
],
dependencies: [
],
targets: [
// , url
.binaryTarget(name: "YandexMapsMobileBinary", path: "YandexMapsMobile.xcframework"),
//
.target(
name: "YandexMapsMobileWrapper",
dependencies: [
.target(name: "YandexMapsMobileBinary"),
],
linkerSettings: [
.linkedFramework("CoreLocation"),
.linkedFramework("CoreTelephony"),
.linkedFramework("SystemConfiguration"),
.linkedLibrary("c++"),
.unsafeFlags(["-ObjC"]),
]),
]
)
5. SPM (Bundle.module).
, , , yourpackagename_yourpackagename, , - . , , .
private class BundleFinder {}
// SPM , 2
public extension Bundle {
// №1, ,
static var resourceBundle: Bundle = {
let bundleName = "Resources_Resources"
let candidates = [
Bundle.main.resourceURL,
Bundle(for: BundleFinder.self).resourceURL,
Bundle.main.bundleURL,
// №2,
Bundle(for: BundleFinder.self).resourceURL?.deletingLastPathComponent().deletingLastPathComponent(),
]
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 \(bundleName)")
}()
}
6. Resolve Swift Packages .
SPM , . SPM , Xcode . Xcode .
7. Other Linker Flags SPM.
, . — ObjC . likerSettings: [.unsafeFlags([“ObjC”])]
. , unsafeFlags, , -, branch .
Swift Package Manager — . , -, . , SPM workaround, ?
, !