Framework详细与iOS 制作

2021-02-03 16:49:32

参考连接 iOS 制作和使用 Framework

介绍

假如你想将你开发的一些控件或者工具与别人分享,一种方法是直接提供源代码文件。然而,这种方法并不是很优雅。因为它会暴露所有的实现细节,而这些实现你可能并不想开源出来。此外,使用者也可能并不想看到你的所有代码,因为他们可能仅仅只是希望将你的这份代码的一部分植入自己的应用中去使用。

网上关于 Framework 制作的教程不说数不胜数吧,但绝对让人眼花缭乱。但很多都步骤过旧也过简单,更没有更新了,所以这里就把我前些时候总结的 制作Framework的过程记录,重新捋一下。

我用的是Xcode 9.4

正题

首先我们需要打开 Xcode,新建一个项目。 并且选择 Cocoa touch Framework。 如下图

然后随便给这个 Framework 取一个名字,比如 TestSDK

为了区分,分别建立了 PublicFile PrivateFile ProjectFile ,

如下图,并分别拖入到对应的 Header

在你弄清楚之前,这三个组的名称可能会让你迷惑,Public 是你期望的,开源出来的,Private 下的头文件依然是可以暴露出来的,因此名字可能有些误导。奇怪的是,在 Project 下的头文件对你的工程来说才是 “私有” 的,因此,你将会更多地希望你的头文件或者在 Public 下,或者在 Project 下

必须更改的两个注意点:

搜索 mach 将工程改为 静态 。

搜索 Defines Module 修改为NO

最后你还要更改 SDK最低支持 的版本,这个和项目更改 系统支持 的版本一样,不再赘述

到此基本配置基本完成,也实现了项目的闭源

打包(Bundle)资源

导入Bundle

在ImageViewer中使用Bundle

添加自动打包脚本环境,实现自动打包

总结

知识点

1. 库

库是源代码经过编译,形成的二进制代码,别人项目中使用我们的库的时候,库在参与编译的时候,直接link就OK了,按照link的方式,可以把库分为静态库和动态库

2. 静态库

静态库在编译的时候会被直接拷贝一份,复制到目标程序里,这段代码在目标程序里就不会再改变了。
一般以.a 和 .framework为文件后缀名
这种做法是牺牲应用“体量”来节省编译时间。

3. 动态库

与静态库相反,动态库在编译时并不会被拷贝到目标程序中,目标程序中只会存储指向动态库的引用。等到程序运行时,动态库才会被真正加载进来。
动态库的优点是,不需要拷贝到目标程序中,不会影响目标程序的体积,而且同一份库可以被多个程序使用(因为这个原因,动态库也被称作共享库)。
同时,编译时才载入的特性,也可以让我们随时对库进行替换,而不需要重新编译代码。动态库带来的问题主要是,动态载入会带来一部分性能损失,使用动态库也会使得程序依赖于外部环境。如果环境缺少动态库或者库的版本不正确,就会导致程序无法运行
以.tbd(之前叫.dylib) 和 .framework 为文件后缀名
苹果系统为我们提供了很多动态链接库,我们可以在我们项目工程中查看一下

4. Framework

Framework 是一种打包方式,将库的二进制文件,头文件和有关的资源文件打包到一起,方便管理和分发。
Framework只是一种打包方式,其本身和静态、动态无关!
但Cocoa Touch Framework 的实际内容为 Header + 动态链接库 + 资源文件

对Framework认识的误区

误区①:.framework是动态库,.a是静态库,前面已经讲过,不再赘述
误区②:有人说“自定义的动态库苹果审核不通过”,那我打的framework是不是通不过审核?
任何没有时间前提的结论都是耍流氓!!!
在 iOS 8 / iOS6之前,iOS 平台不支持使用动态 Framework,开发者可以使用的 Framework 只有系统的framework,这种限制可能是出于安全的考虑
换一个角度讲,因为 iOS 应用都是运行在沙盒当中,不同的程序之间不能共享代码,同时动态下载代码又是被苹果明令禁止的,没办法发挥出动态库的优势,实际上动态库也就没有存在的必要了
但是,码农总是喜欢折腾的,一方面骨子里面有一种“你不让我做我偏要做的倔强”,另一方面用framework确实比用.a加头文件的方式简单,所以这一时期的开发者用了很多“奇淫技巧”来制作framework,这就有了Fake Framework 和 Real Framework的区分
在 iOS 8 / iOS6后,iOS平台添加了动态库的支持,同时, Xcode 6 也原生自带了 Framework 支持,注意,前后两个维度的不同是两件事,不要混淆。。。

那么,为什么 iOS 8 要添加动态库的支持?
主要的理由大概就是 Extension 的出现。Extension 和 App 是两个分开的可执行文件,同时需要共享代码,这种情况下动态库的支持就是必不可少的了。但是这种动态 Framework 和系统的 UIKit.Framework 还是有很大区别;还有就是为了支持swift
虽然同样是动态框架,但是和系统 framework 不同,app 中的使用的 Cocoa Touch Framework 在打包和提交 app 时会被放到 app bundle 中(App 和 Extension 的 Bundle 是共享的),运行在沙盒里,而不是系统中。也就是说,不同的 app 就算使用了同样的 framework,但还是会有多份的框架被分别签名,打包和加载,因此苹果又把这种 Framework 称为 Embedded Framework,也正是代码签名机制,通过AppStore发布的APP是无法通过替换服务端下发framework的方式来进行热更新!

总结:

同一个静态库在不同程序中使用时,每一个程序中都得导入一次,打包时也被打包进去,形成一个程序。而动态库在不同程序中,打包时并没有被打包进去,只在程序运行使用时,才链接载入(如系统的框架如UIKit、Foundation等),所以程序体积会小很多,但是苹果不让使用自己的动态库,否则审核就无法通过。这也是为什么前文将工程选择为 静态的原因

常见的错误:

1, 没有改成静态,不支持动态

2, Defines Module 必须改成NO

3, 支持bitcode的frame操作

1
2
3
4
5
6
7
8
9
如果自己想要制作支持 Bitcode 的 Framework,
1, 工程中开启 Enable Bitcode
2, Build Setting 中 Other Linker Flags 中加入 -fembed-bitcode。
3, Build Setting 中 Other C Flags 中加入 -fembed-bitcode。

作者:山神_云网工作室
链接:https://www.jianshu.com/p/ef5a888e57f2
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

同时支持模拟器真机的配置

静态库和自己项目同时开发的方案

上文中会用到自动打包的 shell 脚本,我使用的是公司其他大神写的根据项目需求配置的脚本,这里就不开源了, 大家可以使用以下脚本,也可以实现自动打包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/bin/sh
#要build的target名
TARGET_NAME=${PROJECT_NAME}
if [[ $1 ]]
then
TARGET_NAME=$1
fi
UNIVERSAL_OUTPUT_FOLDER="${SRCROOT}/${PROJECT_NAME}/"

#创建输出目录,并删除之前的framework文件
mkdir -p "${UNIVERSAL_OUTPUT_FOLDER}"
rm -rf "${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework"

#分别编译模拟器和真机的Framework
xcodebuild -target "${TARGET_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${TARGET_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build

#拷贝framework到univer目录
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework" "${UNIVERSAL_OUTPUT_FOLDER}"

#合并framework,输出最终的framework到build目录
lipo -create -output "${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework/${TARGET_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/${TARGET_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${TARGET_NAME}.framework/${TARGET_NAME}"

#删除编译之后生成的无关的配置文件
dir_path="${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework/"
for file in ls $dir_path
do
if [[ ${file} =~ ".xcconfig" ]]
then
rm -f "${dir_path}/${file}"
fi
done
#判断build文件夹是否存在,存在则删除
if [ -d "${SRCROOT}/build" ]
then
rm -rf "${SRCROOT}/build"
fi
rm -rf "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator" "${BUILD_DIR}/${CONFIGURATION}-iphoneos"
#打开合并后的文件夹
open "${UNIVERSAL_OUTPUT_FOLDER}"


  • 2020-03-13 19:58:19

    推荐Android两种屏幕适配方案

    在Android开发中,由于Android碎片化严重,屏幕分辨率千奇百怪,而想要在各种分辨率的设备上显示基本一致的效果,适配成本越来越高。虽然Android官方提供了dp单位来适配,但其在各种奇怪分辨率下表现却不尽如人意,因此下面探索一种简单且低侵入的适配方式。本文将推荐两种屏幕适配方案,大家可以根据实际情况使用。

  • 2020-03-14 16:35:00

    nuxt.js部署全过程(ubuntu+nginx+node+pm2)

    系统的话本篇是Ubuntu 16.04.6 ,centos也行,大同小异都是Linux。不过如果你是初学者,最好和我使用一样的,因为因为发行版本不同而导致的差异可能导致运行某些东西失败,找问题要找好久。windows server不推荐了,企业用的多,小服务器跑windows server比较费劲。

  • 2020-03-14 23:15:25

    icomoon使用详细介绍

    此篇博文讲述如何利用icomoon导入图标,从而把自己想要的都通过icomoon方式进行,大家都知道,网站以及移动端,用图标还是尽量选择这种。因为直接用image有些图标会失真,从而也是前端开发之中,需求去掌握的一项,很简单的就几个步骤。

  • 2020-03-14 23:39:59

    vuetify和@nuxt/vuetify icon 之我见

    vuetify中v-icon,貌似默认支持 Material Design Icons, Material Icons, Font Awesome 4 and Font Awesome 5, 我自己单独引入了vuetify 用哪一个图标都没有问题。但是用了@nuxt/vuetify只能用mdi-home这样的。不知道因为啥。肯定是封装后,封装成一个了。 但是我修改vuetify的设置,哪一个图标也都能用。哎,不过多研究了。

  • 2020-03-16 15:57:53

    nuxtjs中单独引入Message组件的问题

    // 引入elementUIimport { Message } from 'element-ui';//由于Message组件并没有install 方法供Vue来操作的,是直接返回的,因此按照官方文档单独引入的方法是//会报错的,需要给 Message 添加 install 方法Message.install = function (Vue, options) {Vue.prototype.$message = Message}Vue.use(Message )//消息提示

  • 2020-03-16 16:03:20

    css的var()函数

     随着sass,less预编译的流行,css也随即推出了变量定义var函数。var()函数,就如同sass和less等预编译软件一样,可以定义变量并且进行对应的使用。

  • 2020-03-16 16:52:05

    对icomoon的误解,以及最快速的使用

    此时需要注意顶部第一个选项,Quick Usage,一定要打开,Enable Quick Usage,谁让咱英语不好呢,这个时候会出现一个css连接,直接引用就好了,就可以随意使用图标了,引入这一个css就能实现我们的功能,省区引入太多文件的烦恼,你可以在浏览器打开这个css,可以看到里面把我们所用的文件整成base64了。所以挺好用的。