부스트캠프 팀원들과 그룹프로젝트를 설계하면서, 다음과 같은 고민이 생겼습니다.
Xcode에서 파일 및 폴더를 삭제하거나, 위치를 변경하면 .pbxproj에서 충돌이 나지 않을까요?
그래서 처음 결정된 의견은 "폴더의 수정은 기록해놓고, merge한 후 반영하죠!" 였습니다.
하지만 매번 그런 방식을 사용하면 굉장히 번거롭고, 뭔가 방법이 있을 테니 멘토님께 여쭤보자고 이야기가 나왔습니다.
멘토님은 회사에서도 이 문제때문에 고민이 있었고, XcodeGen과 Tuist를 추천해 주셨습니다. 팀원 분들과 회의 끝에 Tuist
를 사용하기로 하였습니다.
Tuist는 Xcode 프로젝트를 생성하고 관리하는 Command Line Tool 입니다.
깃허브에 나와 있는 한 줄 설명입니다.
이 설명대로, Tuist는 Xcode 프로젝트 모듈화를 위한 툴입니다.
curl -Ls https://install.tuist.io | bash
이 스크립트를 실행하여 Tuist를 설치할 수 있습니다.
위 링크에 나와 있는 대로 프로젝트를 만들어 보겠습니다.
우선 테스트할 디렉토리를 생성합니다.
다음 명령어를 실행하여 Tuist를 세팅합니다.
그럼 디렉토리가 다음과 같이 구성됩니다.
문서에는 Info.plist
, AppDelegate.swift
, Project.swift
및 테스트 파일들이 같이 생성된다고 적혀 있습니다. 위 디렉토리에서는 Info.plist
가 보이지 않지만 일단 진행해 보겠습니다...🥶
(Project.swift
는 Packages.swift
와 동일하다고 합니다.)
다음 명령어를 실행하여 Tuist Manifest를 열고 수정할 수 있습니다.
그러면 Xcode가 자동으로 열리게 됩니다.
아직 Mainfest에 대한 자세한 이해가 없기 때문에, 추후 알아보게 된다면 포스트를 해야겠습니다.
드디어 Xcode 프로젝트를 생성합니다. 다음 명령어를 사용하여 Xcode 프로젝트를 생성합니다.
**.xcodeproj
와 **.xcworkspace
가 생성됩니다.
xcworkspace는 프로젝트가 의존하게 될 다른 프로젝트를 추가할 때 필요하게 됩니다.
(Cocoapod이 xcworkspace를 사용하는 것과 같은 의미가 되는 것 같습니다.)
그런데 tuist generate
는 현재 프로젝트 뿐만 아니라, 이 프로젝트가 의존하고 있는 모든 프로젝트까지 생성하게 됩니다. 이 때 의존하는 프로젝트를 제외한 개인의 프로젝트만 골라서 생성하고 싶을 때는 --project-only
옵션을 사용하면 된다고 합니다.
다음과 같이 프로젝트가 생성되었습니다!
tuist generate
명령이 실행되면서 만든 폴더 구조(바로 위 Xcode의 폴더 구조)와, 저 위에 있는 2. 다음 명령어를 실행하여 Tuist를 세팅합니다.
에 나와 있는 트리 구조가, 정확히는 Targets
가 일치하는 것으로 보아, tuist generate
는 Targets
구조를 따라 Xcode 프로젝트를 생성하는 것 같습니다.
맞는 것 같지만 궁금하니 한 번 Targets
의 내용을 바꾸어 실험해보겠습니다.
시원하게 밀어버리고 다시 init
부터 해보았습니다.
각 Target의 하위 폴더에 hello.swift
를 끼워 넣어 보았습니다.
바로 생성해보겠습니다.
각 폴더에 hello.swift
가 들어가 있네요!
저희는 프로젝트에 바로 Tuist를 적용해보기로 했습니다.
기존에 있는 프로젝트가 아닌, 새로 프로젝트를 만들어서 설정했습니다.
tuist init --platform ios
위 명령어를 입력하여 새로운 프로젝트를 생성해줍니다.
위에서 말한 대로 Targets
폴더에서 프로젝트 구조를 수정해 줄 수 있습니다.
저는 Kit과 UI 프레임워크를 따로 생성하여 관리하지 않을 것이어서, 우선 저 두 폴더를 삭제해 주겠습니다.
이제 tuist edit
으로 Manifest를 수정해줍니다.
Project.swift에서 additionalTargets
에 있는 추가 타겟들을 제외해줍니다.
Tuist/ProjectDescriptionHelpers/Project+Templates.swift
를 열고, organizationName과 bundleId를 수정해줍니다.
저는 replace
로 "io.tuist"를 "com.testapp"으로 변경해주었습니다.
앱에 사용할 라이브러리를 명시하여 추가해줄 수 있습니다.
이번 포스트에서는 많이 사용되는 라이브러리인 RxSwift
, SnapKit
을 추가해보도록 하겠습니다.
Tuist Doc - tuist fetch 를 보면, tuist fetch
명령어를 실행할 경우 Tuist/Dependencies.swift
에 있는 항목들을 받아와 준다고 적혀 있습니다.
그 후 Tuist Doc - Adding External Dependencies에 나와 있는 내용처럼 let dependencies = ...
을 구성해 주어야 합니다.
// Dependencies.swift
import ProjectDescription
let spm = SwiftPackageManagerDependencies([
.remote(url: "https://github.com/ReactiveX/RxSwift", requirement: .upToNextMajor(from: "6.5.0")),
.remote(url: "https://github.com/SnapKit/SnapKit", requirement: .upToNextMajor(from: "5.6.0")),
])
let dependencies = Dependencies(
swiftPackageManager: spm,
platforms: [.iOS]
)
이제 터미널에서 Ctrl+C를 눌러 편집을 종료해줍니다. 그 후 tuist fetch
명령어를 입력하여 Dependencies.swift
에 있는 프레임워크들을 다운받아 줍니다.
이렇게 결과 화면이 뜨게 되면 라이브러리들이 모두 받아진 것입니다.
그럼 tuist generate
명령으로 프로젝트를 실행시켜 보겠습니다.
프로젝트를 열게 되면 아마 위에서 다운받은 라이브러리들이 보이지 않을 것입니다. Project.swift
에서 추가적으로 설정을 해줘야 하기 때문입니다.
Xcode를 닫고, 터미널에 다시 tuist edit
을 입력하여 Manifest 편집을 열어 줍니다.
앱의 타겟을 추가해주기 위해 Project.swift
의 하단에 있는 let project = Project.app(...)
부분을 아래와 같이 설정해 줍니다.
let dependencies: [TargetDependency] = [
.external(name: "RxSwift"),
.external(name: "RxCocoa"),
.external(name: "RxRelay"),
.external(name: "SnapKit"),
]
let targets: [Target] = [
Target(
name: "TestTuist",
platform: .iOS,
product: .app,
bundleId: "com.testapp",
infoPlist: .default,
sources: ["Targets/TestTuist/Sources/**"],
resources: ["Targets/TestTuist/Resources/**"],
dependencies: dependencies
)
]
// Creates our project using a helper function defined in ProjectDescriptionHelpers
let project = Project(
name: "TestTuist",
organizationName: "com.testapp",
settings: .settings(defaultSettings: .recommended),
targets: targets
)
Project.swift
를 관리하는 팩토리 클래스를 만들어 사용하는 경우도 있는 것 같습니다.
터미널을 다시 Ctrl+C로 닫고 tuist generate
를 입력하여 프로젝트를 생성해줍니다.
이제 프로젝트가 완성되었습니다!
추가적으로 Info.plist
, xcconfig
및 기타 많은 설정들을 관리해줄 수 있습니다. 아직 추가 설정은 사용해보지 않아서, 사용하게 된다면 다시 포스트할 예정입니다.
프로젝트를 여러 사람이 같이 개발하는 경우, Xcode 프로젝트에서 Signing을 관리해 주어야 합니다.
저희 팀의 경우 제가 Apple 개발자 계정이 있어서, 프로젝트를 설정해 준 후 GitHub에 업로드하였습니다.
위와 같이 따로 Signing 설정을 해주지 않을 경우 실제 기기에서 실행이 되지 않습니다.
Tuist에서 Signing을 관리하려면 총 3가지 파일이 필요합니다.
.mobileprovision
).cer
).p12
)위 사이트에 접속하여 로그인합니다.
+
버튼을 누른 후 저는 iOS App Development
를 선택해 주었습니다.
이 때 Certificate Signing Request
라는 파일을 업로드하라고 요구합니다. "Learn More >" 버튼을 누르면 해당 파일을 생성하는 방법이 나와 있습니다.
아래와 같은 파일이 생성됩니다.
위 파일을 업로드하고 Continue
를 누르면 인증서가 생성됩니다.
Download
를 눌러 인증서를 다운받습니다.
"키체인 접근"이 열리게 되고, 검색어로 "apple"을 입력하면 다음과 같은 인증서들이 보이게 됩니다.
테스트하다가 인증서를 여러 개 만들어 버렸는데, 위와 같은 형식 중 가장 하단에 있는 것으로 사용하면 되는 것 같습니다. (정확하지는 않습니다..)
다음 절차를 거쳐 .p12
파일을 생성합니다.
중요: 여기서 비밀번호를 입력하라는 창이 뜨는데, 이 때 비밀번호는 반드시 비어 있어야 합니다. 창이 뜨면 비밀번호 란에 아무것도 입력하지 않고 다음을 눌러야 합니다.
이렇게 하지 않으면 Tuist
가 인증서를 인식하지 못하고, tuist generate
명령 실행 시 에러가 나게 됩니다.
이제 6번에서 다운받은 .cer
파일과 .p12
의 이름을 알맞게 바꿉니다. 저는 프로젝트 이름.cer
, 프로젝트 이름.p12
로 설정하였습니다.
Profile을 다운로드하기 전에 팀원들의 기기를 등록해야 합니다.
+
버튼을 누르면 기기를 등록하는 창이 뜨게 됩니다.udid
키워드로 검색하면 획득하는 방법이 나와 있습니다.Continue
를 누르고, 기기 정보가 올바른지 확인 후 Register
을 눌러 등록합니다.Provisioning Profile은 다음과 같이 얻을 수 있습니다.
+
버튼을 누르고, 저는 iOS 앱이기 때문에 iOS App Development
를 선택해 주었습니다. Continue
를 누릅니다.Provisioning Profile Configuration
은 No로 해주었습니다. Continue
를 누릅니다.Continue
를 클릭합니다. 저는 아까 위에서 생성한 인증서를 선택했습니다.Continue
를 누릅니다.Generate
를 누릅니다.Download
를 눌러 파일을 획득합니다.이제 Signing에 필요한 3가지 파일을 모두 생성했습니다.
이 파일들은 팀원들이 모두 가지고 있어야 하고, 만약 Git을 사용한다면 .gitignore
에 Signing/
을 반드시 추가하여 인증서가 유출되지 않도록 해야 합니다.
위 파일들을 Tuist/Signing
폴더에 넣어야 합니다. Signing
폴더를 생성한 후, 3가지 파일을 생성한 폴더 안에 넣어 줍니다.
중요: .mobileprovision
파일의 이름은 반드시 Target.Debug.mobileprovisioning
으로 변경해 주어여 햡니다.
만약 Release 모드의 profile이 필요하다면 이름을 Target.Release.mobileprovisioning
으로 추가해줍니다.
저는 타겟 이름이 TestTuist
이기 때문에 TestTuist.Debug.mobileprovisioning
으로 설정해 주었습니다.
이제 한 가지 작업만 남았습니다.
Tuist
폴더에 master.key
라는 파일을 생성해야 합니다.
파일을 생성해 주고, 다음 명령어를 입력하여 나오는 값을 master.key
파일 안에 그대로 입력해줍니다.
openssl rand -base64 32
모든 설정이 끝났습니다..!
이제 tuist generate
명령어를 입력하면 Signing이 자동으로 설정되어 있을 것입니다.
tuist generate
명령을 실행하면.p12
와.cer
파일 뒤에.encrypted
가 붙게 됩니다. 이는 Tuist 자체에서 파일을 암호화 시키며, 터미널에서tuist signing decrypt
명령어를 입력하여 암호화를 풀거나tuist signing encrypt
명령어를 입력하여 다시 암호화할 수 있습니다.
유익한 자료 감사합니다~