创建 iOS/OSX 框架: 在分发给其他开发人员之前是否有必要进行协同设计?

我正在学习如何创建 iOS 和 OSX 框架。让我们以 iOS 为例,以下步骤对我来说非常有效:

  1. Xcodebuild 框架使用 -sdk iphone 模拟器和 Build 操作
  2. Xcodebuild 框架使用-sdk iphoneos 和 Build 操作
  3. 使用 lipo 工具创建通用二进制,使 lipo -info产生预期效果:

脂肪文件中的架构: Foo.Framework/Foo 是: i386 x86 _ 64 armv7 arm64

问题是:

  1. 我读到我的框架可以由使用它的开发人员重新签名: “代码在复制上签名”,但我不明白它的先决条件是什么,即 在分发给其他开发人员之前,我是否应该加入协同设计步骤,使其与我的签名身份通用二进制?

  2. if previous is positive - should I use my "iPhone Distribution: ..." identity or "iPhone Developer: ..." is enough (so that my framework being a part of some iOS project passes all kinds of validations especially App Store validation)?.

我回答的背景是“ CodeSign 错误: SDK‘ iOS 8.3’中的产品类型‘ Framework’需要代码签名”,我在许多第三方框架和 迦太基 # 235或“代码对象根本没有被签名”(一个例子: 我在 王国 # 1998上报道的问题。

因此,我希望确保我的框架的用户在使用它们时不会遇到任何共同设计问题。

附言。当这个问题不是应用于单个开发人员而是应用于作为框架供应商的组织时,就会变得更加有趣。

36901 次浏览

From reading the linked thread on the Carthage repo it seems relatively simple. If you are distributing the binary framework you need to code sign it and if you are distributing the source via carthage or cocoa pods you do not as those tools take care of this via different methods.

The reason you need to code sign it when you distribute the binary framework is that Xcode won't produce a framework binary without code signing it. If you attempt to not code sign the binary framework you get this error:

CodeSign error: code signing is required for product type 'Framework' in SDK 'iOS 8.1'

It doesn't matter which identity you code sign the framework with (iPhone Developer or iPhone Distribution) because, as you point out, the framework will be re-codesigned with the "code sign on copy" setting. This means that your framework will be re-codesigned by the appropriate certificate from the framework consumer's developer profile when your framework is copied into their application. This means there will be no issues with the App Store as it will only see the final code signature from the framework consumer.

In the end of the day, you might as well code sign your .framework binary as you don't want to have to maintain an exotic build process, and as Xcode will only output signed frameworks you shouldn't move too far away from the defaults. It doesn't really matter anyway because the end consumer will be re-signing it.

I opened the bounty: "Looking for an answer drawing from credible and/or official sources." but haven't receive such since then.

While answer provided by @jackslash is correct, it tells only a part of story so I want to write my own in a way I would like to have seen it at the moment I was asking this question.

The actuality of this answer is: July 2015. It is most likely that things will change.

First of all let's assert that actions needed for correct code signing of framework should be divided into steps that framework's Developer has to take and steps that framework's Consumer has to take.

TLDR;

For OSX framework: Developer is free to distribute OSX framework without codesigning it as Consumer will re-codesign it anyway.

For iOS framework: Developer is free to distribute iOS framework without codesigning it as Consumer will re-codesign it anyway, but Developer is forced by Xcode to codesign their framework when they build for iOS device.

