관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] 3. Tuist로 모듈화 - 템플릿, 프로젝트 생성까지 총정리 (Project.swift, .stencil) 본문

iOS 응용 (swift)

[iOS - swift] 3. Tuist로 모듈화 - 템플릿, 프로젝트 생성까지 총정리 (Project.swift, .stencil)

jake-kim 2023. 3. 13. 01:05

* 목차

tuist scaffold, tuist generate로 메인 프로젝트를 .app 생성

주의)

1) 이름을 꼭 Tuist, Templates으로 아래처럼 설정해야 동작함

2) Templates하위에 있는 폴더 이름과 그 폴더 안에 있는 .swift 파일 이름이 동일해야함 (app 디렉토리 == app.swift)

.
└── Tuist
    └── Templates
        └── app
            ├── Project.stencil
            └── app.swift

 

(Project.stencil)

import ProjectDescription

let project = Project(
    name: "{{ name }}",
    targets: [
        Target(
            name: "{{ name }}",
            platform: .iOS,
            product: .app,
            bundleId: "com.jake.{{ name }}",
            infoPlist: .extendingDefault(with: [
                "CFBundleShortVersionString": "1.0",
                "CFBundleVersion": "1",
                "UILaunchStoryboardName": "LaunchScreen"
            ]),
            sources: ["Sources/**"], // Sources/**누락 시 .swift 파일 수동으로 add files해야 추가됨
            resources: ["Sources/**"], // Sources/**누락 시 LaunchScreen.storyboard 파일 수동으로 add files해야 추가됨
            dependencies: [   
                
            ]
        )
    ]
)
  • scaffold로 Project.swift 파일 생성
tuist scaffold app --name MyApp

(생성된 Project.swift 파일)

.
├── Project.swift
└── Tuist
    └── Templates
        └── app
            ├── Project.stencil
            └── app.swift
  • tuist generate로 .xcworkspace와 필요한 필수 파일들 생성
tuist generate

(Xcode가 자동으로 실행되며 기본 프로젝트 생성 완료)

  • 실행 -> 빌드 실패
    • entry point인 AppDelegate가 없기 때문
  • Tuist/Templates/app 하위에 AppDelegate.stencil, ViewController.stencil, LaunchScreen.stencil을 만들고 이 파일도 자동으로 생성되게끔하는 작업이 필요

(AppDelegate.stencil)

import UIKit

@main 
class AppDelegate: UIResponder, UIApplicationDelegate {    
    var window: UIWindow?
    
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
    ) -> Bool {
        window = UIWindow(frame: UIScreen.main.bounds)
        let viewController = ViewController()
        window?.rootViewController = viewController
        window?.makeKeyAndVisible()
        return true
    }   
}

(ViewController.stencil)

import UIKit

final class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
    }
}

(LaunchScreen.stencil)

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--View Controller-->
        <scene sceneID="EHf-IW-A2E">
            <objects>
                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
                    </view>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="53" y="375"/>
        </scene>
    </scenes>
</document>

(app.swift)

  • 기존 파일에서 AppDelegate, ViewController, storyboard 부분 추가
  • path를 둘 다 Sources 하위에다가 하고 있는데 이건 Project.stencil에서 sources의 경로를 Sources/** 라고 했기 때문에 이곳에 관련 파일들을 위치 시켜야함
import ProjectDescription

let nameAttribute: Template.Attribute = .required("name")

let template = Template(
    description: "Custom template",
    attributes: [
        nameAttribute
    ],
    items: [
        .file(
            path: "Project.swift",
            templatePath: "Project.stencil"
        ),
        .file(
            path: "Sources/AppDelegate.swift",
            templatePath: "AppDelegate.stencil"
        ),
        .file(
            path: "Sources/ViewController.swift",
            templatePath: "ViewController.stencil"
        ),
        .file(
            path: "Sources/LaunchScreen.storyboard",
            templatePath: "LaunchScreen.stencil"
        )
    ]
)
  • root 폴더에 가서 scaffold 실행하고 다시 tuist generate로 생성
tuist scaffold app --name MyApp
tuist generate

-> 빌드하면 성공

* 전체 코드: https://github.com/JK0369/ExTuist_3 레포를 받고나서 아래처럼 project 생성 가능

git clone https://github.com/JK0369/ExTuist_3.git
cd ExTuist_3
tuist scaffold app --name {your_app_name}
tuist generate

* 참고

https://github.com/tuist/tuist

Comments