"뚱뚱한"Cocoa Touch Framework를 내보내는 방법 (시뮬레이터 및 장치 용)?


107

Xcode 6 을 사용하면 Dynamic Cocoa Frameworks.

여기에 이미지 설명 입력

때문에:

  • 시뮬레이터는 여전히 32-bit라이브러리를 사용 합니다.

  • 2015 년 6 월 1 일부터 App Store에 제출 된 앱 업데이트는 64 비트 지원을 포함해야하며 iOS 8 SDK ( developer.apple.com ) 로 빌드되어야합니다.

우리는 장치와 시뮬레이터에서 프로젝트를 실행하기 위해 팻 라이브러리를 만들어야합니다. 즉, 프레임 워크에서 32 비트와 64 비트를 모두 지원합니다.

그러나 다른 프로젝트와의 향후 통합을 위해 범용 팻 프레임 워크 를 내보내는 방법 (그리고이 라이브러리를 다른 사람과 공유 하는 방법)을 찾지 못했습니다 .

재현하는 단계는 다음과 같습니다.

  1. 설정 ONLY_ACTIVE_ARCH=NOBuild Settings

    여기에 이미지 설명 입력

  2. 지원을 추가 armv7 armv7s arm64 i386 x86_64Architectures(확실히)

여기에 이미지 설명 입력

  1. 프레임 워크를 빌드하고 Finder에서 엽니 다.

여기에 이미지 설명 입력 여기에 이미지 설명 입력

  1. 이 프레임 워크를 다른 프로젝트에 추가

실제 결과:

그러나 결국 장치와 시뮬레이터에서이 프레임 워크를 사용하여 한 번에 프로젝트를 실행하는 데 여전히 문제가 있습니다.

  • Debug-iphoneos폴더 에서 프레임 워크를 가져 오면 장치에서 작동하고 시뮬레이터에서 오류가 발생합니다.ld: symbol(s) not found for architecture i386

      xcrun lipo -info CoreActionSheetPicker

    fat 파일의 아키텍처 : CoreActionSheetPicker는 다음과 같습니다. armv7 armv7s arm64

  • Debug-iphonesimulator폴더 에서 프레임 워크를 가져 오면 시뮬레이터에서 작동합니다. 장치에 오류가 있습니다.ld: symbol(s) not found for architecture arm64

      xcrun lipo -info CoreActionSheetPicker

    fat 파일의 아키텍처 : CoreActionSheetPicker : i386 x86_64

그렇다면 장치와 시뮬레이터에서 작동하는 동적 프레임 워크를 만드는 방법은 무엇입니까?

이 답변은 Xcode 6 iOS Cocoa Touch Framework 만들기-아키텍처 문제와 관련이 있지만 중복되지는 않습니다.


최신 정보:

이 사건에 대한 "더티 핵"을 찾았습니다. 아래 내 대답을 참조하십시오 . 누군가가 더 편리한 방법을 알고 있다면 알려주세요!



@ AndriusSteponavičius이 질문은 2 개월 전에 질문되었습니다.
skywinder

네,하지만 훨씬 더 나는 사용자가 알아야 할 생각, 거기에 대한 답변이 자세히 설명되어 있습니다
안드리 Steponavičius

빌드 설정에서 ONLY_ACTIVE_ARCH = NO로 설정하는 것은 중요한 단계입니다.
Jedidja

컴퓨터에 64 비트 아키텍처가 있더라도 시뮬레이터에서 실행하려면 프레임 워크에 팻 바이너리의 i386 x86_64 슬라이스가 모두 필요합니다 !!! 어려운 방법을 배웠습니다.
J.beenie 2017 년

답변:


82

이 답변의 실제는 2015 년 7 월입니다. 상황이 바뀔 가능성이 가장 높습니다.

TLDR;

현재 Xcode에는 범용 fat 프레임 워크를 자동으로 내보내는 도구가 없으므로 개발자는 lipo도구 를 수동으로 사용해야합니다 . 또한 이 레이더 에 따르면 프레임 워크의 소비자 인 AppStore 개발자에게 제출하기 전에 프레임 워크에서 lipo시뮬레이터 슬라이스를 제거 하는 데 사용해야합니다 .

더 긴 대답은 다음과 같습니다.


나는 주제 (답변 하단의 링크)에서 비슷한 연구를 수행했습니다.

내 연구가 애플 개발자 포럼, 카르타고와 영역 프로젝트와 내 자신의 실험 탐구를 기반으로 그래서 배포에 대한 공식 문서를 찾을 수 없습니다했다 xcodebuild, lipo, codesign도구를.

다음은 Apple Developer Forums thread Exporting app with Embedded framework 의 긴 인용문입니다 (나의 약간의 마크 업 포함) .

