目录

CocoaPods笔记

CocoaPods笔记

1、The master repo requires CocoaPods 1.0.0 - (currently using 0.38.2)

参考:http://blog.cocoapods.org/Sharding/

安装1.0之前(e.g:v0.38.2)版本的pod

1
sudo gem install cocoapods -v 0.38.2

之后在执行pod setup时,由于pod工具已经升级到1.xx版本了,pod算法以及Specs库中的文件结构已经改变,所以它会默认拉取新版本的Specs库,这样就会出现旧版本pod新版本Specs库的情况,当执行pod install的时候会发生找不到xxx第三方库的情况。

解决此问题的方案是需要在Podfile中指定source源地址:

1
source "https://github.com/CocoaPods/Old-Specs"

并把本地的Specs库切换到旧版本:

1
2
3
cd ~/.cocoapods/repos/master/
git fetch origin master
git checkout v0.32.1

最后,在执行pod install的时候需要添加上--no-repo-update标识,因为1.0之前的pod版本在执行pod install的时候会默认先更新升级本地Specs库文件。

以下2张图分别是旧版本的spec库和新版本spec库的结构,大家可以对比一下二者的结构:

/images/cocoapods/pods_oldSpec.png
oldSpec
/images/cocoapods/pods_newSpec.png
newSpec

2、File not found with include; use “quoates” instead

target中手动设置Always Search User PathsYES,也可以通过pod动态设置(推荐)

1
2
3
4
5
6
7
post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
        config.build_settings['ALWAYS_SEARCH_USER_PATHS'] = 'YES'
    end
  end
end

3、Cannot create __weak reference in file using manual reference counting

  • https://github.com/ReactiveCocoa/ReactiveCocoa/issues/2761
  • @mdiep 对出现此问题的原因的解释:In Xcode 7.3, __weak causes errors in files compiled as -fno-objc-arc. Since RAC uses __weak, you cannot use it in those files without setting the Weak References in Manual Retain Release setting to YES. If you’re using a .pch that imports RAC, you’re more likely to see this error.

错误样式如下图所示

/images/cocoapods/pods_reactiveCocoa_issue_2761.png
reactiveCocoa_issue_2761

有3种解决办法:

1)修改源码:把.h文件中报错的__weak标识删除(不能删除.m文件中的,否则会发生内存问题)

2)在引入ReactiveCocoa的地方添加macro判断标识:

1
2
3
#if __has_feature(objc_arc)
#import <ReactiveCocoa/ReactiveCocoa.h>
#endif

3)设置工程文件:设置Weak References in Manual Retain ReleaseYES

/images/cocoapods/pods_weak_reference_setting.png
weak reference in manual

4、“The validator for Swift projects uses Swift 3.0 by default, if you are using a different version of swift you can use a .swift-version file to set the version for you Pod. For example to use Swift 2.3, run: echo "2.3" > .swift-version:”

如下图所示:

/images/cocoapods/pods_swift_versionError.png
SwiftVersionError

解决办法:

pod的引用方式由:git方式改为指定版本号的方式。

5、在podpch文件中添加引用时,比如

1
s.prefix_header_contents = '#import "DDDefine.h"'

不能添加自己工程中的文件,执行pod lib lint时,它会一直报找不到你想引入的文件的错误。

但是你可以在这里添加其他pod中的文件,或者iOS自己API中的库文件。

6、CocoaPods卸载

有的时候不小心把podSpec升级到了1.x 版本,然后pod search就不能用了,然后通过切换分支checkoutv0.32.1,但是pod search还是报错:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
$ pod search ZDTableView
[!] Unable to load a specification for the plugin `/Users/fuxianchao/.rvm/gems/ruby-2.2.1/gems/cocoapods-deintegrate-1.0.0.beta.1`

――― MARKDOWN TEMPLATE ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――

 Command

/Users/fuxianchao/.rvm/gems/ruby-2.2.1/bin/pod search ZDTableView


 Report

* What did you do?

* What did you expect to happen?

