본문 바로가기
Tuist/Tuist-기본

Tuist - 2) Target - 2 예제

by KS피터 2023. 12. 8.

Tuist 학습 일기장

 

지난번 Tuist에서 제공하는 Target 모델에 대해서 알아봤습니다. 이번에는 예제를 통해 실제 Target이 만들어지고 설정하는 방법에 대해서 작성하겠습니다.

 

이전글

Tuist - 2) Target - 1 이론

 

Tuist - 2) Target - 1 이론

Tuist 학습 일기장 Xcode에서 Target의 기본 정의와 Tuist에서 Target 생성을 위해 제공하는 모델 내부에 대한 정리를 기록하고 있습니다. 23.12.05 수정사항 기존 작성된 생성자는 deprecated 되어 수정 작성

ks-peter.tistory.com

 

목차

     

    기본 예제 준비

    Tuist - 1) 설치에서 사용한 기본 예제를 이용하겠습니다. (저는 TuistEx에서 작업을 진행하였습니다.)

    // Tuist 초기화
    tuist init --platform ios
    // Tuist 설정 편집 열기
    tuist edit

    tuist edit 화면

    이번 예제에서는 Plugins는 제외하고 Manifests 부분만 다루도록 하겠습니다.

     

    Manifests

    이전글에 작성된 것처럼 Manifests프로젝트는 프로젝트 설정 및 생성, 관리 + 관련 템플릿 작성을 위한 프로젝트입니다.

    Manifests의 각 파일들이 어떤 기능을 나타내는지 간략히 보면 다음과 같습니다.

     

    Project.swift:

    • 프로젝트를 정의하는 곳으로 let projectstruct Project를 생성해서 주입해서 생성 공식 문서

    예시

    // Project.swift
    import ProjectDescription
    
    let project = Project(
        name: "MyProject",
        targets: [
            Target(
                name: "App",
                platform: .iOS,
                product: .app,
                bundleId: "io.tuist.App",
                sources: ["Sources/**"]
            )
        ]
    )

     

     

    Config.swift

    • 전체 Manifests의 프로젝트에 일관된 설정을 지정 공식 문서

    예제

    // Config.swift
    import ProjectDescription
    
    let config = Config(
        compatibleXcodeVersions: ["10.3"],
        swiftVersion: "5.4.0",
        generationOptions: .options(
            xcodeProjectName: "SomePrefix-\(.projectName)-SomeSuffix",
            organizationName: "Tuist",
            developmentRegion: "de"
        )
    )

     

     

    Project+Templates.swift(ProjectDescriptionHelpers): 

    • ProjectDescriptionHelpers를 이용하여 Manifetsts 전체에서 공유하여 재사용할 코드를 작성하여 규칙 지정 및 재사용에 용이. 공식 문서
    • import ProjectDescriptionHelpers를 통해 해당 폴더에 작성된 코드들을 사용
    • Project+Templates.swift는 샘플에서 기본 제공하는 프로젝트 템플릿.
      • 이번 예제에서는 Target만 이용하기 때문에 추후에 자세히 볼 예정.

    템플릿 정의 예시

    // Project+Templates.swift
    import ProjectDescription
    
    extension Project {
      public static func featureFramework(name: String, dependencies: [TargetDependency] = []) -> Project {
        return Project(
            name: name,
            targets: [
                Target(
                    name: name,
                    platform: .iOS,
                    product: .framework,
                    bundleId: "io.tuist.\(name)",
                    infoPlist: "\(name).plist",
                    sources: ["Sources/\(name)/**"],
                    resources: ["Resources/\(name)/**",],
                    dependencies: dependencies
                ),
                Target(
                    name: "\(name)Tests",
                    platform: .iOS,
                    product: .unitTests,
                    bundleId: "io.tuist.\(name)Tests",
                    infoPlist: "\(name)Tests.plist",
                    sources: ["Sources/\(name)Tests/**"],
                    resources: ["Resources/\(name)Tests/**",],
                    dependencies: [.target(name: name)]
                )
            ]
        )
      }
    }

    사용 예시

    // Project.swift
    import ProjectDescription
    import ProjectDescriptionHelpers
    
    let project = Project.featureFramework(name: "MyFeature")

     

    ProjectDescriptionHelpers

    Target 템플릿 작성을 이용할 예정이므로 해당 기능에 대해 조금 더 보도록 하겠습니다.

    공식 문석에 정의된 것을 확인하면 다음과 같이 설명되어 있습니다.

    Project description helpers are Swift files that get compiled into a framework, 'ProjectDescriptionHelpers', that manifest files can import.
    ProjectDescriptionHelpers는 Manifest 파일을 가져올 수 있는 프레임워크 'ProjectDescriptionHelpers'로 컴파일되는 Swift 파일입니다.

     

    또한 아래와 같은 장점들도 설명을 하고 있습니다.

    • 변경 사항을 한 곳에 적용할 수 있고 모든 프로젝트에 자동으로 변경 사항이 적용되므로 유지 관리가 용이합니다 .
    • 이를 통해 새 프로젝트가 준수할 수 있는 규칙 정의할 수 있습니다.
    • 프로젝트의 일관성 향상되므로 불일치로 인해 빌드가 손상될 가능성이 훨씬 적습니다.
    • 기존 로직을 재사용할 수 있기 때문에 새 프로젝트를 추가하는 것은 쉬운 작업이 됩니다.

    이 처럼 Tuist에서는 프로젝트 정의에 있어서 쉽게 정의하고 관리를 용이하게 하기 위해 ProjectDescriptionHelpers 기능을 제공하고 있습니다.

     

    타겟 생성 예제

    이제 여기까지 이해하셨다면 Target을 생성하고 수정하는 단계를 진행하실 수 있습니다. 이후부터는 제가 생각하는 대로 예제를 진행하므로 각자 프로젝트 상황에 맞게 진행을 하시면 될 것 같습니다.

    우선 저는 예제에서 기본 제공해 주는 Project+Templates.swift은 하나의 흐름에 고정되어 있는 상태라서 이용을 안할 예정입니다. 이번에 작성할 Target 템플릿와 추후 재작성될 Projec+Templates.swift합쳐서 프로젝트를 생성할 예정입니다.

     

    Target 템플릿

    ProjectDescriptionHelpers에 Target+Templates.swift을 생성(Targets ProjectDescriptionHelpers 체크 확인)하고 아래와 같이 작성하였습니다.

    ProjectDescriptionHelpers - Target+Templates.swift 파일 생성

    // Target+Templates.swift
    import ProjectDescription
    
    extension Target {
        /**
        Target 간소화 생성자
         
         - Parameters:
            - name: 타겟 이름 설정.
            - platform: 타겟에서 지원되는 배포 대상 설정. default iOS
            - product: 타겟 product 설정. (ex: app, unitTest, framework 등...)
            - deploymentTargets: 타겟 deployment 최소 버전. default: .iOS("15.0")
            - infoPlist: info.plist 설정
            - sources: 소스 경로 설정
            - resources: 리소스 경로 설정
            - scripts: 스크립트 설정
            - dependencies: 의존성 설정
            - settings: 세팅 설정
         */
        public init(name: String,
             destinations: Destinations = [.iPhone],
             product: Product,
             bundleName: String,
             deploymentTargets: DeploymentTargets = .iOS("15.0"),
             infoPlist: InfoPlist = .default,
             sources: SourceFilesList,
             resources: ResourceFileElements? = nil,
             scripts: [TargetScript] = [],
             dependencies: [TargetDependency] = [],
             settings: Settings? = nil) {
            self.init(name: name, // 타겟 이름 설정
                      destinations: destinations, // 타겟에서 지원되는 배포 대상 설정
                      product: product, // 타겟 product 설정
                      bundleId: "\(bundleName).\(name)", // Bundle ID
                      deploymentTargets: deploymentTargets, // 타겟 deployment 최소 버전.
                      infoPlist: infoPlist, // info.plist 설정
                      sources: sources, // 소스 경로 설정
                      resources: resources, // 리소스 경로 설정
                      scripts: scripts, // 스크립트 설정
                      dependencies: dependencies, // 의존성 설정
                      settings: settings) // 세팅 설정
        }
    }

     

    기본 Target에 추가 생성자를 만들어 주었습니다. 해당 코드만 봤을때는 Target에서 제공하는 생성자와 큰 차이는 없습니다. Default를 통해서 Target 생성에 통일화된 규칙을 주면서 작성에 조금 더 간소화를 주기 위해서 위와 같은 방법으로 Target 템플릿을 작성하였습니다.

     

    Target 템플릿 예시

    Target 템플릿을 기본 예제에 Project.swift 그대로 적용해보면 다음과 같습니다.

    // Project.swift
    let name = "TuistEx"
    let organizationName = "kr.kiseok"
    
    let infoPlist: [String: Plist.Value] = [
        "CFBundleShortVersionString": "1.0",
        "CFBundleVersion": "1",
        "UIMainStoryboardFile": "",
        "UILaunchStoryboardName": "LaunchScreen"
    ]
    
    let kitTarget = Target(name: "TuistExKit",
                           product: .framework,
                           bundleName: organizationName,
                           sources: [
                            "Targets/TuistExKit/Sources/**"
                           ])
    let uiTarget = Target(name: "TuistExUI",
                          product: .framework,
                          bundleName: organizationName,
                          sources: [
                            "Targets/TuistExUI/Sources/**"
                          ])
    
    let targets = [Target(name: name,
                          destinations: .iOS,
                                        product: .app,
                          bundleName: organizationName,
                          infoPlist: .extendingDefault(with: infoPlist),
                          sources: [
                            "Targets/\(name)/Sources/**"
                          ],
                          resources: [
                            "Targets/\(name)/Resources/**"
                          ],
                          dependencies: [
                            .target(kitTarget),
                            .target(uiTarget)
                          ]),
                   Target(name: "\(name)Tests",
                          destinations: .iOS,
                          product: .unitTests,
                          bundleName: organizationName,
                          sources: [
                            "Targets/\(name)/Tests/**"
                          ],
                          dependencies: [.target(name: name)])]
    
    let project = Project(name: name,
                          targets: targets + [kitTarget, uiTarget])

    tuist generate 결과 화면

    Tuist 기본 예제와 동일한 결과가 나오는걸 확인할 수 있습니다. 기존 Project+Templates.swift에선 프레임워크들이 고정되어 있어서 각 프레임워크들의 설정을 Custom하기도 어려웠지만 현재 재사용이 가능하면서 각 프레임워크들의 상황에 맞춰서 설정도 가능한 상태가 되었습니다.

     

    마치며

    현재 Project+Templates.swift를 이용하지 않고 Project.swift가 길어지는 문제가 생겼습니다. 이후 Project 글에서 템플릿을 재정의하고 Project 생성을 간소화하는 방법을 익히는 시간을 갖도록 하겠습니다.

    반응형

    'Tuist > Tuist-기본' 카테고리의 다른 글

    Tuist - 2) Target - 1 이론  (0) 2023.11.30
    Tuist - 1) 설치  (0) 2023.11.28