iOS开发:创建动态 framework 和包含资源文件的 bundle

一、创建 framework

在 Xcode 中,首先建立一个新 project,命名为 JYUIAnimate ,类别选择Cocoa Touch Framework

导入所需文件JYUIAnimateView.hJYUIAnimateView.m。默认地,文件对外不可见,此时的工程设置为(TARGETS->Build Phases->Headers):

image-2

注意上图中,Public 意味着头文件对外可见,Project 意味着头文件对工程可见而对外不可见,也就是私有。Private有些误导,其头文件仍然是暴露的。因此大多时候,将头文件放置在PublicProject中即可。

要暴露出JYUIAnimateView.h头文件,需要在工程中进行设置,以及在工程头文件JYUIAnimate.h中包含JYUIAnimateView.h。首先:

image-3

相同效果的另外一种办法是在 File inspector 中设置,选择 Public 即可:

image-4

其次,在工程头文件中加入代码:

#import <JYUIAnimate/JYUIAnimateView.h>

这样就可以运行 Cmd+B 来 Build framework 了。

二、使用 framework

新建一个 project,命名为JYUIAnimateApp。可以把上一步骤中 build 得到的 framework 包含进来,也可以直接包含工程文件(便于调试源码)。

需要进行的工程设置为(TARGETS->General->Embedded Binaries):

image-5

否则会报错:

dyld: Library not loaded: @rpath...
  Referenced from: ...
  Reason: image not found

也可以直接将 JYUIAnimate 工程拖进JYUIAnimateApp中,此时需要额外添加进 TARGETS->Build Phases->Target Dependencies。

在需要使用 framework 的代码中添加:

#import <JYUIAnimate/JYUIAnimate.h>

即可使用对外的头文件中的内容。

三、创建适用全平台的 framework

在创建 framework 的时候会发现,选择不同目标(真机 / 模拟器)会生成不同的 framework,而该 framework 也只能用于真机 / 模拟器调试。这是由于不同平台的架构不同:

  • arm7:用于iOS 7的较老设备
  • arm7s:用于iPhone 5和5C
  • arm64:64位的 ARM 处理器
  • i386:32位模拟器
  • x86_64:64位模拟器

查看 framework 适用架构的命令:

lipo -info <framework>

而选择不同目标运行时,Xcode 只会 build 需要的版本,以缩短时间。当 archive app 时,Xcode 会 build 出3种 ARM 架构适用的 framework。

但是我们一般希望 framework 是通用的,也就是说可以适用于以上5种平台,这就需要做些额外的工作。

在 TARGETS 处点击页面下方的 + 号以增加一个 target,选择 Cross-platform 中的 Aggregate

image-6

命名为JYUIAnimateAggregate。再在TARGETS->Build Phases->Target Dependencies中添加:

image-7

再新建一个脚本来得到通用的 framework:

image-8

添加以下脚本:

# Sets the target folders and the final
#framework product. 
FMK_NAME=${PROJECT_NAME}
# Install dir will be the final output to
#the framework.
# The following line create it in the root
#folder of the current project.
INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework
# Working dir will be deleted after the
#framework creation.
WRK_DIR=build
DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework
SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework
# -configuration ${CONFIGURATION}
# Clean and Building both architectures.

# workaround for bitcode generation problem with Xcode 7.3
unset TOOLCHAINS

xcodebuild BITCODE_GENERATION_MODE=bitcode ENABLE_BITCODE=YES -configuration "Release" OTHER_CFLAGS="-fembed-bitcode" -target "${FMK_NAME}" -sdk iphoneos clean build

xcodebuild BITCODE_GENERATION_MODE=bitcode ENABLE_BITCODE=YES -configuration "Release" OTHER_CFLAGS="-fembed-bitcode" -target "${FMK_NAME}" -sdk iphonesimulator clean build


# Cleaning the oldest.
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
# Uses the Lipo Tool to merge both binary
#files (i386 + armv6/armv7) into one
#Universal final product.
lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/${FMK_NAME}"
rm -r "${WRK_DIR}"
open "${SRCROOT}/Products"

选择 scheme 为 aggregate,build 完成后,会自动打开放置通用 framework 的文件夹。

再像上面步骤添加到JYUIAnimateApp工程中后,即可使用真机或模拟器调试。

四、创建包含资源文件的 bundle

framework 只能包含头文件和代码,而不能包含图片和 storyboard 等资源文件。这时就需要创建 bunble 来保存这些资源,以在其他工程中使用。

JYUIAnimate 工程中再添加一个 target(选择 macOS 中的 bundle),命名为JYUIAnimateBundle

image-10

由于默认在 macOS 中使用,需要进行一些其他的设置:

选择JYUIAnimateBundle,在 Build Settings 中搜索「base sdk」,选中该行并按下 delete,得到的结果如图:

image-11

搜索「product name」,双击编辑,将内容替换为 JYUIAnimate:

image-12

搜索「hidpi」,将COMBINE_HIDPI_IMAGES设置为 NO

image-13

下面,为了确保在 build framework 时一起 build bundle,将该 bundle 设置为 aggregate 的 target dependency。

image-14

要将 bundle 文件与得到的通用 framework 放在同一路径,需要在上面的脚本底部添加:

# Copy the resources bundle
ditto "${BUILT_PRODUCTS_DIR}/${FMK_NAME}.bundle" \
"${SRCROOT}/Products/${FMK_NAME}.bundle"

如果遇到报错提示:

ld: -bundle and -bitcode_bundle (Xcode setting ENABLE_BITCODE=YES) cannot be used together

需要将 bundle target 的 bitcode 选项设置为 NO

添加资源到 bundle

在 TARGETS 中选择JYUIAnimateBundle,在 Build Phases->Copy Bundle Resources 中将需要放在 bundle 中的资源添加进来:

image-15

或者在选中资源文件时,在右侧的 File inspector 中选择:

image-16

五、使用 bundle

将 bundle 文件也添加到JYUIAnimateApp工程后,拖动 bundle 文件到 Build Phases 中的 Copy Bundle Resources(如果不包含 bundle 的话)。

使用JYUIAnimateBundle中图片的示例代码:

UIImage *image = [UIImage imageNamed:@"1" inBundle:[NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"JYUIAnimate" ofType: @"bundle"]] compatibleWithTraitCollection:nil];

六、上传 App Store 报错

以上步骤在真机上运行没有问题,但是上传 App Store 可能遇到报错:

ERROR ITMS-90087: "Unsupported Architecture. The executable for ... contains unsupported architecture '[x86_64, i386]'."
ERROR ITMS-90209: "Invalid segment Alignment. The App Binary at '...' does not have proper segment alignment. Try rebuilding the app with the latest xcode version." 

这是由于 framework 包含了全平台的 build,上传时需要去掉模拟器相关架构 [x86_64, i386]。解决方案参考Submit to App Store issues: Unsupported Architecture x86,选择 JYUIAnimateApp 的 target,类似之前的步骤在 Build Phases 中添加脚本:

APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"

# This script loops through the frameworks embedded in the application and
# removes unused architectures.
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
    FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
    FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
    echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"

    EXTRACTED_ARCHS=()

    for ARCH in $ARCHS
    do
        echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
        lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
        EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
    done

    echo "Merging extracted architectures: ${ARCHS}"
    lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
    rm "${EXTRACTED_ARCHS[@]}"

    echo "Replacing original executable with thinned version"
    rm "$FRAMEWORK_EXECUTABLE_PATH"
    mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"

done

注意:需要勾选下面的选项,如图所示

问题解决。

另外一种报错信息为:

ERROR ITMS-90166: "Missing Code Signing Entitlements. No entitlements found in bundle '...' for executable '...'."

解决方法:右击 bundle 文件->显示包文件,找到 info.plist 文件,有 Executable file 一行,删除。如果有个可执行文件并且遇到报错:

ERROR ITMS-90171: "Invalid Bundle Structure - The binary file '...' is not permitted. Your app can't contain standalone executables or libraries, other than the CFBundleExecutable of supported bundles." 

把该报错的可执行文件删除即可。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容