* What happened instead?

 Stack

   CocoaPods : 0.38.2
        Ruby : ruby 2.2.1p85 (2015-02-26 revision 49769) [x86_64-darwin14]
    RubyGems : 2.4.8
        Host : Mac OS X 10.12.2 (16C67)
       Xcode : 8.2.1 (8C1002)
         Git : git version 2.11.0
Ruby lib dir : /Users/fuxianchao/.rvm/rubies/ruby-2.2.1/lib
Repositories : cocoapods - https://github.com/CocoaPods/Old-Specs @ 6e256ccc84aad851d401fabb79b2c0f9e09bb875
               DDSpec - http://10.255.223.213/ios-code/DDSpec.git @ 941bed4b0c03090e13ecb7ee16a1eafa77969785
               master - https://github.com/CocoaPods/Specs.git @ 2d939ca0abb4172b9ef087d784b43e0696109e7c

Plugins

cocoapods-keys        : 1.7.0
cocoapods-playgrounds : 0.1.0
cocoapods-plugins     : 0.4.2
cocoapods-search      : 1.0.0.beta.1
cocoapods-stats       : 0.5.3
cocoapods-trunk       : 0.6.4
cocoapods-try         : 0.4.5

Error

NoMethodError - undefined method `all' for Pod::Platform:Class
/Users/fuxianchao/.rvm/gems/ruby-2.2.1/gems/cocoapods-search-1.0.0.beta.1/lib/cocoapods-search/command/search.rb:34:in `initialize'
/Users/fuxianchao/.rvm/gems/ruby-2.2.1@global/gems/claide-0.9.1/lib/claide/command.rb:334:in `new'
/Users/fuxianchao/.rvm/gems/ruby-2.2.1@global/gems/claide-0.9.1/lib/claide/command.rb:334:in `parse'
/Users/fuxianchao/.rvm/gems/ruby-2.2.1@global/gems/claide-0.9.1/lib/claide/command.rb:330:in `parse'
/Users/fuxianchao/.rvm/gems/ruby-2.2.1@global/gems/claide-0.9.1/lib/claide/command.rb:308:in `run'
/Users/fuxianchao/.rvm/gems/ruby-2.2.1/gems/cocoapods-0.38.2/lib/cocoapods/command.rb:48:in `run'
/Users/fuxianchao/.rvm/gems/ruby-2.2.1/gems/cocoapods-0.38.2/bin/pod:44:in `<top (required)>'
/Users/fuxianchao/.rvm/gems/ruby-2.2.1/bin/pod:23:in `load'
/Users/fuxianchao/.rvm/gems/ruby-2.2.1/bin/pod:23:in `<main>'
/Users/fuxianchao/.rvm/gems/ruby-2.2.1/bin/ruby_executable_hooks:15:in `eval'
/Users/fuxianchao/.rvm/gems/ruby-2.2.1/bin/ruby_executable_hooks:15:in `<main>'

――― TEMPLATE END ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――

[!] Oh no, an error occurred.

Search for existing GitHub issues similar to yours:
https://github.com/CocoaPods/CocoaPods/search?q=undefined+method+%60all%27+for+Pod%3A%3APlatform%3AClass&type=Issues

If none exists, create a ticket, with the template displayed above, on:
https://github.com/CocoaPods/CocoaPods/issues/new

Be sure to first read the contributing guide for details on how to properly submit a ticket:
https://github.com/CocoaPods/CocoaPods/blob/master/CONTRIBUTING.md

Don't forget to anonymize any private data!

这时候我的做法通常就是卸载pod ,然后重新安装。

1
2
3
4
$ which pod //得到path
$ sudo rm -rf <path>
// 循环遍历卸载pod组件(如果是安装在了用户目录下,那就去掉命令中的sudo
$ for i in `gem list | grep pod | awk '{print $1}'`; do sudo gem uninstall  $i; done

有的时候对于新系统直接调用gem install cocoapods 是不行的,提示错误,此种情况就用下面的命令:

