Summary

개발을 하다보면 소스코드를 문서화 해야하는 경우들이 종종 발생한다. 
내부적으로 볼 경우에는 주석을 잘달아서 소스코드를 직접 보면서 확인하면 되지만, 내부적으로 문서화 요청을 받거나 Wiki등록 혹은 외부에 공개해야하는 등의 경우에는 따로 문서를 만들어서 전달해야 한다. 이런 상황에서 각각의 클래스와 함수, 변수들을 정리하면서 문서로 만들면 아주 작은 프로젝트가 아닌이상 엄청난 노가다 작업을 필요로한다. 
하지만 세상은 많이 발전했고, 이런 작업을 대신해주는 소스코드 문서화 도구가 다양하게 존재한다. (사실 한참 전부터 존재했다.)
예를들어 C/C++은 doxygen, python은 Sphinx, Java는 Javadoc등, 그리고 이외에도 엄청 다양한 도구들이 존재한다.

하지만, 이 글에서는 Apple 소스코드의 문서화에 특화된 문서화 도구를 찾아보려고 한다. 그중에서도 Objective-c. (Swift는 추후에..)
Objective-C 기반이기 때문에 doxygen같은 C언어 관련 문서화 도구를 사용해도 되지만, 조금 더 욕심을 내서 애플 스타일 소스코드 문서화 형태로 만들어주는 도구를 사용해보도록 하자.
최근엔 다른 종류도 많이 나왔지만, 써본건 Appledoc, Headerdoc 두가지이다. 근데 Headerdoc은 애플 폐기 문서함에 들어가 있어서 왠지 쓰기 싫다.
그래서 Appledoc 으로 문서화 방법을 쓰려고 한다.
Appledoc은 기본 탬플릿을 제공하고, 커스터마이징된 탬플릿들도 찾아보면 몇가지 존재하고.. 일단 직접 문서를 보면서 직접 사용해보도록 하자.

Appledoc 설치

AppleDoc은 오픈소스로 공개되어있고, 스크립트를 실행하여 설치하거나 Homebrew를 사용하여 설치할 수 있다.
(스크립트를 이용하면 기본 탬플릿을 설치할 수 있고, Homebrew는 기본 탬플릿을 설치할 수 없다.)
#############
# Git clone #
#############
$ git clone git://github.com/tomaz/appledoc.git
#############################
# install appledoc - Script #
########## Case 1 ###########
#
$ sudo sh install-appledoc.sh
# 1-1. 릿 '-t default’
$ sudo sh install-appledoc.sh -t default
# 1-2. '-t {template_path}’ . (binary '-b {binary_path}')
$ sudo sh install-appledoc.sh -b /usr/bin -t ~/Library/Application\ Support/appledoc
###############################
# install appledoc - Homebrew #
########## Case 1 #############
# Homebrew (Homebrew 릿 )
$ brew install appledoc
설치가 완료되면, 'appledoc' 명령어를 입력해서 제대로 설치가 되었는지 확인해보자.
$ appledoc
appledoc version: 2.2.1 (build 1334)
Caught: AppledocException: At least one directory or file name path is required, use 'appledoc --help'

Appledoc 설치가 완료되면 바로 문서를 생성할 수 있다.
하지만, 바로 사용하려면 command에 여러가지 옵션들을 넣어서 실행을 해야 하기 때문에 프로젝트 내부에 문서화 옵션들을 미리 정의해놓고 사용하는 방법들을 알아보자.
미리 정의하지 않고 사용하면 아래처럼 사용해야 한다.
$ appledoc --project-name '' --project-company '' --template {릿 } --create-html --output ' ' .
# , .

프로젝트 내부 문서화 옵션 정의