프레임 워크 프로젝트에서 프레임 워크를 내보내는 적절한 방법은 무엇입니까?

현재 유일한 방법은 정확히 수행 한 작업입니다.

  • 시뮬레이터 및 iOS 장치 모두에 대한 대상을 빌드하십시오.
  • 해당 프로젝트에 대한 Xcode의 DerivedData 폴더로 이동하고 두 바이너리를 하나의 단일 프레임 워크로 통합합니다. 그러나 Xcode에서 프레임 워크 타겟을 빌드 할 때는 타겟 설정 'Build Active Architecture Only'를 'NO'로 조정해야합니다. 이렇게하면 Xcode가 여러 binarty 유형 (arm64, armv7 등)에 대한 대상을 빌드 할 수 있습니다. 이것이 Xcode에서 작동하지만 독립 실행 형 바이너리로는 작동하지 않는 이유입니다.

  • 또한 스키마가 릴리스 빌드로 설정되어 있는지 확인하고 릴리스에 대한 프레임 워크 대상을 빌드해야합니다. 라이브러리가로드되지 않음 오류가 계속 발생하는 경우 프레임 워크의 코드 조각을 확인하십시오.

  • lipo -info MyFramworkBinary결과를 사용 하고 검토하십시오.

lipo -info MyFrameworkBinary

결과는 i386 x86_64 armv7 arm64

  • 현대의 범용 프레임 워크에는 4 개의 슬라이스가 포함되지만 더 포함 할 수 있습니다. i386 x86_64 armv7 arm64 이 4 개 이상이 표시되지 않으면 Build Active Architecture 설정 때문입니다.

이것은 @skywinder가 대답에서 한 것과 거의 동일한 프로세스를 설명합니다.

이것이 Carthage가 lipo를 사용 하고 Realm이 lipo를 사용 하는 방법 입니다.


중요 사항

레이더가 있습니다 : Xcode 6.1.1 & 6.2 : 시뮬레이터 슬라이스가 포함 된 iOS 프레임 워크는 App Store에 제출할 수 없으며 Realm # 1163Carthage # 188 에 대한 긴 토론 이 특별한 해결 방법으로 끝났습니다.

AppStore에 제출하기 전에 iOS 프레임 워크 바이너리를 시뮬레이터 슬라이스에서 제거해야합니다.

Carthage에는 특수 코드 인 CopyFrameworks 및 해당 문서가 있습니다.

이 스크립트는 범용 바이너리에 의해 트리거 된 App Store 제출 버그를 해결 합니다.

Realm은 특별한 스크립트를 가지고 있습니다 : strip-frameworks.sh 및 해당 문서 :

이 단계는 범용 바이너리를 보관할 때 App Store 제출 버그를 해결하는 데 필요 합니다.

또한 좋은 기사 : Stripping Unwanted Architectures From Dynamic Libraries In Xcode .

strip-frameworks.sh물론 누구나 처음부터 자유롭게 작성할 수 있지만 수정없이 완벽하게 작동 하는 Realm을 사용 했습니다.


이 질문의 또 다른 측면이 포함되어 있기 때문에 읽어 보도록 권장하는 내 주제에 대한 링크 : 코드 서명 -iOS / OSX 프레임 워크 생성 : 다른 개발자에게 배포하기 전에 코드 서명 해야합니까?


1
나는 lipo를 사용했지만 프레임 워크가 시뮬레이터에서 빌드 될 때 클래스 이름으로 해결되지 않은 식별자를 표시하지만 장치에서는 작동합니다. 바이너리의 시뮬레이터 버전을 사용하면 작동합니다. .. 어떤 생각이 있습니까?
Susim Samanta

2
/ : 저는 12 월 2016 년이 엑스 코드 8.2 변경 한 모든 증거를 발견하지 않았습니다
제프리 와이즈만

1
@Geoffrey, 이것이 Xcode 9.2에서 변경되었거나 다른 점이 있습니까? ... 이것은 배포를위한 바이너리 프레임 워크를 만들어 내 처음이다, 나는 이미 무서워
ScottyB

슬프게도이 일을 조금도하지 않았습니다. 말할 수 없습니다. 행운을 빕니다.
Geoffrey Wiseman

57

이것은 그렇게 명확한 해결책은 아니지만 내가 찾는 유일한 방법이 있습니다.

  1. 설정 ONLY_ACTIVE_ARCH=NOBuild Settings

    • 시뮬레이터 용 라이브러리 빌드
    • 장치 용 라이브러리 빌드
  2. Products프레임 워크의 콘솔 폴더 에서 열기 (프레임 워크 폴더를 열고 cd ..거기에서 열 수 있음)

여기에 이미지 설명 입력 여기에 이미지 설명 입력

  1. 폴더 에서이 스크립트를 실행하십시오 Products. 이 폴더에 fat Framework를 생성합니다. (또는 아래 3. 4에 설명 된대로 수동으로 수행하십시오 . )

