创建自己的sdk(含编译脚本)


/*一、创建.a库*/
1.创建静态库工程 > 删除自动创建的.m实现文件及头文件里的信息 > 导入可能用到的系统库
2.目标工程 > Build Phases > Editor > add build Phases(是否公开头文件选项) > 设置公开访问的头文件(或在Target Membership中直接设置)
或
  目标工程 > Build Phases > 点击左侧加号 > add build Phases(是否公开头文件选项) > 设置公开访问的头文件(或在Target Membership中直接设置)

3.将公开头文件导入到总的公用头文件中
4.选择sdk支持的系统版本
5.参数配置
  Build Settings > Dead Code Stripping设置为NO
  Build Settings > Strip Debug Symbol During Copy 全部设置为NO
  Build Settings > Strip Style设置为Non-Global Symbols
  Build Settings > Base SDK > Latest iOS(iOS 选择最新的)
6.设备 和 模拟器 下分别按下command + B进行编译, 编译成功后 > 在Product目录下 Show in Finder 查看
7.debug模式下运行生成  Debug-iphoneos Debug-iphonesimulator两个文件夹
  release模式下运行生成 Release-iphoneos Release-iphonesimulator文件夹
  区别
  Debug和Release,在我看来主要是针对其面向的目标不同的而进行区分的。
  Debug通常称为调试版本,通过一系列编译选项的配合,编译的结果通常包含调试信息,而且不做任何优化,以为开发人员提供强大的应用程序调试能力。
  Release通常称为发布版本,是为用户使用的,一般客户不允许在发布版本上进行调试。所以不保存调试信息,同时,它往往进行了各种优化,以期达到代码最小和速度最优。为用户的使用提供便利
8.为了能在真机和模拟器上都能运行需要使用终端合并
  cd到你想要保存合并后文件的目录下
  合并 lipo -create 模拟器.a(路径) 真机.a(路径) -output 重命名.a
9.使用时,直接导入usr下的头文件和合并的.a文件
10.查看架构模式 lipo -info XXX.a  i386 armv7 x86_64 arm64(下面有介绍)

arm7: 在最老的支持iOS7的设备上使用
arm7s: 在iPhone5和5C上使用
arm64: 运行于iPhone5S的64位 ARM 处理器 上
i386: 32位模拟器上使用
x86_64: 64为模拟器上使用
注意:向下兼容,arm7版本可以做arm7s上运行
需要在对应架构设备上运行,才能生成对应架构的包

11.建立工程验证
12.如果架构报错  Build Settings > BuildActiveArchitecture Only Debug改为NO

/*二、创建.framework库*/

 Framework是资源的集合,将静态库和其头文件包含到一个结构中,让Xcode可以方便地把它纳入到你的项目中。本质也是一个bundle文件

//(1)使用bundle文件创建framework框架

    1.创建一个Bundle工程

    2.目标工程 > Build Phases > Editor > add build Phases(是否公开头文件选项) > 设置公开访问的头文件(或在Target Membership中直接设置)
    或
      目标工程 > Build Phases > 点击左侧加号 > add build Phases(是否公开头文件选项) > 设置公开访问的头文件(或在Target Membership中直接设置)
    3.创建一个总的公共头文件 > 导入需要编译成库的文件 > 设置公开头文件 > 将公开头文件导入总的头文件中

    4.选择framework支持的系统版本

    5.配置参数更改
      Build Settings > public header >  /usr/$(PROJECT_NAME) (公共头文件在工程目录下)
      Build Settings > Dead Code Stripping设置为NO
      Build Settings > Strip Debug Symbol During Copy 全部设置为NO
      Build Settings > Strip Style设置为Non-Global Symbols
      Build Settings > Base SDK > Latest iOS(iOS 选择最新的)
      Build Settings >  Link With Standard Libraries = NO
      Build Settings > Packaging > Wrapper Extension = framework.
      Build Settings >  Mach-O Type(frame 分静态库和动态库) = Static Library
      对于Mach-O Type可能有两种情况:(1)选择 Static Library 打出来的是静态库;(2)选择 Relocatable Object File 打出来是动态库。
      点击plist文件 > Bundle OS Type code改为FMWK

    6.为了方便找到运行后生成的framework,我们提前在项目目录下创建一个目录 build,用来存放运行后生成的文件;
      Build Settings > Per-configuration Build Products Path = $(SRCROOT)/build/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

    7、模拟器和真机分别编译 > 合并

    8.合并的是framework下的二进制文件
      cd到你想要保存合并后文件的目录下
      合并命令 lipo -create xxx.framework/xxx ooo.framework/ooo -output ooo。

    9.将合并成功的二进制文件替换为framework中的二进制文件,如果没有用到info.plist文件,可以删除,避免在工程中发生冲突

    10.验证 查看架构模式 lipo -info XXX.a

