iOS Project를 함께 협업한다면 merge시 늘 우리를 괴롭히는 프로젝트 파일이 있습니다.
Project 설정 파일로 잘못 건들어 읽을 수 없다면 프로젝트가 열리지 않습니다...
(아마 어느정도 규모있게 작업하셨던 분들이라면 많이 공감하실 수 있을 것 같아요)
당연히 merge, rebase 상황에서 굉장히 위험한 작업들을 해야되죠.
컬리에서는 iOS 개발자들이 늘어나고 있습니다.
새로운 iOS 개발자가 계속해서 합류하면서 자연스럽게 branch가 늘어나고 merge 될 때마다 이 .pbxproj 파일이 점점 더 우리를 괴롭히는 것은 당연한 미래라고 느껴졌습니다.
관련한 문제를 해결하기 위해서 솔루션을 찾아야만 했습니다.
당연히 우리의 고민을 먼저 마주친 조직들이 있었습니다.
XcodeGen, Tuist
위의 해법들이 가장 많이 찾게되는 방법들이라고 생각되었습니다.
Xcode project를 관리하는 도구들이죠.
그 중 우리의 main 언어인 Swift로 관리되어질 수 있는 Tuist를 선택할 수 있었습니다.
(Ruby로 관리 되는 Xcode
Tuist 2.x 버전을 기준으로 작성이 되었습니다.
자세한 내용은 Official document를 참조하세요.
curl -Ls https://install.tuist.io | bash
tuist init --platform ios
위의 설치와 init은 한번만 해주시면 됩니다.
아래부터는 앞으로 계속해서 사용하게 될 명령어 입니다.
위의 명령어로 프로젝트를 수정할 Manifests 프로젝트가 실행됩니다.
tuist edit
각각의 프로젝트의 세팅값들을 찾아서 구성합니다.
여러분들이 여태 project 창에서 수정하시거나 변경했던 내용들을 모두 반영해주셔야 합니다.
let baseSettings: [String: SettingValue] = [
"ENABLE_BITCODE": "NO",
"SWIFT_OBJC_BRIDGING_HEADER": "Bridging-Header.h",
"CURRENT_PROJECT_VERSION": "100",
"MARKETING_VERSION": "1.0.0",
"CODE_SIGN_ENTITLEMENTS": "-",
"CODE_SIGN_IDENTITY": "-",
"DEVELOPMENT_TEAM": "-"
]
let releaseSetting: [String: SettingValue] = [
"PROVISIONING_PROFILE_SPECIFIER": "",
"CODE_SIGN_STYLE": "Manual"
]
let adhocSetting: [String: SettingValue] = [
"PROVISIONING_PROFILE_SPECIFIER": "",
"CODE_SIGN_STYLE": "Manual"
]
let settings = Settings.settings(
base: baseSettings,
configurations: [
.release(
name: "Release",
settings: releaseSetting
),
.release(
name: "AdHoc",
settings: adhocSetting
)
],
defaultSettings: .recommended
)
let newProject = Target(
name: "-",
platform: .iOS,
product: .app,
bundleId: "-",
deploymentTarget: .iOS(
targetVersion: "-",
devices: [.iphone, .ipad]
),
infoPlist: "Info.plist",
sources: [
"ProjectRoot/**"
],
resources: ["ProjectRoot/Resource/**"],
entitlements: "ProjectRoot/Project.entitlements",
scripts: scripts,
dependencies: [
.sdk(name: "AdSupport.framework")
.target(name: "SomeFrameWorkProject")
],
settings: settings
)
let projectSettings = Settings.settings(
configurations: [
.debug(name: "Debug")
]
)
let schemes = [
Scheme(
name: "-",
shared: true,
buildAction: .buildAction(targets: ["-"]),
runAction: .runAction(configuration: "Debug"),
archiveAction: .archiveAction(configuration: "Release"),
profileAction: .profileAction(configuration: "Debug"),
analyzeAction: .analyzeAction(configuration: "Debug")
)
]
let project = Project(
name: "ProjectName",
organizationName: "com.project",
settings: projectSettings,
targets: [
newProject
],
schemes: schemes,
additionalFiles: [
]
)
tuist generate
위의 명령으로 프로젝트 파일을 생성해주셔야합니다.
.xcodeproj
.xcworkspace
더 이상 git으로 트래킹해주지 않도록 합니다.
https://github.com/tuist/tuist/releases/tag/2.0.0
위의 배포사항으로 Cocoapods가 더 이상지원되지 않았습니다.
항상 tuist generate 이후에 bundle exec pod install을 해주도록 했습니다.
아래의 script를 생성해두고 계속 사용하도록 합시다.
tuist generate && bundle exec pod install
저희는 CI/CD로 Bitrise를 사용하게 됩니다.
당연히 가상빌드환경에서도 tuist를 설치 및 생성해주는 script를 추가해주어야합니다.
리소스 파일을 관리하는 도구로 R.swift를 해줍니다. 그러나 R.swift는 변동이 매번 발생하는 파일이므로 .gitignore처리가 되어있습니다.
그러므로 최초 빌드시 tuist project에는 존재하지 않습니다. 매번 tuist generate 전 touch R.generated.swift 파일을 추가해주어야합니다.
Tuist에서는 그 외의 리소스 관리등의 기능들을 제공합니다.
사용하고 사용할 Tuist에 대한 세팅들을 아래 Config.swift를 통해서 관리해줄 수 있습니다.
https://docs.tuist.io/manifests/config
조금의 작업과 수고스러움은 생겼지만 이렇게 해주니 앞으로의 프로젝트 파일 추가, 삭제 등의 과정에서 더 이상 conflict의 과정을 마주치지 않을 수 있습니다.
또 앞으로 모듈레벨의 분리의 관리에서도 더욱 편리하게 프로젝트를 관리할 수 있을 것으로도 기대하고 있습니다.
읽어주셔서 감사합니다.