문서화 옵션을 프로젝트내에 정의하는 방법은 plist 파일 추가, run script 추가 두가지 방법이 있다.
plist 파일을 생성하면 문서화 관련 옵션들을 plist로 쉽게 관리할 수 있는 장점이 있고,
run script를 사용하면 터미널을 열지 않고 문서화 타겟을 생성하여 빌드하면서 바로 문서를 생성할 수 있는 장점이 있다.
우선 두가지 모두 생성/사용 방법을 알아보자.
0. 공통
설정 가능한 전체 옵션이 궁금하다면 터미널에서 아래 명령어로 확인 가능하다.
$ appledoc --help
Usage: appledoc [OPTIONS] <paths to source dirs or files>
PATHS
-o, --output <path> Output path
-t, --templates <path> Template files path
--docset-install-path <path> DocSet installation path
-s, --include <path> Include static doc(s) at path
-i, --ignore <path> Ignore given path
-x, --exclude-output <path> Exclude given path from output
--index-desc <path> File including main index description
PROJECT INFO
-p, --project-name <string> Project name
-v, --project-version <string> Project version
-c, --project-company <string> Project company
--company-id <string> Company UTI (i.e. reverse DNS name)
OUTPUT GENERATION
-h, --create-html [b] Create HTML
-m, --create-markdown [b] Create markdown
-d, --create-docset [b] Create documentation set
-n, --install-docset [b] Install documentation set to Xcode
-u, --publish-docset [b] Prepare DocSet for publishing
--html-anchors <string> [*] The html anchor format to use in DocSet HTML.
--clean-output [b] Remove contents of output path before starting !!CAUTION!!
OPTIONS
--keep-intermediate-files [b] Keep intermediate files in output path
--keep-undocumented-objects [b] Keep undocumented objects
--keep-undocumented-members [b] Keep undocumented members
--search-undocumented-doc [b] Search undocumented members documentati
...
1. plist 사용
appledoc 오픈소스를 받으면 폴더내에 AppledocSettings.plist 라는 파일이 존재한다. 
직접 생성해도 전혀 문제는 없지만, 귀찮으니 있는 파일을 이용하도록 하자.
파일은 문서화를 하려는 프로젝트 root에 위치시키면 된다. (참고로 파일명은 AppledocSettings.plist 에서 바꿀 경우 설정을 변경해줘야 하므로 변경없이 쓰도록 하자)
plist파일은 터미널에서 명령어를 직접 입력할때 사용된다. (= 문서화를 터미널 명령어로 실행해야 한다)
아래 는 plist의 내부 모습이다. 각각 옵션값들이 어떤 역할을 하는지는 주석을 확인하자.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- Paths -->
<key>--output</key> <!-- -->
<string>./help</string>
<key>--templates</key> <!-- 릿 ( 릿 ) -->
<string>~./appledoc-jazzy</string>
<key>--include</key> <!-- , -->
<array>
<string>Libs/Internal</string>
</array>
<key>--ignore</key> <!-- , -->
<array>
<string>Libs/External</string>
<string>*.framework</string>
<string>Pods</string>
</array>
<!-- Output generation -->
<key>--create-html</key> <!-- HTML -->
<true/>
<key>--create-markdown</key> <!-- markdown -->
<true/>
<key>--create-docset</key> <!-- Documentation set -->
<true/>
<key>--install-docset</key> <!-- DocSet Xcode -->
<true/>
<key>--clean-output</key> <!-- ( !!) -->
<true/>
<!-- Project Info -->
<key>--project-name</key> <!-- -->
<string>AppleDoc Example</string>
<key>--project-version</key> <!-- -->
<string>1.0.0</string>
<key>--project-company</key> <!-- -->
<string>Tez Lab.</string>
<key>--company-id</key> <!-- Bundle id -->
<string>kr.tez.appledoc.exam</string>
<!-- Options -->
<key>--keep-intermediate-files</key> <!-- -->
<true/>
<key>--print-information-block-titles</key> <!-- "Note:", "Warning:", "TODO:" -->
<true/>
<key>--preprocess-headerdoc</key> <!-- preprocess header -->
<true/>
<key>--repeat-first-par</key> <!-- Repeat first paragraph in member documentation -->
<true/>
<key>--merge-categories</key> <!-- Category class base class -->
<true/>
<key>--merge-category-comment</key> <!-- Category class comment base class -->
<true/>
<key>--keep-merged-sections</key> <!-- -->
<true/>
<key>--prefix-merged-sections</key> <!-- category class category prefix -->
<true/>
<key>--explicit-crossref</key> <!-- -->
<true/>
<key>--use-code-order</key> <!-- Order sections by the order specified in the input files -->
<true/>
<key>--docs-section-title</key> <!-- ( "Programming Guides") -->
<string>Tez Programming Guides </string>
<key>--exit-threshold</key> <!-- (0: Success!, 1: At least one warning was logged., 2: At least one error was logged., 3: At least one fatal error was logged., 250: Unhandled exception (Oops message). -->
<integer>2</integer>
<!-- MISCELLANEOUS -->
<key>--logformat</key> <!-- Log format [0-3] -->
<integer>3</integer>
<key>--verbose</key> <!-- ( ) [0-6, xcode] -->
<string>6</string>
</dict>
</plist>
2. RunScript
run script를 사용하려면 프로젝트 타겟에 script를 추가해주어야 한다.
기존 타겟에 추가를 할 경우 다른 스크립트들과 충돌날 수도 있기 때문에 새로운 타겟을 하나 생성해서 추가하는게 정신건강에 이로울 수 있다.
정신건강을 위해 먼저 타겟 추가 방법을 알아보자.
프로젝트 설정 -> 타겟 쭉 아래쪽에 ‘+’버튼 -> Cross-platform -> Aggregate 선택 -> 네이밍은 마음대로 하고 Finish를 해주면 새로운 타겟이 생성된다.
이제 스크립트 추가 방법을 알아보자.
프로젝트 설정 -> 생성한 타겟 선택 -> Build Phases 에 ‘+’ 버튼을 눌러서 New Run Script Phases로 스크립트를 넣을 수 있도록 추가해주자
생성된 스크립트 입력 공간에 아래 정보를 자신의 프로젝트 설정에 맞춰서 넣어주도록 하자.
#Appledoc Script
/usr/local/bin/appledoc \
--clean-output \
--output "./help" \
--templates "~/.appledoc" \
--ignore "*.framework" \
--create-html \
--no-create-docset \
--no-install-docset \
--project-name "${PROJECT_NAME}" \
--project-version "${PROJECT_VERSION}" \
--project-company "Tez Lab." \
--company-id "kr.tez.appledoc" \
--docset-platform-family "iphoneos" \
--keep-intermediate-files \
--keep-undocumented-objects \
--keep-undocumented-members \
--search-undocumented-doc \
--print-information-block-titles \
--preprocess-headerdoc \
--repeat-first-par \
--merge-categories \
--merge-category-comment \
--keep-merged-sections \
--prefix-merged-sections \
--explicit-crossref \
--use-code-order \
--docs-section-title "${PROJECT_NAME} Programming Guides " \
--exit-threshold 2 \
--no-warn-missing-output-path \
--no-warn-missing-company-id \
--warn-undocumented-object \
--warn-undocumented-member \
--warn-empty-description \
--warn-unknown-directive \
--warn-invalid-crossref \
--warn-missing-arg \
--warn-unsupported-typedef-enum \
--logformat xcode \
--verbose "2" \
.

문서 생성

plist를 사용한 경우와 script를 추가한 경우 모두 알아보자
1. plist 사용
위에서 언급한 것처럼 plist를 사용하면 터미널에서 명령어로 실행해 주어야 한다. (옵션을 모두 추가해 두었기 때문에 생각보다 복잡하지는 않다.)
$ appledoc .
이렇게 명령어를 입력하면 주르르륵 로그들이 나오고 문서가 생성된다.
2. Script 사용
script 를 추가해둔 경우 target을 생성해 두었기 때문에 xcode 내에서 문서화를 위해 생성한 타겟 생성 후 build를 해주면 지정해둔 경로에 문서가 생성된다.

Tip. 특정 폴더 추가/제거

1. 특정 폴더 제거
문서화를 하면서 특정 폴더를 제거하고 싶다면 ignore 옵션을 넣어주면 된다 (run script 기준)
(GenerateDoc 타겟의 Build Phases -> 작성해둔 Run script에서 제외할 경로들을 아래처럼 --ignore로 추가)
#Appledoc Script
...
--ignore "<path>" \
...
2. 특정 폴더 추가
문서화를 하면서 일부 폴더만 선택해서 문서화를 하고 싶다면, 마지막에 문서화 경로를 추가해주면 된다. (Run script 기준)
--include 옵션은 제대로 처리를 할 수 없어서 다른 방법으로 알아보자.
제거하기와 마찬가지로 Run script를 수정하는데, 일부 폴더 추가는 모든 폴더를 제외시키고 포함시킬 폴더를 전부 넣어주자. 아래 참조
#Appledoc Script
...
--ignore "." \
...
. \
<path1> \
<path2>

Custom Templates

appledoc은 내부 탬플릿을 제공하기는 하지만, 사용자가 맞춤형으로 탬플릿을 수정하여 사용할 수 있다.
여기서는 간단히 오픈소스로 공유되고 있는 두가지 탬플릿만 알아보도록 하자.
1. jazzy
jazzy 탬플릿은 조금 더 애플 문서에 맞춤형으로 생성이 되어있는 탬플릿이다. 기본 제공되는 것보다 구성이 더 깔끔하게 정리되있는 정도라고 생각하면 된다.
https://github.com/kaiinui/appledoc-template-jazzy
2. tez-custom
이건 그냥 기본 탬플릿에 objective-c code syntax 적용한 버전이다. 함수나 변수들을 볼때 조금 더 직관적으로 보기 위해서 github에 추가해 두었다.
기존 문서에서 코드 부분에 조금 더 색을 입히고 싶을때 사용하면 된다.
https://github.com/tezpark/appledoc-custom-template
ps. 코드내에 문서화 주석이 없으면 이 모든 작업이 아무 소용없다.


반응형

Summary

개발을 하다보면 여러 객체들을 배열형태로 관리하면서 모든 객체에 어떤 함수를 호출시키는 작업이 필요한 경우가 있다.
예를 들면 UIView 의 subViews를 호출하여 for문을 돌면서 모두 removeFromSuperview를 하는게 있다.
이런 경우 makeObjectsPerformSelector를 이용하면 쉽게 해결할 수 있다.

Example

UIView - removeFromSuperview
// Default
for (UIView *view in [self.view subviews]) {
[view removeFromSuperview];
}
// using makeObjectsPerformSelector
[[self.view subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
ps. 이 예제 외에 다른 배열형태로 관리되는 객체들은 모두 적용이 가능해서 편리하게 사용할 수 있다.


반응형

Info

iOS, Android 프로젝트에서 배포를 위해 아카이브 파일 (.ipa), 패키지파일 (.apk) 을 추출하고 업로드 및 공유하는데 귀찮은 작업들이 상당히 많다.
(iOS는 scheme 바꾸고, 아카이빙하고 파일 추출하고 업로드하고 공유하고.., 안드로이드도 뭐 작업중에는 뭘 할 수가 없으니까 )

그래서 이런 귀찮은 작업을 좀 편하게 할 수 있는 방법을 찾다가 Fastlane 이라는 것을 찾다.
Fastlane 은 인증서 자동갱신, 스냅샷 추출, 아카이빙, crashlytics 배포, slack 공유, s3업로드, 테스트 플라이트, 앱스토어 등록 등등 다양한 동작을 하도록 구성할 수 있다.

자세한 내용은 아래 fastlane 사이트를 참고하는걸로 하고..
일단은 내부 배포를 위하여 프로젝트 내에서 provisioning 파일을 생성/갱신, 테스트용 뱃지 추가, 아카이브 후 추출, aws-s3에 파일 업로드, Crashlytics 에 배포 파일 업로드, slack에 결과 공유 까지만 작업을 하는 방법을 소개하려고 한다.

1. Fastlane 설치

기능을 사용하기 위해서 mac에 fastlane을 설치 해야한다. 설치 방법은 세가지가 있으니 자신의 mac 에서 주로 사용하는 방법을 선택하여 설치를 진행하면 된다.

(Homebrew 로 설치하면 fastlane 내부 ruby가 동작해서 작업이 귀찮아짐. ruby 모듈들을 fastlane 안에 ruby에 설치해줘야함. 맘편하게 Script로 설치하세요)


Homebrew

$ brew cask install fastlane

Installer Script

아래 링크에서 zip 파일을 다운로드 받고, install 스크립트를 실행

https://download.fastlane.tools/fastlane.zip

Rubygems

$ sudo gem install fastlane -NV



2. Fastlane 초기화

Fastfile, Appfile, .env 파일을 직접 생성해서 작업을 해도 되지만 귀찮으니까 iOS혹은 Android 프로젝트 루트에서 아래 명령어로 관련 파일들을 생성해주자
# fastlane
$ fastlane init
초기화 작업이 완료되면 ./fastlane 폴더 내부에 Fastfile, Appfile, .env 파일이 생성되어 기본적인 준비가 된다.


3. Plugin 설치 (aws_s3, badge) - optional

Badge

앱을 내부배포할 때 dev, stage등 여러가지 앱 스킴을 사용하는 경우들이 있는데 이럴경우 어떤 버전이 설치되어 있는지 직관적으로 알 수 있는 방법이 없다. 
그래서 badge 라는 plugin을 사용하여 앱 아이콘에 뱃지를 넣어주어 직관적인 버전 확인이 가능하도록 해줄 수 있다. 
아래를 참고하여 플러그인을 설치하고, 관련된 모듈들을 설치하도록 하자.
더 자세한 내용은 아래 사이트를 참고하자
# badge
$ fastlane add_plugin badge
#
$ brew install imagemagick
$ brew install librsvh

aws_s3

내부 배포를 위한 파일 서버가 S3로 설정되어 있는 경우 아카이브 파일 (.ipa), 패키지파일 (.apk) 을 생성한 후 Amazon S3 Bucket 으로 바로 전송을 할 수가 있다.
이 기능을 사용하려면 아래를 참고하여 S3 플러그인을 설치하면 되고, 조금 더 자세한 정보 및 사용법은 아래 링크에서 확인하면 된다.
# aws-s3
$ fastlane add_plugin aws_s3


4. Fastlane 파일 설정

이제 fastlane 초기 세팅 작업들은 마무리가 되었고, 실제로 동작시킬 내용들을 추가하는 방법을 알아보도록 하자.

Fastfile

우선 가장 핵심이 되는 Fastfile 에 대해서 살펴보자. 
이 파일은 platform과 lane 을 설정하고 lane 별로 어떤 동작을 시킬지, lane 실행전/후에 어떤 동작을 수행할 지 설정하는 곳이다.
아래 예제 파일을 보면서 동작들을 확인해보자.
# More documentation about how to customize your build
# can be found here:
# https://docs.fastlane.tools
fastlane_version "2.18.3"
# This value helps us track success metrics for Fastfiles
# we automatically generate. Feel free to remove this line
# once you get things running smoothly!
generated_fastfile_id "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" # fastfile
default_platform :ios
#######
# iOS #
#######
platform :ios do
before_all do
# lane
end
##################################################
# First iOS App Lanes - A
##################################################
lane :firstapp_debug do
# provisioning profile , ,
sigh
# (Optional) badge
# badge(dark: true) #
badge(shield: "Version-dev-red", no_badge: true) # shield
# iOS app build, archive, export
gym(
# workspace
workspace: "[Project path].xcworkspace", # [Project path]: xcworkspace (xcodeproj secondapp )
configuration: "Debug", # configuration
scheme: "[Project scheme]", # [Project scheme]: scheme
silent: true,
clean: true,
output_name: "[file name]", # [file name]:
include_symbols: false, # (optional)
include_bitcode: true, # (optional) - default:false
export_method: "development", # export method
)
# (Optional) S3
aws_s3(
access_key: ENV['S3_ACCESS_KEY'], # .env
secret_access_key: ENV['S3_SECRET_ACCESS_KEY'], # .env
bucket: ENV['S3_BUCKET'], # .env
region: ENV['S3_REGION'], # .env
path: '[bucket path]', # [bucket path]:
ipa: '[file name].ipa', # export
upload_metadata: true,
)
# (Optional) Crashlytics
crashlytics(
api_token: ENV['CRASHLYTICS_API_TOKEN'], # .env
build_secret: ENV['CRASHLYTICS_SECRET'] # .env
)
end
lane :firstapp_stage do
sigh
badge(shield: "Version-stage-blue", no_badge: true)
gym(
workspace: "[Project path]",
configuration: "Stage",
scheme: "[Project scheme]",
silent: true,
clean: true,
output_name: "[file name]",
include_symbols: false,
include_bitcode: true,
export_method: "ad-hoc",
)
aws_s3(
access_key: ENV['S3_ACCESS_KEY'],
secret_access_key: ENV['S3_SECRET_ACCESS_KEY'],
bucket: ENV['S3_BUCKET'],
region: ENV['S3_REGION'],
path: '[bucket path]',
ipa: '[file name].ipa',
upload_metadata: true,
)
crashlytics(
api_token: ENV['CRASHLYTICS_API_TOKEN'],
build_secret: ENV['CRASHLYTICS_SECRET']
)
end
###########################################################
# Second iOS App Lane - B iOS
###########################################################
lane :secondapp_debug do
sigh
badge(shield: "Version-dev-red", no_badge: true)
gym(
# project
project: "[Project path].xcodeproj", # [Project path]: xcodeproj
configuration: "Debug",
scheme: "[Project scheme]",
silent: true,
clean: true,
output_name: "[file name]",
include_symbols: false,
include_bitcode: true,
export_method: "development",
)
aws_s3(
access_key: ENV['S3_ACCESS_KEY'],
secret_access_key: ENV['S3_SECRET_ACCESS_KEY'],
bucket: ENV['S3_BUCKET'],
region: ENV['S3_REGION'],
path: '[bucket path]',
ipa: '[file name].ipa',
upload_metadata: true,
)
crashlytics(
api_token: ENV['CRASHLYTICS_API_TOKEN'],
build_secret: ENV['CRASHLYTICS_SECRET']
)
end
# lane
after_all do |lane|
# slack .
slack(
message: "FastLane success",
slack_url: ENV['SLACK_URL']
)
end
# lane
error do |lane, exception|
slack(
message: exception.message,
success: false,
slack_url: ENV['SLACK_URL']
)
end
end
##############################################################################################
##############################################################################################
###########
# Android #
###########
platform :android do
before_all do
end
##################################################
# First iOS App Lanes - A
##################################################
lane :firstapp_debug do
gradle(task: 'clean', project_dir: "[Project path]") # [Project path]: root
gradle(task: "assemble",
build_type: "Debug",
project_dir: "[Project path]") # [Project path]: root
# (Optional) shell script
# shell script Fastfile fastlane/
sh "mv ../firstapp_android/app/build/outputs/apk/firstapp-debug.apk ../firstapp_android/app/build/outputs/apk/[File name].apk" # [File name]:
# (Optional) S3
# plugin fastlane
aws_s3(
access_key: ENV['S3_ACCESS_KEY'], # .env
secret_access_key: ENV['S3_SECRET_ACCESS_KEY'], # .env
bucket: ENV['S3_BUCKET'], # .env
region: ENV['S3_REGION'], # .env
path: '[bucket path]', # [bucket path]:
ipa: './firstapp_android/app/build/outputs/apk/[File name].apk', # export
upload_metadata: true,
)
end
lane :firstapp_stage do
gradle(task: 'clean', project_dir: "[Project path]")
gradle(
task: "assemble",
build_type: "Release",
# signing
properties: {
# 'versionCode' => [version code], # (Optional) [version code]:
# 'versionName' => [version name], # (Optional) [version name]:
'android.injected.signing.store.file'=> ENV['ANDROID_APP_SIGNING_KEY'], # .env
'android.injected.signing.store.password'=> ENV['ANDROID_APP_SIGNING_PASSWORD'], # .env
'android.injected.signing.key.alias'=> ENV['ANDROID_APP_SIGNING_ALIAS'], # .env
'android.injected.signing.key.password'=> ENV['ANDROID_APP_SIGNING_PASSWORD'] # .env
},
project_dir: "[Project path]")
sh "mv ../firstapp_android/app/build/outputs/apk/firstapp-release.apk ../firstapp_android/app/build/outputs/apk/[File name].apk"
aws_s3(
access_key: ENV['S3_ACCESS_KEY'],
secret_access_key: ENV['S3_SECRET_ACCESS_KEY'],
bucket: ENV['S3_BUCKET'],
region: ENV['S3_REGION'],
path: '[bucket path]',
ipa: './firstapp_android/app/build/outputs/apk/[File name].apk',
upload_metadata: true,
)
end
after_all do |lane|
slack(
message: "FastLane success",
slack_url: ENV['SLACK_URL']
)
end
error do |lane, exception|
slack(
message: exception.message,
success: false,
slack_url: ENV['SLACK_URL']
)
end
end

.env

다음은 환경변수를 선언해 놓고 사용하는 dotenv 형태의 .env 파일이다.
이 파일에 선언된 값들을 Fastfile 에서 ENV[‘ ‘] 형태로 사용할 수 있다.
아래는 예제용으로 작성된 Fastfile의 .env 파일이다.
# for Slack
SLACK_URL="https://hooks.slack.com/services/~~~" # slack hook
# for S3
S3_ACCESS_KEY='XXXXXXX' # S3 Access key
S3_SECRET_ACCESS_KEY='xxxxxxxxxxxxxxxx' # S3 Sceret Access key
S3_BUCKET='example-buket' # S3 Bucket name
S3_REGION='ap-northeast-2' # S3 Region
# for Crashlytics
CRASHLYTICS_API_TOKEN='xxxxxxxxxxxxxxxx' # Crashlytics API token
CRASHLYTICS_SECRET='xxxxxxxxxxxxxxxx' # Crashlytics Secret
# for Android
ANDROID_APP_SIGNING_KEY='./keystore/firstapp_key.keystore' # Signing key
ANDROID_APP_SIGNING_PASSWORD='xxxx' # signing pw
ANDROID_APP_SIGNING_ALIAS='firstapp_android' # signing alias

Appfile

마지막으로 앱 관련 설정을 가지고 있는 Appfile 이다.
이 파을은 AppStore Id, Bundle Id, Team Id 등 식별자 값이 설정되어있는 파일이다.
Appfile 과 관련해서 더 자세한 내용은 링크를 참고하면 된다. (https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Appfile.md)
아래 파일도 예제용으로 작성된 FastfileAppfile 이다.
# Default
app_identifier "kr.tez.firstapp" # The bundle identifier of your app
apple_id "dev@tez.kr" # Your Apple email address
team_id "XXXXXXX" # Developer Portal Team ID
for_platform :ios do
for_lane :first_debug do
app_identifier "kr.tez.firstapp"
apple_id "dev@tez.kr"
team_id "XXXXXXX"
end
for_lane :first_stage do
app_identifier "kr.tez.firstapp"
apple_id "dev@tez.kr"
team_id "XXXXXXX"
end
for_lane :second_debug do
app_identifier "kr.tez.secondapp"
apple_id "tez_enterprise@tez.kr"
team_id "XYXYXYXY"
end
end
# you can even provide different app identifiers, Apple IDs and team names per lane:
# More information: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Appfile.md


5. Fastlane 기본 명령어

lane 과 파일 작성이 완료되면 몇가지 기본적인 명령어를 확인하고 사용해보도록 하자.

$ fastlane lanes

우선 사용가능한 lane들을 조회하는 명령어 이다. 
이 명령어로 추가해 놓은 lane들이 정상적으로 로드되는지 확인하면 된다.
$ fastlane lanes
+------------------------+---------+--------+
| Used plugins |
+------------------------+---------+--------+
| Plugin | Version | Action |
+------------------------+---------+--------+
| fastlane-plugin-aws_s3 | 0.2.4 | aws_s3 |
+------------------------+---------+--------+
[18:47:48]: -------------------------------------------------
[18:47:48]: --- Step: Verifying required fastlane version ---
[18:47:48]: -------------------------------------------------
[18:47:48]: Your fastlane version 2.28.7 matches the minimum requirement of 2.18.3
[18:47:48]: ------------------------------
[18:47:48]: --- Step: default_platform ---
[18:47:48]: ------------------------------
--------- ios---------
----- fastlane ios firstapp_debug
----- fastlane ios firstapp_stage
----- fastlane ios secondapp_debug
--------- android---------
----- fastlane android firstapp_debug
----- fastlane android firstapp_stage
Execute using `fastlane [lane_name]`

$ fastlane env

이 명령어는 fastlane 환경 체크를 하는 명령이다. 
fasatlane이 정상적으로 실행되지 않거나 정보를 확인할 경우 이용하면 된다.
$ fastlane env
...
#
...


6. Fastlane 실행

이제 기나긴 작업이 끝나고 완성된 lane들을 사용하는 방법이다!

작업은 길지만 실제 사용은 별거 없다. 
platform과 lane 을 선택해주면 설정해준 작업들이 수행된다.
fastlane {platform} {lane}
$ fastlane ios firstapp_debug
...
# working...
...
[13:48:03]: ▸ Archive Succeeded
...
[13:48:06]: Successfully exported and compressed dSYM file
[13:48:06]: Successfully exported and signed the ipa file:
...
[13:48:06]: -------------------
[13:48:06]: --- Step: slack ---
[13:48:06]: -------------------
[13:48:07]: Successfully sent Slack notification
+------+-------------------------------------+-------------+
| fastlane summary |
+------+-------------------------------------+-------------+
| Step | Action | Time (in s) |
+------+-------------------------------------+-------------+
| 1 | Verifying required fastlane version | 0 |
| 2 | default_platform | 0 |
| 3 | gym | 23 |
| 4 | slack | 1 |
+------+-------------------------------------+-------------+
...
[13:48:07]: fastlane.tools finished successfully
위와 같이 진행과정이 표시되고 모든 작업이 완료되면 fastlane.tools finished successfully 이라는 메시지와 함께 작업이 완료된다.


반응형