Because of radar: "iOS frameworks containing simulator slices can't be submitted to the App Store" Consumer of iOS framework is forced to run special script like "copy_frameworks" or "strip_frameworks" which uses lipo -remove to strip off simulator slices from iOS framework and re-codesigns stripped framework because at this point its codesigning identity whatever it was (or wasn't) is removed as side effect of lipo -remove manipulation.

Longer answer follows.


This answer is not a "drawing from credible and/or official sources" one but is rather based on a number of empiric observations.

Empiric observation #1: Consumer does not care because they will re-codesign framework they receive from Developer

Binary framework distributions of well-known open source projects on Github are not codesigned. Command codesign -d -vvvv gives: "code object is not signed at all" on all of the binary iOS and OSX frameworks I used to explore. Some examples: ReactiveCocoa and Mantle, Realm, PromiseKit.

From this observation it is clear that authors of these frameworks intend them to be codesigned by Consumer, on their behalf i.e. a Consumer must use either "Code Sign on Copy" flag in "Embed frameworks" build phase provided by Xcode or use some custom shell script which does the same thing manually: codesigns framework on the Consumer's behalf.

I didn't find any single example of the opposite: open source framework that would be distributed with codesigning identity in it so in the rest of the answer I am assuming this widely adopted approach as correct one: there is no need for framework Developer to distribute their framework to other developers with codesigning identity in it because Consumer will anyway re-codesign it.

Empiric observation #2 which applies to iOS only and which is entirely a Developer's concern

While Consumer does not care whether framework they receive from Developer is codesigned or not, Developer still needs to codesign their iOS framework as part of its build process when they build it for iOS device because otherwise Xcode does not build: CodeSign error: code signing is required for product type 'Framework' in SDK 'iOS 8.1'. To quote Justin Spahr-Summers:

OS X frameworks don't need to be codesigned at build... Unfortunately, Xcode does require that iOS frameworks be codesigned at build time.

This pretty well answers on my question #2: "iPhone Developer" identity is enough to cajole Xcode so that it would build iOS framework for device. This comment on Carthage#339 says the same thing.

Empiric observation #3: lipo tool

Specific behavior of lipo tool: when applied to framework binary, it always recursively removes any codesign identities from it: lipo -create/-remove codesigned framework ... -> not codesigned framework.

This could be an answer why all of the examples in observation #1 are not codesigned at all: their codesigning identity is blown away after lipo is applied but since according to observation #1 Consumer does not care it is fine.

This observation is especially relevant to the next observation #4 about AppStore.

Empiric observation #4: iOS frameworks containing simulator slices can't be submitted to the App Store

This is widely discussed in: Realm#1163 and Carthage#188 and radar is opened: rdar://19209161.

This is entirely Consumer's concern: for iOS universal framework that Consumer includes in their application, when application is being built, they must run special script (custom Run Script Phase) that removes simulator slice from that framework's binary so that app could pass AppStore validation.

The good example for binary frameworks I found in Realm: strip-frameworks.sh.

It uses lipo to remove all slices of architectures other than ${VALID_ARCHS} and then re-codesigns it with Consumer's identity - this is where observation #3 kicks in: framework is to be re-codesigned because of lipo manipulations on it.

Carthage has CopyFrameworks.swift script which does the same thing to all the frameworks included by Consumer: it strips off the simulator slices and re-codesigns framework on behalf on Consumer.

Also there is good article: Stripping Unwanted Architectures From Dynamic Libraries In Xcode.


Now the overview of steps required to produce both iOS and OSX from both Developer's and Consumer's perspectives. First the easier one:

OSX

Developer:

  1. Builds OSX framework
  2. Gives it to Consumer

No codesigning activities are required from Developer.

Consumer:

  1. Receives OSX framework from Developer
  2. Copies framework to Frameworks/ directory and codesigns it automatically on their, Consumer's, behalf as part of "Code Sign on Copy" process.

iOS

Developer:

  1. Builds iOS framework for device. Codesigning is required by Xcode, "iPhone Developer" identity is enough.
  2. Builds iOS framework for simulator.
  3. Uses lipo that produces universal iOS framework from previous two. At this point the codesigning identity of 1 step is lost: universal framework binary "is not signed at all" but that is fine since "Consumer does not care".
  4. Gives it to Consumer

Consumer:

  1. Receives iOS framework from Developer
  2. Copies framework to Frameworks/ directory (this step may be redundant depending on what script in step 3 is.)
  3. Uses special script as a part of build process: this script strips simulator slices off the iOS framework and then re-codesigns it on their, Consumer's, behalf.