×

iOS制作framework

96
纪小衰
2016.09.13 22:46* 字数 2315

转载请注明出处:

http://www.jianshu.com/p/04a7e28f11b9

作者:纪小衰

framework的使用十分方便,一般来说直接拖入到项目中就可以直接使用接口,而不用在意具体的实现细节,对于功能的封装是个很好的途径。当我们写的工具给别人使用的同时又不想让别人知道自己的代码,这个时候使用framework就可以派上用场了(ps:个人觉得开源是一个大牛必须要体会到的思想)。。。

废话不多说,xcode如今已经到了7,对于framework的制作可以说是十分方便了。公司之前的framework的制作都是采用执行纯脚本的方法,可以直接命令行编译和融合不同版本(模拟器,真机,debug,release)的framework,个人不是很喜欢,还是喜欢用较为官方的方式来制作framework,当然为了方便还是少量地参照了网上的一些脚本。

一、新建framework工程


xcode->file->new->project选中iOS下的cocoa touch framework->next

创建工程

接下来的步骤和创建一个普通的工程没什么区别,创建完毕以后在工程中新建JRModel类和JRModel2类文件,在我们的framework工程创建以后系统会默认创建一个和工程名相同的头文件,我这里是JRDataModel.h。一般来说我们会把framework中需要提供给外部的头文件都在这个头文件中import一下,这样使用者只要包含一个头文件就可以使用所有的类了。

创建文件后导入公共头文件

这个地方需要注意到两点,一个就是导入的时候必须要使用framework的方式导入,使用<包名/头文件名.h>,因为在实际使用framework的时候是需要从包中搜索头文件的。还有一个坑就是右边的那个设置,对于总的头文件还有所有需要用到的头文件,都需要公开,选中以后把右边包的编译属性改为public,否则打出来的包在别的工程中实际上是不能引用的。

二、编译工程


接下来就是开始编译工程了(如下图),选中运行按钮右边的编译目标,选择Generic iOS Device,然后command+b编译一下,这个时候我们工程中的products文件夹下面的framework文件会由原来的红色(表示文件丢失)变成黑色(表示文件存在)。如果我们选择的是Generic iOS Device那么编译出来的framework只能在真机中使用,如果选中的是普通的模拟器,那么编译出来framewo只能在模拟器中使用。

tips:这里需要注意一下,如果一开始选择的是模拟器,那么即使build成功,framework也不会变成黑色,可能是因为这里的framework指向的是真机中对应的framework,但是在相对应的目录下的模拟器对应的framework是存在的

编译framework

右击生成好的framework,选中show in finder可以查看framework在磁盘中的位置。进入目录以后,一般来说最多有四个目录,我这里只有三个(如下图)因为对于模拟器一般不会要release版本的。也可以通过finder,快捷键control+command+g输入~/Library/Developer/Xcode/DerivedData/Build/Products默认路径进入

分别在模拟器和真机选项中编译,发现实际只产生了模拟器和真机的debug版本的framework包,而没有release版本的包。这需要我们调整一下xcode的build类型,选中运行的target在下来列表中选Edit Scheme,进入以后把run中的Build Configureation修改为Release,这时候就可以编译出release版本的包了(如下图)

三、合并framework


到此,我们已经制作出对于各种情况下使用的framework了,对于不同的环境需要使用不同种类的framework,这在很多时候显得很麻烦。能不能制作一个能在所有场景使用的包呢。

这个时候我们可以考虑合并所有版本的包,一般来说可以使用脚本进行合并,但是每次使用脚本比较麻烦,我们可以在xcode中添加一个共同体aggregate,然后添加编译脚本来实现。

在工程中点击上方工具栏File->New->Target,在选项中选择Other中的Aggregate,命名最好和工程名有关,我这里就写成JRDataModelAggregate。

新建Aggregate

新建好以后,选择targets列表下的JRDataModelAggregate,点击build phases,点击+新建一个New Run Script Phase,把下面的脚本复制到shell下的选项中(脚本来源自网络,感谢这段脚本的原作者)。有能力的可以根据自己的需要修改下面的脚本。

# Sets the target folders and the final framework product.

#如果工程名称和Framework的Target名称不一样的话,要自定义FMKNAME

#例如: FMK_NAME = "MyFramework"

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.

xcodebuild -configuration"Release"-target"${FMK_NAME}"-sdk iphoneos clean build

xcodebuild -configuration"Release"-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"${INSTALL_DIR}"