//(2)直接创建framework库

    1、使用xcode直接创建frame工程

    2、把需要编译的库导入到工程中

    3、设置需要公开的头文件
       Build Phases > Headers > 把文件拖动到指定位置(或在Target Membership选择)公开还是私有(Project为真正私有)

    4.选择framework支持的系统版本

    5、配置参数
      Build Settings > public header >  /usr/$(PROJECT_NAME) (公共头文件在工程目录下)
      Build Settings > Dead Code Stripping设置为NO
      Build Settings > Strip Debug Symbol During Copy 全部设置为NO
      Build Settings > Strip Style设置为Non-Global Symbols
      Build Settings > Base SDK > Latest iOS(iOS 选择最新的)
      Build Settings >  Link With Standard Libraries = NO
      Build Settings >  Mach-O Type(frame 分静态库和动态库) = Static Library
      对于Mach-O Type可能有两种情况:(1)选择 Static Library 打出来的是静态库;(2)选择 Relocatable Object File 打出来是动态库。

    6.为了方便找到运行后生成的framework,我们提前在项目目录下创建一个目录 build,用来存放运行后生成的文件
      Build Settings > Per-configuration Build Products Path = $(SRCROOT)/build/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

    7、模拟器和真机分别编译 > 合并

    8.合并的是framework下的二进制文件
      cd到你想要保存合并后文件的目录下
      合并命令 lipo -create xxx.framework/xxx ooo.framework/ooo -output ooo。

    9.将合并成功的二进制文件替换为framework中的二进制文件,如果没有用到info.plist文件,可以删除,避免在工程中发生冲突

    10.验证

//(3)直接在工程中创建framework库

    1.点击目标工程 > 点击下面左下角加号 > 创建framework

    2.参数配置和合并流程同上(直接创建framework)

    区别
    为避免原工程编译错误
    点击工程的目标文件 General > Embedded Binaries > 删除你创建的framework

/*注意事项*/
category的处理
category是项目开发中经常用到的,把category打包成静态库是没有问题的,但是在使用这个静态库时,
调用category中的方法时会发生找不到该方法的运行时错误(selector not recognized),
解决的办法是在使用静态库的工程中配置other linker flags的值为 -ObjC  -all_load

对图片资源和UI界面xib或nib文件的处理
.a和.framework两种静态库,通常都是把需要用的到图片或者xib文件存放在一个bundle文件中,而该bundle文件的名字和.a或.framework的名字相同。
.a文件中无法存放图片或xib文件,很容易理解,但是.framework从本质上说也是一个bundle文件,为什么不把图片或者xib文件直接放在.framework中而单独再创建个bundle文件呢?
那是因为iOS系统不会去扫描.framework下的图片等资源文件,也不会在项目中显示,也就是说即使放在 .framework目录下,系统根本就不会去扫描,因此也无法发现使用。

/*开发UI控件库*/
在无法看到真实效果的情况下为iOS开发一个UI控件库是极其困难的
1.创建库工程,流程同上(第一节创建.a工程)也可创建framework (存在图片放入bundel中)
2.创建依赖库工程
3.关闭库工程
4.添加依赖库,将你的库工程xxxx.xcodeproj从Finder中拖到Xcode中依赖工程组下。
/*注意*/
你无法将同一工程在两个Xcode窗口中同时打开,如果你发现你无法在你的工程中导航到库工程的话,检查一下是否库工程在其他Xcode窗口中打开了。
5.连接到静态库
  Build Phases > Link Binary With Libraries > 点击 “+” > Workspace组中选你的.a > 点击add
  Build Phases > Target Dependencies > 选择你的库
6.导入库的头文件(头文件路径)编译库,编译依赖工程
7.报错问题解决
  ①删除添加的库,重新编译后导入
  ②确保编译路径相同
    Build Settings > Per-configuration Build Products Path >
    $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

像这样使用嵌套工程的好处是你可以对库本身做出修改,而不用离开示例工程,即使你同时改变两个地方的代码也一样。每次你编译工程,你都要检查是否将头文件的public/project关系设置正确。如果实例工程中缺失了任何需要的头文件,它都不能被编译。

/*在xcode中直接使用脚本生成framework*/
静态库构建过程中添加脚本来创建文件结构
1.打开静态库工程 > Build Phases > 左侧 “+” 按钮 > New Run Script Phases
  这一步在build phases部分添加了一个新的面板,这允许你在构建时运行一个Bash脚本。你希望让脚本在build的过程中何时执行,就把这个面板拖动到列表中相对应的那一位置。对于该framework工程来说,脚本最后执行,因此你可以让它保留在默认的位置即可。
2.双击面板标题栏Run Script,重命名为Build Framework。