1
2
3
4
// 安装指定版本的pod
sudo gem install -n /usr/local/bin cocoapods -v 1.2.0
// 卸载
sudo gem uninstall -n /usr/local/bin cocoapods -v 1.2.0

7、Library not found for -lAFNetworking

这种情况的解决方案是设置project -> build setting -> library search patchs 里添加 $(inherited) 标识。

8、Cannot synthesize weak property because the current deployment target does not support weak refernces

refer: http://stackoverflow.com/questions/37160688/set-deployment-target-for-cocoapodss-pod

解决方案:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
post_install do |installer|
    installer.pods_project.targets.each do |target|
        target.build_configurations.each do |config|
            if target.name == 'DDKit'
                config.build_settings['ENABLE_STRICT_OBJC_MSGSEND'] = 'NO'
            elsif target.name == 'PulsingHalo'
                config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '9.2'
            end
        end
    end
end

或者错误提示为:Cannot synthesize weak property in file using manual reference counting

1
2
3
4
5
6
7
8
9
post_install do |installer|
    installer.pods_project.targets.each do |target|
        target.build_configurations.each do |config|
            if target.name == 'ReactiveCocoa'
                config.build_settings['CLANG_ENABLE_OBJC_WEAK'] = 'YES'
            end
        end
    end
end

9、Cocoapods debug

我们可以用 pry 来调试 podfile ,即调试 ruby,使用之前先安装

1
gem install pry

接下来在 podfile 中导入 require 'pry',然后在你想打断点调试的地方添加一行代码 binding.pry,这样就可以在每次执行pod install or pod update 的时候断在这句代码的位置,我们就可以调试了;

10、自动添加modulemap的支持

如果我们想以@import的方式引用一个不支持modulemaprepo,那么我们可以让CocoaPods自动生成modulemap,语法如下:

1
pod 'MLFilterKit', '1.9.705', :modular_headers => true

这个可以解决部分repo@import 报错的问题;

11、为CocoaPods开启增量编译模式:

开启增量编译模式后,post_install、pre_install 中的某些设置会报错,因为工程配置的层级结构发生了变化;

1
2
3
install! 'cocoapods',
         :generate_multiple_pod_projects => true,
         :incremental_installation => true

12、静态库和动态库共存的设置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# https://www.rubydoc.info/gems/cocoapods/Pod
# https://github.com/facebook/flipper/issues/254
# https://github.com/facebook/flipper/blob/master/docs/getting-started.md
$dynamic_framework = ['LayoutInspector', 'PromiseKit', 'Yoga', 'YogaKit']
pre_install do |installer|
#    installer.pod_targets.each do |pod|
#        if $dynamic_framework.include?(pod.name)
#            pod.instance_variable_set(:@host_requires_frameworks, true)
#        end
#    end

  Pod::Installer::Xcode::TargetValidator.send(:define_method, :verify_no_static_framework_transitive_dependencies) {}
  installer.pod_targets.each do |pod|
     if not $dynamic_framework.include?(pod.name)
       def pod.build_type;
          #Pod::Target::BuildType.static_library
          Pod::BuildType.static_library
       end
     end
  end
end


pre_install do |installer|
  $dynamic_framework = ['RxSwift']
  Pod::Installer::Xcode::TargetValidator.send(:define_method,:verify_no_static_framework_transitive_dependencies) {}
  installer.pod_targets.each do |pod|
    if $dynamic_framework.include?(pod.name)
      def pod.build_type;
        Pod::BuildType.dynamic_framework
      end
    end
  end
end

13、使用Ruby特性快速设置头文件

https://github.com/mxcl/PromiseKit/blob/6.15.3/PromiseKit.podspec

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
s.subspec 'CorePromise' do |ss|
    hh = Dir['Sources/*.h'] - Dir['Sources/*+Private.h']

    cc = Dir['Sources/*.swift'] - ['Sources/SwiftPM.swift']
    cc << 'Sources/{after,AnyPromise,GlobalState,dispatch_promise,hang,join,PMKPromise,when,race}.m'
    cc += hh

    ss.source_files = cc
    ss.public_header_files = hh
    ss.preserve_paths = 'Sources/AnyPromise+Private.h', 'Sources/PMKCallVariadicBlock.m', 'Sources/NSMethodSignatureForBlock.m'
