노블의 개발이야기

[iOS] Framework 만들기 본문

iOS

[iOS] Framework 만들기

더플러스 2015. 7. 14. 18:06

Framework 만들기


xCode 6 부터 손쉽게 Framework를 만들 수 있으나 iOS 8 이상에서만 사용할 수 있어 기존 static library를 Framework로 변경하여 사용해야한다.


XCode 6 Framework 만들기


1. Library를 Framework로 만들어 배포해야할 필요성

보통은 static library로 만들어서 Header 파일과 libXXX.a 파일을 배포하게 된다.

SDK 사용자는 Header와 libXXX.a 파일을 프로젝트에 추가하여 사용하는데 파일관리가 번거로울 수 있다.

Framework로 만들어서 배포하게 되면 사용자 입장에서는 .framework 하나만 추가하면 바로 개발이 가능해진다.


2. Framework 뼈대 만들기

https://github.com/jverkoey/iOS-Framework 를 참고하여 기술


Step 1. 프로젝트 생성


"Cocoa Touch Static Library" 선택

Product 이름은 "HelloSDK"로 생성하였다.


Step 2. 기본 Header 파일 생성

HelloSDK.framework를 프로젝트에 추가한 개발자는 이전의 framework를 사용하는 것과 같은 경험을 제공받기를 원할 것이다.

#import <HelloSDK/HelloSDK.h> 라는 기본 Header 파일만 import하면 HelloSDK.framework에 속할 클래스를 사용할 수 있도록 해야한다.


1) 새롭게 추가할 클래스를 생성한다. 예를 들어 "HelloInfo.h / HelloInfo.m" 파일을 추가한다.

2) HelloSDK.m 파일을 삭제한다.


3) Editor -> Add Build Phase -> Add Copy Headers Build Phase 선택 또는 + 를 눌러 "New Header Phase" 선택하여 Header를 생성한다. 


4) + 를 눌러 framework에 노출될 header 파일을 추가하고 Project에 존재하는 header 파일을 Pulbic으로 이동 시킨다.



Step 3. Public Headers Location 변경

static library 프로젝트를 만들면 기본적으로 Build Setting -> Package의 Public Headers Folder Path가 /user/local/include로 설정되어 있다. 

이 값을 "$(PROJECT_NAME)Headers"로 변경한다.


Step 4. Disable Code Stripping

Build Setting에서 아래와 같이 define값을 변경하여 준다.

변경해야하는 이유는 원문 참고


- Linking - "Dead Code Stripping" => No (for all setting)

- Deployment - "Strip Debug Symbols During Copy" => No (for all setting)

- Deployment - "Strip Style" => Non-Global Symbols (for all setting)





Step 5. Build Script 추가 (prepare_framework.sh)


set -e


mkdir -p "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Versions/A/Headers"

# Link the "Current" version to "A"

/bin/ln -sfh A "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Versions/Current"

/bin/ln -sfh Versions/Current/Headers "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Headers"

/bin/ln -sfh "Versions/Current/${PRODUCT_NAME}" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/${PRODUCT_NAME}"

# The -a ensures that the headers maintain the source modification date so that we don't constantly

# cause propagating rebuilds of files that import these headers.

/bin/cp -a "${TARGET_BUILD_DIR}/${PUBLIC_HEADERS_FOLDER_PATH}/" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Versions/A/Headers"


Editor -> Add Build Phase -> Add Run Script Build Phase



이 script는 framework가 되기 위한 폴더 구조를 만들어 준다.


-- Note: "->" denotes a symbolic link --

Headers/ -> Versions/Current/Headers
HelloSDK -> Versions/Current/HelloSDK
Versions/
  A/
    Headers/
      HelloSDK.h
      HelloInfo.h
  Current -> A



3. Framework Distribution Target 만들기

Step 1. Aggregate Target 생성
Click File -> New Target -> iOS -> Other and create a new Aggregate target.

Product Name은 "Framework"를 입력한다.

Step 2. Dependent Target에 Static Library 추가.


Step 3. Build Framework Script 추가.