또는:

  1. 이 스크립트로 lipo 를 사용하여이 두 프레임 워크를 결합 YourFrameworkName합니다 (프레임 워크 이름으로 대체 ).

    lipo -create -output "YourFrameworkName" "Debug-iphonesimulator/YourFrameworkName.framework/YourFrameworkName" "Debug-iphoneos/YourFrameworkName.framework/YourFrameworkName"
  2. 기존 프레임 워크 중 하나의 새 바이너리로 교체합니다.

    cp -R Debug-iphoneos/YourFrameworkName.framework ./YourFrameworkName.framework
    mv YourFrameworkName ./YourFrameworkName.framework/YourFrameworkName

  1. 이익 : ./YourFrameworkName.framework- 즉시 사용 가능한 팻 바이너리입니다! 프로젝트로 가져올 수 있습니다!

작업 공간에없는 프로젝트의 경우 :

여기에 설명 된 대로이 요점 을 사용해 볼 수도 있습니다 . 그러나 작업 공간의 프로젝트에는 작동하지 않는 것 같습니다.


나는 애플이 더 이상 뚱뚱한 바이너리를 받아들이지 않는다고 생각했다. kodmunki.wordpress.com/2015/03/04/…
Monstieur

1
@skywinder 팻 바이너리를 사용하기 위해 Cocoa Touch Framework를 내보내는 다른 간단한 방법을 찾았습니까? 위와 동일한 접근 방식을 사용하고 있지만 마음에 들지 않습니다. Xcode에는 프로세스를 자동화하는 일부가 있어야합니다.
dev gr

1
@devgr 아직 .. 그래서 내 대답을 받아들이지 않았습니다. 여전히 더 나은 솔루션을 찾고 있습니다.
skywinder

1
시뮬레이터에서는 실행할 수 없지만 3 단계와 4 단계의 장치에서 작동합니다
jose920405

1
@ Debug-폴더 만 사용 하는 이유를 누구든지 설명 할 수 lipo -create있습니까? 이 프레임 워크를 Release구성에 사용할 수 있으며 그 이유는 무엇입니까? 감사.
Yevhen Dubinin

10

@Stainlav 답변은 매우 유용했지만 대신 두 가지 버전의 프레임 워크 (하나는 장치 용, 다른 하나는 시뮬레이터 용)를 Run Script Phase컴파일 한 다음 실행중인 아키텍처에 필요한 미리 컴파일 된 프레임 워크를 자동으로 복사하기 위해 다음 을 추가했습니다.

echo "Copying frameworks for architecture: $CURRENT_ARCH"
if [ "${CURRENT_ARCH}" = "x86_64" ] || [ "${CURRENT_ARCH}" = "i386" ]; then
  cp -af "${SRCROOT}/Frameworks/Simulator/." "${SRCROOT}/Frameworks/Active"
else
  cp -af "${SRCROOT}/Frameworks/Device/." "${SRCROOT}/Frameworks/Active"
fi

이런 식으로 저는 lipoRealm strip-frameworks.sh이 App Store에 제출할 때 불필요한 슬라이스를 제거하는 데 사용할 수없는 팻 프레임 워크를 만들 필요가 없습니다 .


어느 쪽과 연결합니까?
Jaka Jančar

@ JakaJančar 나는 ${SRCROOT}/Frameworks/Active폴더 에있는 것들에 대해 링크 합니다. 컴파일 타임에 활성 아키텍처에 적합한 사전 컴파일 된 프레임 워크로 대체됩니다.
odm

2
그것을 사랑하십시오! 이것은 결합 후 분리 lipo방식 보다 훨씬 간단합니다 .
clozach

2

기본적으로 나는 아주 좋은 해결책을 찾았습니다. 이 간단한 단계를 따르기 만하면됩니다.

  1. 코코아 터치 프레임 워크를 만듭니다.
  2. 활성화 된 비트 코드를 아니요로 설정합니다.
  3. 대상을 선택하고 편집 구성표를 선택하십시오. 실행을 선택하고 정보 탭에서 릴리스를 선택합니다.
  4. 다른 설정은 필요하지 않습니다.
  5. 이제 시뮬레이터가 x86 아키텍처에서 실행되므로 모든 시뮬레이터에 대한 프레임 워크를 빌드하십시오.
  6. Project Navigator에서 Products 그룹을 클릭하고 .framework 파일을 찾습니다.
  7. 그것을 마우스 오른쪽 버튼으로 클릭하고 Finder에 표시를 클릭하십시오. 아무 폴더 에나 복사하여 붙여 넣으십시오. 개인적으로 '시뮬레이터'라는 이름을 선호합니다.
  8. 이제 Generic iOS Device 용 프레임 워크를 빌드하고 6-9 단계를 따르십시오. 폴더 이름을 'simulator'대신 'device'로 변경하면됩니다.
  9. 장치 .framework 파일을 복사하고 다른 디렉토리에 붙여 넣습니다. 나는 둘 다의 즉각적인 슈퍼 디렉토리를 선호합니다. 따라서 디렉토리 구조는 다음과 같습니다.
    • 데스크탑
    • 장치
      • MyFramework.framework
    • 모의 실험 장치
      • MyFramework.framework
    • MyFramework.framework 이제 터미널을 열고 데스크탑으로 cd합니다. 이제 다음 명령을 입력하십시오.

