드디어! 남은 건 Tuist Code 작성뿐이다!!
이지만 Code가 사실 반이상이라는 것!
오늘은 Target을 생성하는 코드부터 먼저 정의해보도록 하겠습니다.
어차피 Swift 코드니까 각자가 편한대로 코드를 작성할 수 있잖아요?
Target Enum
그러니 Target을 나눌 Enum부터 정의해줍시다.
정의는 그냥 Project+Templates 파일에 했습니다.
별로 파일 만들어도 상관없는것 같아요.
public enum TargetType: String {
case dev = ""
case test = "Test"
case content = "Content"
case service = "Service"
public var bundleID: String {
"com.Rey.AppName"
}
public var projectName: String {
"AppName"
}
}
요렇게! enum을 정의했습니다.
그리고 Path와 Bundle Identifier에 관련된 String을 만들어줍니다.
extension TargetType {
var infoPlist: String {
switch self {
case .dev: return "App/plist/info.plist"
case .test, .content, .service: return "App/plist/\(self.rawValue)-info.plist"
}
}
var targetPathName: String {
switch self {
case .dev, .test: return projectName
case .content, .service: return self.rawValue
}
}
var configName: String {
switch self {
case .dev: return projectName
case .test: return "\(projectName)-Test"
case .content, .service: return self.rawValue
}
}
var bundleIdentifier: String {
switch self {
case .dev: return bundleID
case .test, .content, .service: return "\(bundleID).\(self.rawValue)"
}
}
}
Target 인스턴스 생성
Documentation
tuist.github.io
뭘 모르겠을땐 Document죠!
Target(
name: String,
platform: Platform,
product: Product,
productName: String?,
bundleId: String,
deploymentTarget: DeploymentTarget?,
infoPlist: InfoPlist?,
sources: SourceFilesList?,
resources: ResourceFileElements?,
copyFiles: [CopyFilesAction]?,
headers: Headers?,
entitlements: Path?,
scripts: [TargetScript],
dependencies: [TargetDependency],
settings: Settings?,
coreDataModels: [CoreDataModel],
environment: [String : String],
launchArguments: [LaunchArgument],
additionalFiles: [FileElement]
)
파라미터가 많네요...
하지만 이중에 이번에 사용할 것만 빼면!
Target(
name: String, // 이름
platform: Platform, // Device
product: Product, // Target의 종류 ex) App, Framework, App Extension 등
bundleId: String, // Bundle Identifier
deploymentTarget: DeploymentTarget?, //
infoPlist: InfoPlist?, // plist Path
sources: SourceFilesList?, // Swift 소스 코드 Path
resources: ResourceFileElements?, // Swift 소스를 제외한 나머지 파일 Path
entitlements: Path?, // Entitlements Path
dependencies: [TargetDependency], // Dependencies
settings: Settings?, // Setting
)
많이 짧아졌죠? 이제 이 Target을 반환할 함수 하나를 Project안에 정의해줍니다.
extension Project {
public static func target(
type: TargetType,
product: Product = .app,
dependencies: [TargetDependency] = []
) -> Target {
let baseSettings = SettingsDictionary()
return Target(
// Parameters
)
}
}
이렇게 하면 실제로 Target을 생성할 때 코드가 간결해지겠죠?
실제로 Target 인스턴스를 생성하는 부분에선 이렇게 사용됩니다!
Project.target(
type: .dev,
dependencies: [
.target(name: "Content"),
.target(name: "Service"),
.package(product: "Kingfisher"),
// dependency
]
),
Project.target(
type: .test,
dependencies: [
.package(product: "Kingfisher"),
// dependency
]
),
Project.target(
type: .content,
product: .appExtension
),
Project.target(
type: .service,
product: .appExtension
)
Target 인스턴스 생성 함수 정의
이제 본격적으로 값을 채워보아요
Target(
name: type.name,
platform: .iOS,
product: product,
productName: type.name,
bundleId: type.bundleIdentifier,
deploymentTarget: .iOS(targetVersion: "13.0",
devices: [.iphone, .ipad]
),
infoPlist: "\(type.infoPlist)",
sources: "Targets/\(type.targetName)\(ResourceType.source.rawValue)",
resources: [
"Targets/\(type.targetName)\(ResourceType.xibs.rawValue)",
"Targets/\(type.targetName)\(ResourceType.assets.rawValue)",
"Targets/\(type.targetName)\(ResourceType.storyboards.rawValue)"
],
entitlements: "App/Entitlements/\(type.targetName).entitlements",
dependencies: dependencies,
settings: .settings(
base: [:],
configurations: [
.debug(
name: "Debug",
settings: baseSettings,
xcconfig: "App/Configuration/\(type.configName)-Debug.xcconfig"
),
.release(
name: "Release",
settings: baseSettings,
xcconfig: "App/Configuration/\(type.configName)-Release.xcconfig"
)
],
defaultSettings: .recommended
)
)
참고로 ResourceType은
public enum ResourceType: String {
case source = "Sources/**"
case xibs = "Sources/**/*.xib"
case storyboards = "Resources/**/*.storyboard"
case assets = "Resources/**"
}
이렇게 생겼답니다!
각 값들이 StringLiteral값으로 생성되기 때문에 대부분 저렇게 "" 으로 감싸서 넣어주는게 좋습니다.
고민했던 것들
파라미터 중 어떤 값인지 한번에 이해가 안가는 부분이 있었다면 settings 인데요.
바로 Debug과 Release가 나눠진 저 부분에 대한 설정입니다.
그래서 xcconfig의 경로를 넣어주었습니다.
값으로 들어간 settings Dictionary도 어떻게 설정해야하는지 궁금했는데요.
let baseSettings = SettingsDictionary()
Project.swift | Tuist Documentation
This page documents the models that users can use to define their project: how to initialize them, attributes and their meaning, protocol comformances.
docs.tuist.io
알고보니 답이 있었습니다.
bitcode, code sign 같은 자주 사용하는 부분들을 제공하니 참고해서 functional 하게 사용하시면 됩니다.
최종코드
Target Function
extension Project {
public static func target(
type: TargetType,
product: Product = .app,
dependencies: [TargetDependency] = []
) -> Target {
let baseSettings = SettingsDictionary()
.bitcodeEnabled(true)
.automaticCodeSigning(devTeam: "**********")
return Target(
name: type.name,
platform: .iOS,
product: product,
productName: type.name,
bundleId: type.bundleIdentifier,
deploymentTarget: .iOS(targetVersion: "13.0",
devices: [.iphone, .ipad]
),
infoPlist: "\(type.infoPlist)",
sources: "Targets/\(type.targetName)\(ResourceType.source.rawValue)",
resources: [
"Targets/\(type.targetName)\(ResourceType.xibs.rawValue)",
"Targets/\(type.targetName)\(ResourceType.assets.rawValue)",
"Targets/\(type.targetName)\(ResourceType.storyboards.rawValue)"
],
entitlements: "App/Entitlements/\(type.targetName).entitlements",
dependencies: dependencies,
settings: .settings(
base: [:],
configurations: [
.debug(
name: "Debug",
settings: baseSettings,
xcconfig: "App/Configuration/\(type.configName)-Debug.xcconfig"
),
.release(
name: "Release",
settings: baseSettings,
xcconfig: "App/Configuration/\(type.configName)-Release.xcconfig"
)
],
defaultSettings: .recommended
)
)
}
}
ResourceType
public enum ResourceType: String {
case source = "Sources/**"
case xibs = "Sources/**/*.xib"
case storyboards = "Resources/**/*.storyboard"
case assets = "Resources/**"
}
TargetType
public enum TargetType: String {
case dev = ""
case test = "Test"
case content = "Content"
case service = "Service"
public var bundleID: String {
"com.Rey.AppName"
}
public var projectName: String {
"AppName"
}
}
extension TargetType {
var name: String {
switch self {
case .dev: return projectName
case .test: return "\(projectName)_Test"
case .content, .service: return self.rawValue
}
}
var infoPlist: String {
switch self {
case .dev: return "App/plist/info.plist"
case .test, .content, .service: return "App/plist/\(self.rawValue)-info.plist"
}
}
var targetPathName: String {
switch self {
case .dev, .test: return projectName
case .content, .service: return self.rawValue
}
}
var configName: String {
switch self {
case .dev: return projectName
case .test: return "\(projectName)-Test"
case .content, .service: return self.rawValue
}
}
var bundleIdentifier: String {
switch self {
case .dev: return bundleID
case .test, .content, .service: return "\(bundleID).\(self.rawValue)"
}
}
}
다음편엔 Project Setting까지해서 Generate까지 해보아요!
'iOS > iOS' 카테고리의 다른 글
[iOS] CI/CD 환경 구축하기 - 1. Tuist in Git Actions & fastlane (0) | 2024.01.09 |
---|---|
[iOS] Tuist - 4. Project 생성 (0) | 2023.02.11 |
[iOS] Tuist - 2. 프로젝트 파일 정리 (0) | 2023.02.02 |
[iOS] Tuist - 1. XcodeGen에서 Tuist로 (0) | 2023.02.02 |
[iOS] Swift Static Framework 만들기(Universal) - 1. 삽질 구간 (0) | 2022.07.16 |