美文网首页大前端开发
iOS静态库开发基础

iOS静态库开发基础

作者: shaosolas | 来源:发表于2019-08-15 09:24 被阅读12次

    一、为什么用库

    1、为了方便共享源代码,在分享的同时又不愿意暴露源代码及具体实现

    2、实现iOS程序组件化,可以把固定的业务模块化成库文件,方便多个工程使用,节省编译时间

    3、开发第三方SDK的需要(企业级业务)

    二、库的简介

    2.1、什么是库?

    库是一段编译好的二进制代码,附加上公开的头文件,代码就可以供其他开发者使用。在使用库的时候,编译时只需要链接就好。根据库的链接方式,分为静态库和动态库两类。

    2.2、静态库与动态库的区别?

    静态库:链接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝。

    动态库:链接时不复制到可执行文件中,程序运行时由系统动态加载到内存,程序中只存储指向动态库的引用。系统只加载一次,多个程序共用,节约了内存。

    针对iOS项目,可以以下面的方式来简单区分:

    以==Embedded Binaries==方式导入为动态库;

    以==Link Binary With Libraries== 方式导入为静态库。

    2.3、iOS中静态库

    .a和.framework。

    主流的SDK开发方式,腾讯、百度等大厂的SDK主要采用静态开发方式。

    静态库不能嵌套(见iOS中Framework Library嵌套使用),这样可以减少库与其他库之间的耦合。

    但是在使用静态库的时候,需要导入所依赖的其他库文件,这样会比较麻烦。因此,当SDK需要引用其他SDK,且不希望将内部实现暴露给用户时,那么就会采用动态库形式,这种一般是系统级的库文件。

    2.4、iOS中动态库

    .dylib,.tbd和.framework,主要是系统组件。

    若SDK和项目中用到相同的三方库(如:AFNetworking),在使用动态库时,工程和项目中可以存在2份AFNetworking,因此开发相对方便一些。而静态库只会存在一份,因此开发相对复杂,但是可以减少代码的冗余。

    注意:

    在导入自定制的动态库时,要在Embedded Binaries中导入,不然会报错:image not found。

    2.5、framework为什么既是静态库又是动态库?

    .framework本质上并不是一个库,它是苹果为了方便开发者提供了一种库的打包方式,Framework会将Mach-O文件、头文件和资源包全都包含进来,不需要你再手动整理,我们也可以通过Xcode来制作framework动态库使用。

    系统的.framework是动态库形式。

    开发者所创建的.framework大部分是静态库,因此需要拷贝到目标程序中。

    所以说.framework既可以是静态库也可以是动态库,这取决于编译成的Mach-O(就是那个二进制文件)是以动态库还是静态库形式编译。

    综上: .framework是iOS开发中库的一种打包形式,既可以是动态库也是静态库。

    2.6、a与.framework有什么区别?

    .a是一个纯二进制文件,.framework中除了有二进制文件外还有资源文件,一个比较简单的描述即.a + .h + sourceFile = .framework。

    所以.a文件不能直接使用,需要添加对应的.h文件,而.framework文件可以直接供开发者使用。

    2.7、静态库开发的注意事项:

    1、无论是.a静态库还.framework静态库,需要的都是二进制文件+.h+其它资源文件的形式。不同的是,.a本身就是二进制文件,需要我们手动加上.h和其它资源文件,而.framework本身已经包含了.h和其它文件。

    2、图片资源的处理:在.a和.framewok两种静态库文件,一般都是把图片资源拿出,相应放在一个.bundle、.bundle的名字可以和.a或.framework的名字相同。一种方式是:可直接创建一个文件夹,后缀名为.bundle,在显示包内容时,添加图片资源文件。另一种方式是:在Xcode的工程中添加bundle target,添加图片资源文件。

    3、Category在实际开发项目中会经常用到的。将Category打包成静态库,不会有什么问题的。但是在应用该静态库的工程中,会遇到调用Category的方法,找不到该方法的运行时错误(Selector not recognized)。这是因为链接标志所造成的,需要在应用静态库的工程配置,在==Other linker flags==处,添加『-ObjC』。

    4、如果一个静态库较为复杂,必须暴露的.h文件过多,可在静态库的内部创建一个专门的.h文件(一般这个.h文件的名字和静态库名相同),然后把所有需要暴露的.h文件集中到此.h文件,再把这个.h文件暴露即可。

    三、静态SDK开发流程

    3.1、静态SDK的创建和配置

    1、创建空白Xcode Workspace

    2、创建SDK工程

    (1)创建SDK

    在当前workspace中创建SDK工程,如图1所示,并将SDK工程与workspace关联,如图2所示。

    图1.png
    图2.png

    配置SDK为静态库。

    配置==Deployment Target==iOS 9.0

    Mach-O Type ==Static Library==

    Enable Bitcode ==No==

    Edit Scheme - Run - Info - Build Configuration ==Release==

    (2)创建Bundle

    因为在静态库中,SDK中的图片资源及xib等,需要添加到对应的Bundle中。所以在步骤(1)中的工程添加『target』,如图3所示,并配置如下:

    图3.png

    Build Settings - Base SDK - ==iOS==

    Deployment Target -9.0

    Enable Bitcode ==NO==

    清除Build settings - Installation Directory路径信息

    COMBINE_HIDPI_IMAGES设置为==NO==

    Edit Scheme - Run - Info - Build Configuration ==Release==

    (3)配置生成脚本

    在iOS开发中,模拟器运行平台为PC,架构为i386和x86_64等,而真机的架构为arm7和arm64等。所以,为了使SDK在模拟器及真机上都可运行,则需编译生成两个在不同平台的SDK,然后再用工具合二为一。

    在SDK工程中,添加对应的Aggregate工程。

    图4.png

    在设置Build Phrase中设置Target Dependices关联SDK工程,另外为Run Script添加下列代码,如图5所示。

    #  This is a modified script and it will ask the target to build separate libraries for simulator and device etc   
    # On project folder it will be found under Generated-Frameworks folder  
    # As per the documentations for XCode 10 Apple does not allow building FAT librares  
    # Go ahead and check https://forums.developer.apple.com/thread/66978 and https://forums.developer.apple.com/thread/109583  
    # Enjoy NicoX :)  
    
    set -e  
    # If we're already inside this script then die  
    if [ -n "$MULTIPLATFORM_BUILD_IN_PROGRESS" ]; then  
    exit 0  
    fi  
    export MULTIPLATFORM_BUILD_IN_PROGRESS=1  
    
    ############################################  
    # Options  
    ############################################  
    REVEAL_ARCHIVE_IN_FINDER=true  
    OUTPUT_DIR_NAME="Generated-Frameworks" 
    
    FRAMEWORK_NAME="${PROJECT_NAME}"  
    
    OUTPUT_DIR="${PROJECT_DIR}/${OUTPUT_DIR_NAME}/${FRAMEWORK_NAME}-${CONFIGURATION}-framework"  
    SIMULATOR_LIBRARY_OUT_DIR="${OUTPUT_DIR}/Simulator/"  
    GENERATED_LIBRARY_DIR="${BUILD_DIR}/${CONFIGURATION}-iphoneuniversal"  
    SIMULATOR_FRAMEWORK_OUT_DIR="${GENERATED_LIBRARY_DIR}/Simulator"  
    FRAMEWORK="${SIMULATOR_FRAMEWORK_OUT_DIR}/${FRAMEWORK_NAME}.framework"  
    
    ########################################################################  
    # Build Frameworks  
    ########################################################################  
    xcodebuild -scheme ${PROJECT_NAME} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphonesimulator OBJROOT="${OBJROOT}/DependantBuilds"   
    
    ########################################################################  
    # Create directory for general  
    ########################################################################  
    rm -rf "${GENERATED_LIBRARY_DIR}"  
    mkdir "${GENERATED_LIBRARY_DIR}"  
    mkdir "${SIMULATOR_FRAMEWORK_OUT_DIR}"  
    mkdir "${FRAMEWORK}"  
    
    ########################################################################  
    # Copy files Framework  
    ########################################################################  
    SIMULATOR_LIBRARY_PATH="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${FRAMEWORK_NAME}.framework"  
    
    ########################################################################  
    # Make a binary for simulaotr ie. x86_64 ot i386 file system  
    ########################################################################  
    # For Swift framework, Swiftmodule needs to be copied in the universal framework   
    if [ -d "${SIMULATOR_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/" ]; then  
    cp -f "${SIMULATOR_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/"* "${FRAMEWORK}/Modules/${FRAMEWORK_NAME}.swiftmodule/" | echo  
    fi  
    cp -r "${SIMULATOR_LIBRARY_PATH}/." "${FRAMEWORK}"  
    
    ########################################################################  
    # Copy simulator build library in output folder  
    ########################################################################  
    rm -rf "$OUTPUT_DIR"  
    mkdir -p "$OUTPUT_DIR"  
    mkdir -p ${SIMULATOR_LIBRARY_OUT_DIR}  
    
    cp -r "${FRAMEWORK}" "$SIMULATOR_LIBRARY_OUT_DIR"  
    #########################################################################  
    
    echo "Simulator Lib Path ---->" "${SIMULATOR_LIBRARY_PATH}" "<----"  
    
    ##########################################################################  
    # Now lets build for device; shall we?  
    ##########################################################################  
    DEVICE_LIBRARY_OUT_DIR="${OUTPUT_DIR}/Device/"  
    DEVICE_FRAMEWORK_OUT_DIR="${GENERATED_LIBRARY_DIR}/Device"  
    FRAMEWORK="${DEVICE_FRAMEWORK_OUT_DIR}/${FRAMEWORK_NAME}.framework"  
    
    ########################################################################  
    # Build Device Frameworks  
    ########################################################################  
    xcodebuild -scheme ${PROJECT_NAME} -sdk iphoneos ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphoneos OBJROOT="${OBJROOT}/DependantBuilds"   
    
    ########################################################################  
    # Create directory for general  
    ########################################################################  
    rm -rf "${GENERATED_LIBRARY_DIR}"  
    mkdir "${GENERATED_LIBRARY_DIR}"  
    mkdir "${DEVICE_FRAMEWORK_OUT_DIR}"  
    mkdir "${FRAMEWORK}"  
    
    ########################################################################  
    # Copy files Framework  
    ########################################################################  
    DEVICE_LIBRARY_PATH="${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FRAMEWORK_NAME}.framework"  
    
    ########################################################################  
    # Make a binary for device ie. arm7, arm7v, arm8 file system  
    ########################################################################  
    # For Swift framework, Swiftmodule needs to be copied in the universal framework   
    if [ -d "${DEVICE_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/" ]; then  
    cp -f "${DEVICE_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/"* "${FRAMEWORK}/Modules/${FRAMEWORK_NAME}.swiftmodule/" | echo  
    fi  
    cp -r "${DEVICE_LIBRARY_PATH}/." "${FRAMEWORK}"  
    ########################################################################  
    # Copy device build library in output folder  
    ########################################################################  
    mkdir -p ${DEVICE_LIBRARY_OUT_DIR}  
    cp -r "${FRAMEWORK}" "$DEVICE_LIBRARY_OUT_DIR" 
    
    echo "Device Lib Path ---->" "${DEVICE_LIBRARY_PATH}" "<----"  
    
    # Copy device build library in output folder  
    # Create Cross Platform Output
    ########################################################################  
    cp -r  "${DEVICE_LIBRARY_OUT_DIR}/" "${OUTPUT_DIR}/"
    lipo -create "${DEVICE_LIBRARY_OUT_DIR}${PROJECT_NAME}.framework/${PROJECT_NAME}" "${SIMULATOR_LIBRARY_OUT_DIR}${PROJECT_NAME}.framework/${PROJECT_NAME}" -output "${OUTPUT_DIR}/${PROJECT_NAME}.framework/${PROJECT_NAME}"
    
    if [ ${REVEAL_ARCHIVE_IN_FINDER} = true ]; then  
        open "${OUTPUT_DIR}//"  
    fi  
    
    
    
    图5.png

    同上面的步骤,修改工程中的Target配置

    Enable Bitcode 设置为==NO==

    Edit Scheme - Run - Info - Build Configuration ==Release==

    3.2、Demo工程的创建与配置

    1、创建Demo工程

    创建一个空白iOS工程,关联到当前workspace。

    2、关联SDK工程

    在Demo工程设置==Link Binary With Libraries==,加入SDK工程编译生成的framework,如图6所示。

    图6.png

    3.3、SDK开发

    1、SDK功能开发

    在DemoSDK中添加源码文件,开发对应的功能。本例中添加一个简单的VC作为示例,

    图7.png

    添加测试用的图片资源,

    图8.png

    将新添加的代码头文件添加到SDK的Public Header中,

    图9.png

    在SDK头文件中,引用新建的源码头文件

    图10.png

    将SDK中Building Phases中的Copy Bundle Resources中的图片资源或者xib等移除掉,后续会加入到SDK专属的Bundle文件中。

    图11.png

    在修改SDK工程的源码之后,清理并重新编译工程。

    2、SDK Bundle生成

    在SDK中的Bundle Target中,Copy Bundle Resources处添加对应的资源,

    图12.png

    编译Bundle Target,在SDK工程目录中的Products目录下找到相应的.bundle文件,将其复制到SDK Demo工程所对应的文件中。然后在SDK Demo中的Copy Bundle Resouces里面添加刚才的.bundle文件。

    图13.png

    3.3、SDK调试

    此时在SDK Demo工程当中,引用SDK 头文件,测试SDK提供的功能和视图。

    图14.png

    在模拟器中Run工程,在SDK源码中添加断点,然后在模拟器中查看实际效果。

    图15.gif

    四、手动应用SDK

    4.1 生成Framework

    选择SDK工程的Cross Target,编译运行Target,执行配置好的生成脚本,就打包好可以在模拟器与真机上都可成功运行的.framework文件。

    4.2 使用SDK

    类似于步骤3.2,将SDK的文件添加到目标工程中。

    4.3 开发工程

    参考

    一、包含 Bundle 资源的 framework 的正确打包方式

    二、iOS SDK开发(静态SDK)

    三、iOS静态库SDK制作(包含第三方静态库)

    四、Xcode中的 workspace, project, target, scheme

    五、Fat Framework Script for Xcode 10?

    六、iOS 静态库,动态库与 Framework

    七、iOS中Framework Library嵌套使用

    八、jverkoey/iOS-Framework

    相关文章

      网友评论

        本文标题:iOS静态库开发基础

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