lipo -create 'device / MyFramework.framework / MyFramework' 'simulator / MyFramework.framework / MyFramework'-output 'MyFramework.framework / MyFramework'

그리고 그게 다야. 여기서 우리는 MyFramework.framework 안에있는 MyFramework 바이너리의 시뮬레이터와 장치 버전을 병합합니다. 시뮬레이터 및 장치를 포함한 모든 아키텍처를 위해 빌드되는 범용 프레임 워크를 얻습니다.


비트 코드가 활성화 된 FAT 파일을 만들고 싶습니다. 나를 안내 해주세요.
user3898700

2

@odm 의이 훌륭한 답변 을 업데이트 하고 싶습니다. Xcode 10 이후 CURRENT_ARCH변수는 더 이상 빌드 아키텍처를 반영하지 않습니다. 그래서 대신 플랫폼을 확인하도록 스크립트를 변경했습니다.

echo "Copying frameworks for platform: $PLATFORM_NAME"
rm -R "${SRCROOT}/Frameworks/Active"
if [ "${PLATFORM_NAME}" = "iphonesimulator" ]; then
    cp -af "${SRCROOT}/Frameworks/Simulator/." "${SRCROOT}/Frameworks/Active"
else
    cp -af "${SRCROOT}/Frameworks/Device/." "${SRCROOT}/Frameworks/Active"
fi

또한 복사하기 전에 대상 디렉터리를 지우는 줄을 추가했습니다. 그렇지 않으면 하위 디렉터리의 추가 파일을 덮어 쓰지 않을 것임을 알았습니다.


1

내 답변은 아래 사항을 다룹니다.

  • 시뮬레이터와 장치 모두에서 작동하는 프레임 워크 만들기

  • "뚱뚱한"Cocoa Touch Framework를 내보내는 방법 (시뮬레이터 및 장치 모두)?

  • 아키텍처 x86_64에 대한 정의되지 않은 기호

  • ld : 아키텍처 x86_64에 대한 기호를 찾을 수 없습니다.

1 단계 : 먼저 Simulator 타겟으로 프레임 워크 빌드

2 단계 : 시뮬레이터 빌드 프로세스가 성공한 후 이제 장치 대상 선택 또는 일반 iOS 장치 선택으로 프레임 워크 용으로 빌드합니다.

3 단계 : 이제 프레임 워크 대상을 선택하고 "Build Phases"에서 "Add Run Script"를 선택하고 아래 스크립트 코드를 복사합니다.)

4 단계 : 이제 마지막으로 다시 빌드하면 프레임 워크가 시뮬레이터 및 기기 호환성을 모두 사용할 수 있습니다. 만세!!!!

[참고 : 최종 4 단계 이전에 호환 가능한 프레임 워크가 모두 준비되어 있어야합니다 (시뮬레이터 및 기기 아키텍처 호환 가능, 그렇지 않은 경우 위의 1 단계 및 2 단계를 올바르게 수행하십시오).

참조 이미지보기 :

여기에 이미지 설명 입력

여기에 이미지 설명 입력

쉘 영역에 아래 코드를 넣으십시오.

#!/bin/sh


UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal


# make sure the output directory exists

mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"


# Step 1. Build Device and Simulator versions

xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos  BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build

xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build


# Step 2. Copy the framework structure (from iphoneos build) to the universal folder

cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"


# Step 3. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory

SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/."

if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then

cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"

fi


# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory

lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"


# Step 5. Convenience step to copy the framework to the project's directory

cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"


# Step 6. Convenience step to open the project's directory in Finder

open "${BUILD_DIR}/${CONFIGURATION}-universal"


이 스크립트는 자신을 호출하여 무한 루프를 일으키는 것 같습니다 !! 컴퓨터를 실행 한 후 다시 시작해야했습니다! 계속해서 새로운 xcodebuild 프로세스를 생성하고 새 파인더 창을
열었

재귀 문제가없는 유사한 스크립트에 대한 이 SO Q / A 에서 @ l0gg3r의 답변을 확인하십시오 .
J.beenie 2017 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.