粘贴shell脚本

复制完以后,点击左上角运行旁边的target(上图左上角那个黄色的选项),在下拉的列表中选中我们刚才创建的JRDataModelAggregate,command+B编译一下,如果没什么意外,等到编译成功便会弹出我们编译好的framework了。

四、验证framework


framework其实可以看做是一个带扩展名的文件夹,所以我们可以直接进入framework的内部。通过下面的控制台指令进入到framework中(cd后面是你自己的framework路径)

cd /Users/ctzxh/Desktop/JRModel/JRDataModel/Products/JRDataModel.framework

执行下面的命令判断当前framework支持的架构

lipo -info JRDataModel

完成验证

Tips1:

对于上面的每种处理器架构对应的设备请自行百度。这里说明一下,如果让你的包可以支持armv7s的架构(这里说的支持指的是针对这种架构的优化),可以根据下图的方式添加,新版的xcode默认便没有加上armv7s的架构,由于处理器向下兼容,所以即使不添加,所使用包的工程也是可以在armv7s架构上的机器运行的。个人推荐还是不必考虑了,按照官方的来就可以了。添加完以后在验证包的时候会多显示一个armv7s。

添加armv7s架构

Tips2:

上面用Aggregate制作的库是拖入到使用的工程是直接可以使用的,但是之前分别制作的库直接拖入是不能使用的,解决的方式有两种:

第一种:制作链接库的时候,选择生成静态库

第二种:在使用动态链接库的时候嵌入二进制库,在下面的选项中添加要导入的动态库

网上有种方式是把framework的属性从required变成Optional,亲测行不通,能导入但是不能用。。。

就到这儿吧~~~

Add:如果只做的是.a的静态库可以使用下面的脚本,方法一样

if["${ACTION}"="build"]

then

#要build的target名

target_Name=${PROJECT_NAME}

echo"target_Name=${target_Name}"

#build之后的文件夹路径

build_DIR=${SRCROOT}/build

echo"build_DIR=${build_DIR}"

#真机build生成的头文件的文件夹路径

DEVICE_DIR_INCLUDE=${build_DIR}/Release-iphoneos/include/${PROJECT_NAME}

echo"DEVICE_DIR_INCLUDE=${DEVICE_DIR_INCLUDE}"

#真机build生成的.a文件路径

DEVICE_DIR_A=${build_DIR}/Release-iphoneos/lib${PROJECT_NAME}.a

echo"DEVICE_DIR_A=${DEVICE_DIR_A}"

#模拟器build生成的.a文件路径

SIMULATOR_DIR_A=${build_DIR}/Release-iphonesimulator/lib${PROJECT_NAME}.a

echo"SIMULATOR_DIR_A=${SIMULATOR_DIR_A}"

#目标文件夹路径

INSTALL_DIR=${SRCROOT}/Products/${PROJECT_NAME}

echo"INSTALL_DIR=${INSTALL_DIR}"

#目标头文件文件夹路径

INSTALL_DIR_Headers=${SRCROOT}/Products/${PROJECT_NAME}/Headers

echo"INSTALL_DIR_Headers=${INSTALL_DIR_Headers}"

#目标.a路径

INSTALL_DIR_A=${SRCROOT}/Products/${PROJECT_NAME}/lib${PROJECT_NAME}.a

echo"INSTALL_DIR_A=${INSTALL_DIR_A}"

#判断build文件夹是否存在,存在则删除

if[ -d"${build_DIR}"]

then

rm -rf"${build_DIR}"

fi

#判断目标文件夹是否存在,存在则删除该文件夹

if[ -d"${INSTALL_DIR}"]

then

rm -rf"${INSTALL_DIR}"

fi

#创建目标文件夹

mkdir -p"${INSTALL_DIR}"

#build之前clean一下

xcodebuild -target${target_Name}clean

#模拟器build

xcodebuild -target${target_Name}-configuration Release -sdk iphonesimulator

#真机build

xcodebuild -target${target_Name}-configuration Release -sdk iphoneos

#复制头文件到目标文件夹

cp -R"${DEVICE_DIR_INCLUDE}""${INSTALL_DIR_Headers}"

#合成模拟器和真机.a包

lipo -create"${DEVICE_DIR_A}""${SIMULATOR_DIR_A}"-output"${INSTALL_DIR_A}"

#打开目标文件夹

open"${INSTALL_DIR}"

fi

iOS(大牛之路)
Web note ad 1