Build Framework Script는 디바이스와 시뮬레이터용 .framework를 합쳐주는 역할을 한다. (Universal Framework)


set -e

set +u

# Avoid recursively calling this script.

if [[ $SF_MASTER_SCRIPT_RUNNING ]]

then

exit 0

fi

set -u

export SF_MASTER_SCRIPT_RUNNING=1


SF_TARGET_NAME=${PROJECT_NAME}

SF_EXECUTABLE_PATH="lib${SF_TARGET_NAME}.a"

SF_WRAPPER_NAME="${SF_TARGET_NAME}.framework"


# The following conditionals come from

# https://github.com/kstenerud/iOS-Universal-Framework


if [[ "$SDK_NAME" =~ ([A-Za-z]+) ]]

then

SF_SDK_PLATFORM=${BASH_REMATCH[1]}

else

echo "Could not find platform name from SDK_NAME: $SDK_NAME"

exit 1

fi


if [[ "$SDK_NAME" =~ ([0-9]+.*$) ]]

then

SF_SDK_VERSION=${BASH_REMATCH[1]}

else

echo "Could not find sdk version from SDK_NAME: $SDK_NAME"

exit 1

fi


if [[ "$SF_SDK_PLATFORM" = "iphoneos" ]]

then

SF_OTHER_PLATFORM=iphonesimulator

else

SF_OTHER_PLATFORM=iphoneos

fi


if [[ "$BUILT_PRODUCTS_DIR" =~ (.*)$SF_SDK_PLATFORM$ ]]

then

SF_OTHER_BUILT_PRODUCTS_DIR="${BASH_REMATCH[1]}${SF_OTHER_PLATFORM}"

else

echo "Could not find platform name from build products directory: $BUILT_PRODUCTS_DIR"

exit 1

fi


# Build the other platform.

xcrun xcodebuild -project "${PROJECT_FILE_PATH}" -target "${TARGET_NAME}" -configuration "${CONFIGURATION}" -sdk ${SF_OTHER_PLATFORM}${SF_SDK_VERSION} BUILD_DIR="${BUILD_DIR}" OBJROOT="${OBJROOT}" BUILD_ROOT="${BUILD_ROOT}" SYMROOT="${SYMROOT}" $ACTION


# Smash the two static libraries into one fat binary and store it in the .framework

xcrun lipo -create "${BUILT_PRODUCTS_DIR}/${SF_EXECUTABLE_PATH}" "${SF_OTHER_BUILT_PRODUCTS_DIR}/${SF_EXECUTABLE_PATH}" -output "${BUILT_PRODUCTS_DIR}/${SF_WRAPPER_NAME}/Versions/A/${SF_TARGET_NAME}"


# Copy the binary to the other architecture folder to have a complete framework in both.


cp -a "${BUILT_PRODUCTS_DIR}/${SF_WRAPPER_NAME}/Versions/A/${SF_TARGET_NAME}" "${SF_OTHER_BUILT_PRODUCTS_DIR}/${SF_WRAPPER_NAME}/Versions/A/${SF_TARGET_NAME}"





"Framework not found HelloSDK" 에러 발생...

타켓은 반드시 "Framework"로 빌드해야한다.




4. Framework 배포하기


Framework를 배포할때는 HelloSDK.framework 만 서드파티 개발자에게 전달하면 된다.

배포할때는 Release 계열을 배포한다. Universal Framework이기 때문에 Release-iphoneos, Release-iphonesimulator 둘 중 하나의 HelloSDK.framework만 배포하여도 된다.



FrameworkSample.zip



[참고 사이트]

iOS 라이브러리를 Framework 형태로 만들기 및 배포

How to Create a Framework for iOS

'iOS' 카테고리의 다른 글

[iOS] Storyboard - Animated Segues  (0) 2015.09.10
[iOS] In App Purchase  (0) 2015.07.24
[iOS] UIView에서 상위 UIVewController 가져오기  (0) 2015.07.13
[iOS] UIActivityViewController  (0) 2015.07.13
[iOS] UIActionSheet  (0) 2015.07.13
Comments