美文网首页
创建自己的sdk(含编译脚本)

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

作者: kenewang | 来源:发表于2017-06-01 18:19 被阅读110次
    
    /*一、创建.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/图片名"];
    
    
    
    

    相关文章

      网友评论

          本文标题:创建自己的sdk(含编译脚本)

          本文链接:https://www.haomeiwen.com/subject/peiefxtx.html