根据frame文件结构构件Framework,此时不包含二进制文件
#set –e确保脚本的任何地方执行失败,则整个脚本都执行失败。
set -e

#导出的文件路径
export FRAMEWORK_LOCN="${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework"

# 创建真是文件路径
mkdir -p "${FRAMEWORK_LOCN}/Headers"

# 拷贝公共头文件到framework中
/bin/cp -a "${TARGET_BUILD_DIR}/${PUBLIC_HEADERS_FOLDER_PATH}/" \
"${FRAMEWORK_LOCN}/Headers"

3.多架构(Multi-Architecture)编译

  ①点击目标工程 > 添加新目标 > Cross-Platform > Aggregate > next > 命名为Framework

  为什么使用集合(Aggregate)目标来创建一个framework呢?为什么这么不直接?因为OS X对库的支持更好一些,事实上,Xcode直接为每一个OS X工程提供一个Cocoa Framework编译目标。基于此,你将使用集合编译目标,作为Bash脚本的连接串来创建神奇的framework目录结构。
  你是不是开始觉得这里的方法有些愚蠢了?

  为了确保每当这个新的framework目标被创建时,静态链接库都会被编译,你需要往静态库目标中添加依赖
  ②选择Framework目标 > Build Phases > Target Dependencies > 点击 + > 加入你的库
  在库工程中选择Framework目标,在Build Phases中添加一个依赖。展开Target Dependencies面板,点击 + 按钮选择RWUIControls静态库。

  ③选择Framework目标 > Build Phases > 左侧 “+” 按钮 > New Run Script Phases > 命名MultiPlatform Build

  ④写入编译文件
    #set –e确保脚本的任何地方执行失败,则整个脚本都执行失败。
    set -e

    #标示 如果已经插入脚本 退出
    if [ -n "$IYQ_MULTIPLATFORM_BUILD_IN_PROGRESS" ]; then
    exit 0
    fi
    export IYQ_MULTIPLATFORM_BUILD_IN_PROGRESS=1

    # 自定义变量
    IYQ_FRAMEWORK_NAME=${PROJECT_NAME}
    IYQ_INPUT_STATIC_LIB="lib${PROJECT_NAME}.a"
    IYQ_FRAMEWORK_LOCATION="${BUILT_PRODUCTS_DIR}/${IYQ_FRAMEWORK_NAME}.framework"

    #构建静态库 传参 "${1}"
    function build_static_library {
    # 重新构建库
        xcrun xcodebuild -project "${PROJECT_FILE_PATH}" \
        -target "${TARGET_NAME}" \
        -configuration "${CONFIGURATION}" \
        -sdk "${1}" \
        ONLY_ACTIVE_ARCH=NO \
        BUILD_DIR="${BUILD_DIR}" \
        OBJROOT="${OBJROOT}" \
        BUILD_ROOT="${BUILD_ROOT}" \
        SYMROOT="${SYMROOT}" $ACTION
    }

    #合并
    function make_fat_library {

        xcrun lipo -create "${1}" "${2}" -output "${3}"
    }

    # 1 正则判断 真机还是模拟器 (iphoneos/iphonesimulator)
    if [[ "$SDK_NAME" =~ ([A-Za-z]+) ]]; then
    IYQ_SDK_PLATFORM=${BASH_REMATCH[1]}
    else
    echo "Could not find platform name from SDK_NAME: $SDK_NAME"
    exit 1
    fi

    # 2 SDK版本
    if [[ "$SDK_NAME" =~ ([0-9]+.*$) ]]; then
    IYQ_SDK_VERSION=${BASH_REMATCH[1]}
    else
    echo "Could not find sdk version from SDK_NAME: $SDK_NAME"
    exit 1
    fi

    # 3 其他平台判断 如果 则 否则
    if [ "$IYQ_SDK_PLATFORM" == "iphoneos" ]; then
    IYQ_OTHER_PLATFORM=iphonesimulator
    else
    IYQ_OTHER_PLATFORM=iphoneos
    fi

    # 4 其他平台路径
    if [[ "$BUILT_PRODUCTS_DIR" =~ (.*)$IYQ_SDK_PLATFORM$ ]]; then
    IYQ_OTHER_BUILT_PRODUCTS_DIR="${BASH_REMATCH[1]}${IYQ_OTHER_PLATFORM}"
    else
    echo "Could not find other platform build directory."
    exit 1
    fi

    #调用上面构建函数 如果当前运行的是真机则构建模拟器
    build_static_library "${IYQ_OTHER_PLATFORM}${IYQ_SDK_VERSION}"

    # 如果你现在正在为模拟器编译,那么Xcode会默认只在该系统对应的结构下编译,例如i386 或 x86_64。为了在这两个结构下都进行编译,这里调用了build_static_library,基于iphonesimulator SDK重新编译,确保这两个结构都进行了编译。
    if [ "$RW_SDK_PLATFORM" == "iphonesimulator" ]; then
    build_static_library "${SDK_NAME}"
    fi

    # 合并库
    make_fat_library "${BUILT_PRODUCTS_DIR}/${IYQ_INPUT_STATIC_LIB}" \
    "${IYQ_OTHER_BUILT_PRODUCTS_DIR}/${IYQ_INPUT_STATIC_LIB}" \
    "${IYQ_FRAMEWORK_LOCATION}/${IYQ_FRAMEWORK_NAME}"

    # 确保文件存在 相当于-dpR,保持文件的连接(d),保持原文件的属性(p)并作递归处理(R)
    cp -a "${IYQ_FRAMEWORK_LOCATION}/${IYQ_FRAMEWORK_NAME}" \
    "${IYQ_OTHER_BUILT_PRODUCTS_DIR}/${IYQ_FRAMEWORK_NAME}.framework/${IYQ_FRAMEWORK_NAME}"

    # 拷贝到指定目录下
    ditto "${IYQ_FRAMEWORK_LOCATION}" "${SRCROOT}/BuildFramework/${IYQ_FRAMEWORK_NAME}.framework"

  ⑤show in Finder 查看编译的库 > 打开终端验证 > 创建工程验证
    $ cd XXXX.framework
    $ XXX.framework  xcrun lipo -info XXXX

    iOS app需要在许多不同的CPU架构下运行:
    arm7: 在最老的支持iOS7的设备上使用
    arm7s: 在iPhone5和5C上使用
    arm64: 运行于iPhone5S的64位 ARM 处理器 上
    i386: 32位模拟器上使用
    x86_64: 64为模拟器上使用
    每个CPU架构都需要不同的二进制数据,当你编译一个应用时,无论你目前正在使用那种架构,Xcode都会正确地依照对应的架构编译。例如,如果你想跑在虚拟机上,Xcode只会编译i386版本(或者是64位机的x86_64版本)。

