iOS组件化之私有库

作者: TitanCoder | 来源:发表于2018-08-30 09:29 被阅读436次
    • 随着公司业务的不断发展,应用的代码体积将会越来越大,业务代码耦合也越来越多,代码量也是急剧增加
    • 如果仅仅完成代码拆分还不足以解决业务之间的代码耦合,而组件化是一种能够解决代码耦合、业务工程能够独立运行的技术
    • 这篇文章主要介绍远程私有库的创建和管理以及本地索引库的使用, 并且可参照发布开源框架到CocoaPods入坑指南
    • 个人原文博客地址: iOS组件化之私有库

    本地库方案

    创建本地私有库

    • 首先需要一个宿主工程MainMoudle和一个用于存放所有本地私有库的文件夹AllMoudles, 这两个文件夹在同一目录下
    • AllMoudles文件夹中创建一个私有库TitanFMBase, 在子目录创建Classes用于存放所有的文件, 目录如下: AllMoudles/TitanFMBase/Classes
    • Classes文件夹中添加文件, 并提交到本地git
    //进入TitanFMBase文件夹
    cd xxx/AllMoudles/TitanFMBase
    
    //初始化git
    git init
    
    //将本地代码提交到本地仓库
    git add .
    
    // 提交修改到本地仓库
    git commit -m '你的修改记录'
    
    //创建spec文件
    pod spec cteate TitanFMBase
    

    最后打开TitanFMBase文件夹中的TitanFMBase.podspec, 修改对应的配置信息, 可参考修改博客

    <div class="note warning"><p>注意点</p></div>

    source配置中, 本地库的git地址不需要填

    s.source = { :git => "", :tag => "#{s.version}" }
    

    使用本地私有库

    • 安装和使用本地私有库和和远程私有库步骤一样, 不同的是:
      • 远程私有库不需要指明库的地址
      • 本地私有库需要制定库地址(相对路径即可)
    • 使用path的形式添加框架依赖
    pod 'TitanFMBase', :path => '../AllMoudles/TitanFMBase'
    

    <div class="note warning"><p>注意点</p></div>

    • 入伙时本地私有库, 不需要使用pod lib lint或者pod spec lint验证spec文件的正确性
    • 因为有些字段只有远程私有库才需要设置, 只要保证本地私有库的路径正确, 并不影响使用

    远程私有库

    • 当我们在终端执行pod search命令时, 搜索的其实是本地缓存的spec文件, 当然第一次使用时需要先更新本地的spec文件
    • 可在终端执行pod repo命令查看当前本地的索引库, 或者查看目录~/.cocoapods/repos/master/Specs
    • 在组件化开发过程中, 为防止代码泄露, 我们必须要创建自己的本地索引库
    • 发布开源框架到CocoaPods入坑指南文章中提到了一种创建方式
      • 但是上述提到的创建方式, 需要手动创建podspec文件
      • 需要手动进行git管理, 不能测试, 需要手动添加测试工程
    • 执行pod repo add TitanSpec http://xxxx命令, 可创建一个新的本地索引库
    • 创建远程索引库, 码市
    • 除图中红色箭头外, 其他地方不需要填写, 新建即可
    CreateSpec

    创建远程私有库

    • pod lib create xxx
    • 规范创建私有库, 执行上述命令, 可同时创建spec文件和测试工程等
    • 根据提示创建不同的配置文件即可, 创建完成后, 将需要添加的私有库文件放到xxx/xxx/Classes文件夹下即可, 默认创建的.m文件可删除
    • 最后需要打开Example目录下的测试工程, 并执行pod install命令, 将你的私有库文件安装到测试工程
    • 最后修改xxx文件下的xxx.podspec文件中相关配置即可
    createLib

    做完上述工作即可将项目所有文件提交到远程私有库了

    // 将本地代码加入本地仓库里
    git add .
    
    // 提交修改到本地仓库
    git commit -m '你的修改记录'
    
    // 查看当前的远程连接
    git remote
    // 添加名称为origin的远程连接
    git remote add origin '你的github项目地址'
    
    // 在push之前, 查看spec是否配置有问题
    // 验证本地spec文件是否有误
    pod lib lint
    // 验证远程spec文件是否有误
    pod spec lint
    
    // 推送master分支的代码到名称为origin的远程仓库
    git push origin master
    
    • 正常情况下本地验证一般没问题, 远程验证正常情况下会有问题
    • 本地验证不会验证s.source后面的tag
    • 远程验证会验证tag, 而至此我们的tag还没有设置, 所以验证不会通过, 需要打标签
    • 设置好tag, 再次验证应该就是没问题的了
    // 查看当前的tag值
    git tag
    
    // 设置tag值
    git tag "0.0.1"  
    
    // 上传提交tag
    git push --tags
    
    
    // 删除标签相关命令
    // 先删除本地再删除远程标签, 删除后需要重新打标签
    // 删除本地标签
    git tag -d 0.0.1
    
    // 删除远程标签
    git push origin :0.0.1
    
    

    提交私有的SpecRepo

    向私有的SpecRepo中提交podspec:

    pod repo push SpecName XXX.podspec
    

    <div class="note warning"><p>注意点</p></div>

    • 提交podspec的过程中会有验证, 最好在提交之前先验证spec文件的配置是有问题pod lib lint
      • 警告可以使用--allow-warings忽略
      • 但是涉及到的错误信息一定要解决
    • 提交过程中, 会提交信息到远程私有索引库

    使用私有库

    • 检索私有库: pod search XXX
      • 如果检索不到, 可以先到私有索引库内, 看看是否存在私有库
      • 如果存在还是检索不到, 则直接删除私有库索引文件, 重新配置
    • Podfile文件中, 同事使用私有库和第三方库是需要指定对应的source
    • pod repo命令执行后的结果
    master
    - Type: git (master)
    - URL:  'https://github.com/CocoaPods/Specs.git'
    - Path: /Users/xxx/.cocoapods/repos/master
    
    TitanFMSpec
    - Type: git (master)
    - URL:  'https://git.coding.net/CoderTitan/TitanFMSpec.git'
    - Path: /Users/xxx/.cocoapods/repos/TitanFMSpec
    

    Podfile文件中配置信息

    // 远程私有库
    source 'https://git.coding.net/CoderTitan/TitanFMSpec.git'
    // 官方仓库
    source 'https://github.com/CocoaPods/Specs.git'
    
    platform :ios, '8.0'
    
    target 'TitanjunFM' do
      use_frameworks!
    
    pod 'TitanFMBase'
    pod 'MJExtension'
    
    end
    

    更新私有库

    更新远程私有库

    1. 修改xxx/xxx/Classes文件夹下对应的库文件
    2. 更新测试工程的Pod库文件: pod update --no-repo-update
    3. 更新xxx.podspec文件的配置信息, 版本号一定要改
    4. 提交代码到远程仓库: git push origin master
    5. 更新tag标签: git push --tags
    6. 更新远程和本地的私有索引库: pod repo push SpecName XXX.podspec

    私有库依赖

    初步设计方案

    • 在设计私有库的过程中难免可能会涉及到使用其他第三方库的情况, 又该如何解决这种问题
    • 添加组件依赖: 在podspec文件配置中, 添加如下依赖代码
    s.dependency 'AFNetworking'
    s.dependency 'SDWebImage'
    
    • 注意依赖, 以及框架头文件中, 不要直接导入依赖框架的头文件
    • 也就是说, 上述涉及到的所依赖的第三方库, 在项目的Podfile文件中, 不会再导入该类库

    优化方案

    上述方案存在的问题: 假如另外一个业务线, 仅仅需要依赖一些基础配置, 但是, 如果把整个库作为依赖, 便会导入一些不用的冗余代码

    • 这样, 我们现在终端执行pod search AFNetworking, 看一下AFNetworking的搜索结果
    • 会看到Subspecs中, 将AFNetworking分成了几个不同的部分, 这样我们就可以根据不同的功能需求导入不同部分的代码即可, 防止代码冗余
    -> AFNetworking (3.2.1)
       A delightful iOS and OS X networking framework.
       pod 'AFNetworking', '~> 3.2.1'
       - Homepage: https://github.com/AFNetworking/AFNetworking
       - Source:   https://github.com/AFNetworking/AFNetworking.git
       - Versions: 3.2.1, ......,0.5.1 [master repo]
       - Subspecs:
         - AFNetworking/Serialization (3.2.1)
         - AFNetworking/Security (3.2.1)
         - AFNetworking/Reachability (3.2.1)
         - AFNetworking/NSURLSession (3.2.1)
         - AFNetworking/UIKit (3.2.1)
    

    为解决将私有库中的代码分成不同的功能模块, 使用subspec语法配置podspec文件, 如下:

    //格式:
    s.subspec 'XXX' do |x|
        //需要导入的所有文件的相对路径
        x.source_files = '相对路径/**/*'
        //需要导入的.h头文件的相对路径
        x.public_header_files = '相对路径/**/*.h'
        //需要导入的资源文件的相对路径
        x.resource = "相对路径/**/*.{bundle,nib,xib}"
        //所依赖的其他的库
        x.dependency 'AFNetworking', '~> 1.0.0'
    end
    
    //示例:
    s.subspec 'Network' do |n|
        n.source_files = 'XMGFMBase/Classes/Network/**/*'
        n.dependency 'AFNetworking'
    end
    
    • 将原来的s.source_files改成上述语法即可
    • 外部使用时只需导入pod 'AFNetworking/Reachability'即可

    私有库的资源引用

    xib&storyboard

    • 所有私有库中的xib必须动态获取
    • 私有库中引用图片资源或者Xib资源时, 又该如何引用呢?
    • 都知道项目中引用Xib时, 通常方式是[[NSBundle mainBundle] load]方式, 但是这种方式在私有库中显然不适用
    • 在私有库中加载私有库中的XIb, 使用方法[NSBundle bundleForClass:self]动态获取, 具体看一下
    // MiddleView.m
        
    NSBundle *mainBundle = [NSBundle mainBundle];
    NSBundle *bundle = [NSBundle bundleForClass:self];
        
    MiddleView *middleView = [[bundle loadNibNamed:@"MiddleView" owner:nil options:nil] firstObject];
    
    // 打印一下上述两个bundle如下:
    // mainBundle:
    NSBundle </Users/xxx/Library/Developer/CoreSimulator/Devices/6B74958F-560F-4BF4-9BDF-9AD789379FC9/data/Containers/Bundle/Application/FC9747F0-8A82-4643-AC7E-BDC268190B8D/TitanFM.app>
    // bundle:
    NSBundle </Users/xxx/Library/Developer/CoreSimulator/Devices/6B74958F-560F-4BF4-9BDF-9AD789379FC9/data/Containers/Bundle/Application/FC9747F0-8A82-4643-AC7E-BDC268190B8D/TitanFM.app/Frameworks/TitanFMMain.framework>
    
    • 从上述信息中可以看到, 项目中正常的Xib等资源文件是放在TitanFM.app中的
    • 而私有库的Xib等资源文件是放在TitanFM.app/Frameworks/TitanFMMain.framework文件目录下的, 所以私有库中的资源文件加载, 要到对应的文件目录下
    • 具体也可以到TitanFM.app中查看, 找到对应的app文件, 显示包内容, 即可层级查看

    图片资源

    图片存放问题

    • 正常项目中, 我们的图片一般都会放在类似后缀.xcassets的文件中
    • 在设计私有库时, 在Classes的同级目录中会默认创建一个Assets的文件夹, 用于存放图片等资源
    • podspec文件中, 同样修改加载文件资源的配置, 如下:
    s.resource_bundles = {
       'MainMoudle' => ['MainMoudle/Assets/*']
    }
    

    修改完配置信息和图片记得执行pod install把资源文件导入到项目中

    私有库图片的使用

    xib中加载图片, 需要在图片前面加上组件的主bundle, 类似: MainMoudle.bundle/tabbat_back

    xibimage

    私有库中使用代码加载图片, 一定不能使用imageNamed方法

    //1. 获取当前的bundleName
    NSBundle *currentBundle = [NSBundle bundleForClass:[self class]];
    
    //2. 根据图片名称, 在bundle中检索图片路径
    NSString *path = [currentBundle pathForResource:@"tabbar_np_play@2x.png" ofType:nil inDirectory:@"MainMoudle.bundle"];
    
    //获取图片
    UIImage *image = [UIImage imageWithContentsOfFile:path];
    

    <div class="note warning"><p>引用图片需要注意的的是</p></div>

    • 图片引用过程中不会自动选择@2x和@3x的图片, 所以必须手动指定具体的图片名称包括图片后缀名
    • 获取路径的方法pathForResource, 也要必须指明图片所在的bundle路径, 即inDirectory参数不可为空

    <div class="note info"><p>提交本地的私有库索引</p></div>

    • 当你的私有库中引用了其他的私有库框架, 比如MainMoudle中引用了TitanFMBase/Category部分
    • 则切记不要进行本地和远程的spec验证, 否则可能回报错, 原因只是因为spec中默认的依赖库是共有的索引库, 私有库无法检索到, 错误信息如下图
    • 提交本地索引的过程中遇到类似错误则可以, 直接忽略提交即可, 但是其他的错误信息, 切记需要修改好, 警告可以忽略, 但是错误信息不能忽略(依赖私有库的问题除外)
    // 提交本地私有索引库需要忽略警告的命令
    pod repo push TitanjunSpec MainMoudle.podspec --allow-warnings
    
    podspec

    相关参考


    相关文章

      网友评论

        本文标题:iOS组件化之私有库

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