解决环信EaseUI的pod依赖库冲突问题

作者: naiyi | 来源:发表于2017-05-17 11:27 被阅读690次

    问题描述

    环信的EaseUI的pod文件依赖于MWPhotoBrowser,而MWPhotoBrowser又依赖于MBProgressHUD ,'~>0.9',问题就出在这个0.9上面了,根据CocoaPods官方文档对于Podspec Syntax的语法描述。

    Podspec Syntax的dependency命令描述

    其版本号规则为匹配指定的最后一位数字以上,但不能超过前一位,而实际上MBProgressHUD的版本号已经更新到1.0.0了,也就是说MWPhotoBrowser指定的版本号规则无法使用1.0.0版本。

    而项目里之前已经通过pod依赖了MWPhotoBrowser的1.0.0版本,并且1.0.0的api又较大改动,当降级到0.9.2时,编译错误多达上百处。

    而且MWPhotoBrowser的项目已经一年多不再维护,其依赖的MBProgressHUD、SDWebImage都存在版本过低的现象,github的issue里也是怨声载道。

    MWPhotoBrowser的最新issue列表

    如此看来等作者解决这个问题是不可能了,只能靠自己work round了。

    解决办法

    1、在MWPhotoBrowser的issue里找到一个家伙的留言,说他fork并更新了MWPhotoBrowser依赖库版本问题,就用它吧。https://github.com/EvoIos/MWPhotoBrowser

    更新过的MWPhotoBrowser

    2、由于EaseUI里依赖的spec.dependency MWPhotoBrowser 没法直接修改,并且也不支持通过:git =>指定下载来源的语法。这里有两个解决方案:一是先fork该项目,然后修改fork后的podspec里的spec.dependency,去掉MWPhotoBrowser,然后在自己的项目的Podfile里通过pod 'MWPhotoBrowser', git => 的方式引入上一步修改过的类库。但这里存在的问题是,EaseUI更新比较频繁,fork以后为了与官方库同步要经常主动去pull request才可以,比较麻烦。

    3、第二个解决方案就是,不fork EaseUI,也不去掉MWPhotoBrowser,继续使用环信官方的EaseUI pod。然后直接像上一步一样在自己的项目的Podfile里通过pod 'MWPhotoBrowser', git => ,本来我以为podspec中指定的spec.dependency一定会去官方库或者source命令指定的私有库里去查询,但实际上通过pod update --verbose命令的执行情况来看,pod的执行逻辑是预先通过Pre-downloading操作加载所有用户指定的来自私有库的类库(先查缓存目录,没有的话则从私有库指定的网络地址下载到缓存中),然后再检查每个库的依赖情况,如果依赖的库已经在私有库中指定并且预加载处理过,则不到Cocoapods的官方spec或者source指定的私有spec中去查询和匹配,而是直接使用已经加载处理过的。

    4、fork后的pod项目,不需要修改podspec中的source,因为只有从Cocoapods的spec中搜索到的库才需要从podspec中读取source来获取源文件。如果是在Podfile中直接指定:git =>的私有库的地址,而不是通过查询spec仓库里的podspec方式匹配来加载的情况下,即使git私有库的项目里podspec指定了spec.source路径,pod执行的时候也会忽略该source路径设置,而是一定会把:git=>指向的地址作为source路径,所以podspec中指定的source在这里不起作用,不过其他的像source_files等配置和编译属性还是起作用的。

    5、通过pod加载本地的类库时,也就是pod '类库名', :path => '本地路径' 这种方式加载本地的类库时,在路径下需要同时包含源文件路径和podspec文件,pod引擎执行的时候一定会从该目录下找源文件,而不会从podspec配置文件中指定的source地址去下载。也就是说这种方式下,podspec中的source配置也是失效的。综上4、5两条来说,podspec中的source配置选项,只有在通过Podfile的source命令配置的spec仓库中找到podspec的时候才会起作用,:git和:path的方式都会忽略source,所以fork后的项目,是不需要调整来源中的podspec.source路径的,反正pod引擎也忽略他。

    6、还有一点需要注意的是,私有库使用:git =>的方式引入,必须要配合:tag或者:commit命令指定其来源的commit id,如果不指定的话,pod引擎会忽略掉podspec中指定的tag(很明显tag是source的一个子属性,source都忽略了肯定也忽略tag),而是每次都去获得最新的一次commit的源码。并且pod引擎不会先去查询类库的git中的最新commit对应的源码是否已经在本地被缓存过,而是一定去下载最新的类库源码然后覆盖缓存,这样造成的后果就是,每次修改了Podfile文件后执行pod update的时候,都会把所有私有库的类库重新git clone一遍完整的源码,非常浪费时间。但是如果指定了:tag或者:commit的话,pod引擎就会优先去缓存中查询,成功匹配到的话就不会再去尝试下载了。

    附:一个不错的git使用中文教程 http://gitbook.liuhui998.com/index.html

    更新2017-05-22

    尝试了一种新的引入pod依赖的方式,即自定义specs仓库。

    1、在github上建立一个新的git仓库ZXSpecs。

    2、进入本地~/.cocoapods/repos目录,通过git clone下载上一步创建的ZXSpecs。

    3、当前下载下来的空的,但是有.git配置文件,然后在ZXSpecs目录下新建自己定义的podspec文件。注意必须是ZXSpecs/Specs/类库名/版本号/.podspec文件,这种目录结构,不符合这种目录的话使用pod repo lint命令验证的时候会报错误。

    4、创建完成podspec文件后,通过pod repo push ZXSpecs xxx.podspec的方式加入到远程仓库中。但这种方式我一直没成功,总是报错(后来证明这种方法需要本地有podspec对应的源码结构,以及源码对应的github远程仓库才能好用),所以就换成直接操作git进行commit然后push的方式。

    5、使用上一步的git push的方式添加spec也要保证符合第三步目录结构,试了一下如果不加<类库名>这一级目录,则pod查找的时候则匹配不到,同名的话会找下一个source中指定的。如果加了<类库名>但是没有加<版本号>,则执行pod update的时候报错不能转换nil。

    6、通过这种方式加入的自己fork后修改过的spec,由于pod的机制是从前往后找source里指定的specs仓库里第一个匹配的,所以要把自己定义的仓库写在github/cocoapods官方库的前面。另外同名的库会报警告。

    [!] Found multiple specifications for `MWPhotoBrowser (2.1.2)`:

    - /xxx/.cocoapods/repos/ZXSpecs/Specs/MWPhotoBrowser/2.1.2/MWPhotoBrowser.podspec

    - /xxx/.cocoapods/repos/AliyunSpecs/Specs/d/7/3/MWPhotoBrowser/2.1.2/MWPhotoBrowser.podspec.json

    不用管它,反正是引用的第一个没问题。再就是发现如果podspec是用.json的方式提供的话,就不会报这个重复定义警告。

    7、原始的cocoapods的repos里面的spec最好不要重命名,就保留原来的master的名字,因为很多像pod search一类的命令,都会默认去master这个名字下的specs里面去找,如果不存在的话,他会强制从github/cocoapods clone specs并且起名叫master。如果把自己从别的源(oschina,aliyun等等)clone出来的镜像改个名字叫master,pod就会从这些进行操作了。

    总结:这种写法,相比之前的,优势是不需要在Podfile文件里指定:git和:commit,只需要pod '类库名'就可以了,再就是最前面需要source ‘‘自定义spec.git’’指定私有库索引来源。如果不指定:tag或者:commit,那么每次都会使用最新的提交的代码,并且能够缓存,不会像使用:git私有库那样每次都去clone一遍。另外需要注意的就是这种方式会读取s.source字段来下载源码,所以fork的项目里的podspec中的source要指向fork之后的地址。

    缺点是不添加新的版本号目录的话,pod就认为该类库没有更新过。即使有新的提交也会忽略。

    附:这篇文章写的也不错,更全面一点。http://blog.csdn.net/xc120313778/article/details/39956979

    更新Ruby环境版本

    参考资料http://www.jianshu.com/p/80944c75c763

    安装ruby命令ruby install 2.4,过程中检查没有安装过Homebrew的话会自动安装。

    顺序为:Xcode -> Homebrew(可选) -> RVM -> Ruby -> CocoaPods

    注意:通过rvm安装的ruby和gem定义在~/.rvm/rubies/ruby-2.4.1/bin/目录下,gems仓库在.rvm/rubies/ruby-2.4.1/lib/ruby/gems/2.4.0/gems下。

    而mac系统自带的gem是在ruby类库中:/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/gem。

    对应的gems仓库是在/Library/Ruby/Gems/2.0.0/gems目录下,我之前安装过好几个版本的cocoapods,用find / -name pod查找一下,结果如下

    /Library/Ruby/Gems/2.0.0/gems/cocoapods-0.37.1/bin/pod

    /Library/Ruby/Gems/2.0.0/gems/cocoapods-0.39.0/bin/pod

    /Library/Ruby/Gems/2.0.0/gems/cocoapods-1.0.1/bin/pod

    /Library/Ruby/Gems/2.0.0/gems/cocoapods-1.2.1/bin/pod

    /Library/Ruby/Gems/2.0.0/gems/cocoapods-plugins-0.4.2/lib/pod

    /Library/Ruby/Gems/2.0.0/gems/cocoapods-plugins-1.0.0/lib/pod

    /Library/Ruby/Gems/2.0.0/gems/cocoapods-trunk-0.6.0/lib/pod

    /Library/Ruby/Gems/2.0.0/gems/cocoapods-trunk-0.6.4/lib/pod

    /Library/Ruby/Gems/2.0.0/gems/cocoapods-trunk-1.0.0/lib/pod

    /Library/Ruby/Gems/2.0.0/gems/cocoapods-trunk-1.2.0/lib/pod

    /Library/Ruby/Gems/2.0.0/gems/cocoapods-try-0.4.4/lib/pod

    /Library/Ruby/Gems/2.0.0/gems/cocoapods-try-0.5.1/lib/pod

    /Library/Ruby/Gems/2.0.0/gems/cocoapods-try-1.0.0/lib/pod

    /Library/Ruby/Gems/2.0.0/gems/cocoapods-try-1.1.0/lib/pod

    但是通过rvm安装了新版本的ruby以后,其实是安装在一个新的路径~/.rvm/rubies/ruby-2.4.1下面。并没有替换到mac系统自带的ruby和gem,并且rvm通过修改.bashrc和.bash_profile把自己下载的ruby路径添加到PATH中优先级更高的位置。于是再次执行pod相关命令时候,系统会执行新安装的gem,并且从.rvm/rubies/ruby-2.4.1/lib/ruby/gems/2.4.0/gems中查找pod命令(至于为什么不从原来的路径下查找pod我也不知道,也许是通过rvm安装ruby和gem后的脚本从PATH中删除掉了原来/Library下的pod,因为which pod找不到),而这时会发现找不到pod命令,解决方法就是使用新的gem命令再安装一遍cocoaPods。

    新版本的gem install cocoapods的时候,会依赖于内部的xcodeproj.gem,不需要本机的xcodeproj.bin,所以也就不需要指定-n /usr/local/bin来避开苹果10.11以后的rootless限制了。

    sudo gem install cocoapods 安装完成后的cocoapods位于:

    ~/.rvm/rubies/ruby-2.4.1/bin/pod

    ~/.rvm/rubies/ruby-2.4.1/lib/ruby/gems/2.4.0/gems/cocoapods-1.2.1/bin/pod

    ~/.rvm/rubies/ruby-2.4.1/lib/ruby/gems/2.4.0/gems/cocoapods-plugins-1.0.0/lib/pod

    ~/.rvm/rubies/ruby-2.4.1/lib/ruby/gems/2.4.0/gems/cocoapods-trunk-1.2.0/lib/pod

    ~/.rvm/rubies/ruby-2.4.1/lib/ruby/gems/2.4.0/gems/cocoapods-try-1.1.0/lib/pod

    这样which ruby / gem / pod,都是在.rvm/rubies/ruby-2.4.1/bin目录下面了,对应的都是最新版本,也就是说每次更新ruby环境的版本,会同时安装对应版本的gem到相同目录,并且export source到PATH中,同时删除之前的PATH,想使用pod就需要重新安装一遍cocoapods到rvm管理的当前版本的ruby对应的目录下。

    其他相关资料

    http://www.jianshu.com/p/fb202af858fd

    http://www.jianshu.com/p/4b63dfbd8be7

    http://www.jianshu.com/p/c6c227c0c221

    http://www.jianshu.com/p/1e5927eeb341

    安装cocoapods http://www.jianshu.com/p/b64b4fd08d3c

    Homebrew的单独安装和使用 http://blog.csdn.net/aaawqqq/article/details/44088141  https://brew.sh

    创建Cocoapods自定义类库 http://blog.wtlucky.com/blog/2015/02/26/create-private-podspec

    http://blog.csdn.net/zaitianaoxiang/article/details/39555153

    Cocoapods使用自定义类库的几种方式 http://blog.csdn.net/xc120313778/article/details/39956979

    相关文章

      网友评论

      • 码客波锣:咨询个问题:私有库依赖私有库时,pod install 是最新版本,pod lib lint 不到最新版本,请问遇到过吗?
        naiyi:@码客波L 你是说lint能验证通过,只是搜索到的不是b的最新版本?但install能安装b的最新版本?我没遇到过这个问题,我都是直接指定到b的:commit=>b的唯一提交id,不指定的话私有库pod每次install都要重新下载一遍然后自己比较版本,即使最新的没变化也会反复下载,这个很浪费时间。我怀疑lint没有这个过程,所以缓存的旧的commit id,你可以在a的podspec中指定b的commit id试试。
        码客波锣:@naiyi 我想要做的是 发布私有库a,私有库a依赖私有库b。:git=> 在podfile文件中写了。pod install 不会报错,可以取到最新版本,没问题。问题在 pod lib lint验证时,我看验证过程不是库b的最新版本
        naiyi:@码客波L 在私有库的podspec里面的依赖项目里指定另一个依赖的私有库的地址不行吗?:git=>那个写法,你是说私有库的名字在公共库里不存在所以lint报错?不用lint验证吧,直接install也会报错吗?

      本文标题:解决环信EaseUI的pod依赖库冲突问题

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