/*sdk存在图片等资源文件的情况*/
使用bundle文件封装图片、xib等资源,以下流程是使用多目标编译,单独创建bundle文件类似
1.选择库工程目标文件 > 左下角 + > maxOS > Bundle > 自定义命名IYQResources

2.配置几个编译设置,因为你正在创建一个在iOS上使用的bundle,这与默认的OS X不同。
  选择Bundle目标文件 > Build Settings > Base SDK > Latest iOS (iOS 10.2选择最新)
  Build Settings > Product Name > ${TARGET_NAME}替换为你的工程名XXXX(直接写工程名就好)

3.选择Framework目标 > Build Phases > Target Dependencies > 点击 + > 加入你的Bundle

4.默认情况下,有两种resolutions(分辨率)的图片可以产生一些有趣的现象。
  例如,当你导入一个retina@2x版本的图片时,普通版的和Retina版的将会合并成一个多resolution的TIFF(标签图像文件格式,Tagged Image File Format)。
  Build Settings > COMBINE_HIDPI_IMAGES设置为NO

5.如何添加资源文件
  ①直接拖入
  ②选择图片或其他资源文件 > Target Membership > 选择bundle目标

6.如果想把你的编译包copy到指定位置,在脚本后面加入如下代码
  # 拷贝bundle到指定目录下
  ditto "${BUILT_PRODUCTS_DIR}/${IYQ_FRAMEWORK_NAME}.bundle" \
  "${SRCROOT}/BuildFramework/${IYQ_FRAMEWORK_NAME}.bundle"

7.如何引用:UIImage *image = [UIImage imageNamed:@"XXXX.bundle/图片名"];



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

推荐阅读更多精彩内容

  • 总览 一、创建自己的SDK - .a静态库 这篇教程将只使用一小部分Objective-C代码,本文主要讲解从开始...
    leonardni阅读 11,758评论 6 61
  • ——日记星球小牛妈妈访谈录 395号星宝宝衣袂飞扬,三月里款款走来的女子,安静、祥和,是我们...
    程程百合阅读 473评论 2 0
  • //距离// 你 溜溜地走着 有没有想过 活生生的人 和黑白遗照的距离 水壶 咕咕地响着 如何测量 生水 与翻滚沸...
    单想阅读 143评论 0 1
  • 最近大半年,我的注意力主要放在三个领域:短视频,陌生人社交,KOL的知识变现。 “短视频”是主赛道。 “陌生人社交...
    纯银V阅读 12,318评论 0 192
  • 惊蛰以来,已经连续下了两天大雨了。 邕城的春天总是湿漉漉的,让我的心情明朗不起来。但街道两旁的榕树换了新绿,偶尔还...
    楚南之获阅读 459评论 0 4