end

14、创建文件软链接实现解耦

cocoapods插件文件,在pod install时创建文件软链

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
require 'zd/core' #伪代码
require 'zd/abc/core' #伪代码

require 'cocoapods'
require 'json'
require 'pathname'
require 'fileutils'

module ZD # 伪代码
  module ABC # 伪代码
    module Service
      class AppDefineIntegration
        def before_all
          remove_not_exist_soft_link
        end

        def prepare_install
          create_soft_link
        end

        def remove_unused_files(dir, used_files)
          dir = Pathname.new(dir)
          dir.children.each do |child|
            next if used_files.include?(child.to_s)
            FileUtils.rm_rf(child)
          end
        end

        def remove_not_exist_soft_link
          Dir.glob("#{soft_link_destination_dir}/*.h").each do |file_path|
            FileUtils.rm_rf(file_path) unless File.exist?(file_path) # 真身不存在时,需要删除软连
          end
        end

        def create_soft_link
          FileUtils.mkdir_p(soft_link_destination_dir) unless File.exist?(soft_link_destination_dir)
          
          # 目标文件名
          service_name = "MyAppDefine"

          # 遍历所有本地pod,查找`myappdefine.h`
          pod_local_path_map.each do |pod_name, pod_path|
            # 如果当前目录下已经存在此文件则不需要做软链,跳过,避免陷入死循环
            next if File.exist?(File.join(soft_link_destination_dir, "#{service_name}.h"))

            pod_dir = File.expand_path("#{root_dir}/#{pod_path}")
            file_path = Dir.glob("#{pod_dir}/**/#{service_name}.h").first

            # 不存在则跳过
            next if file_path.nil?

            source_file_path = Pathname.new(File.expand_path(file_path))
            dest_file_path = Pathname.new(File.join(soft_link_destination_dir, File.basename(file_path)))
            dest_dir_path =  Pathname.new(File.dirname(dest_file_path.to_s))
            # 创建软链
            FileUtils.ln_sf(source_file_path.relative_path_from(dest_dir_path), dest_file_path)
          end
        end

        def root_dir
          @root_dir ||= Pod::Config.instance.project_root.to_s
        end

        def pod_root_dir
          @pod_root_dir ||= Pod::Config.instance.project_pods_root.to_s
        end

        def current_dir
          @current_dir ||= File.expand_path(File.dirname(__FILE__))
        end

        def soft_link_destination_dir
          # 路径可以自己指定
          @soft_link_destination_dir = File.join(current_dir, "Core", "Link")
        end

        def podfile_info
          @podfile_info ||= ABC.pod_file_info # 伪代码
        end

        def pod_local_path_map
          @pod_local_path_map ||= begin
            podfile_info.local_root_pod_deps.each_with_object({}) do |dep, hash|
              next unless dep.external? && dep.external_source.include?(:path)
              hash[dep.root_name] = dep.external_source[:path]
            end
          end
        end

      end

    end
  end
end

15、使用自定义的Podspec代替原仓库的Podspec

用以方便的解决原仓库Podspec配置错误或者想使用fork版本的问题

1
2
3
4
5
# Local Podspec
pod 'CombineCocoa', :podspec => './CustomPodspecs/CombineCocoa.podspec'

# Remote Podspec
pod 'CombineCocoa', :podspec => 'https://example.com/CombineCocoa.podspec'

16、通过pod修改代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 通过pod修改代码
post_install do |installer|
    installer.pods_project.targets.each do |target|
      if target.name == 'Flipper'
        file_path = 'Pods/Flipper/xplat/Flipper/FlipperTransportTypes.h'
        contents = File.read(file_path)
        unless contents.include?('#include <functional>')
          File.chmod(0755, file_path)
          File.open(file_path, 'w') do |file|
            file.puts('#include <functional>')
            file.puts(contents)
          end
        end
      end
    end
end

参考: