# Pod

## 1. 组件的地址

我们在做组件化的时候经常将一些业务模块封装打包，做成 pod 管理的形式，然后当在开发的时候需要修改一些模块化的代码。

当维护好组件的时候我们可能在一个新的工程设置好 podfile 引入组件，但是有可能需要继续修改组件的源代码，代码需要可编辑。所以我们可能需要将 Podfile 中的 pod 源修改为本地。
然后安装 pod install 后就可以看到在项目文件里面有可编辑的组件代码

```
pod 'GoodsCategoryModule', :path => '../GoodsCategoryModule'
#pod 'GoodsCategoryModule',:git => 'git@gitlab.xxx.com:forntend_ios/GoodsCategoryModule.git',:branch => 'release/Appstore'
```

注意点：
1. 我们本地的组件源代码需要和 pod 文件中的代码工程文件名称一致
2. 注释掉远端仓库的地址
path 后面是相对路径

## 2. 组件库使用 pch 头文件

```Objective-c
///一个区分开发和线上环境的Log。NSLog的本质是调用对象方法的 description 方法，所以线上代码使用NSLog会造成性能和安全问题
#ifdef DEBUG
    #define SafeLog(...) NSLog(__VA_ARGS__)
#else
    #define SafeLog(...)
#endif
```

所以我们需要对各个组件库里面的 **NSLog** 进行改造，变成 **SafeLog**。没做特殊处理，当你在 pod 库的 pch 文件写好代码，发现主工程执行 pod install 之后，看到之前写的 SafeLog 代码不见了。所以我们需要指定 pch 文件。
操作：
- 新建 **PrefixHeader.h** 头文件
- 在当前 pod 库的 ***.podspec 文件中写如下代码 
```Ruby
  s.prefix_header_contents = '#import "PrefixHeader.h"'
```
说明：该代码的作用相当于将 PrefixHeader.h 文件写入到当前 pod 库 XQTriggerKit-prefix.pch 文件的最后一行。相当于
```Objective-c
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif

#import "PrefixHeader.h"
```

缺点：项目存在多个 pod 组件库。主工程修改 pch 还好，但是每个 pod 库都去新建 PrefixHeader.h 文件和 podspec 文件添加一行代码。工作量非常大。

改进方案：对 NSLog 进行 Hook。

步骤：
- 引入 fishhook 库
- 新建 SafeLog.h 和 SafeLog.m 文件
- 在 SafeLog.m 文件的 load 方法中对 NSLog 进行 hook，判断是 Debug 环境就打印。代码如下

```Objective-c
#import "SafeLog.h"
#import "fishhook.h"

// orig_NSLog是原有方法被替换后 把原来的实现方法放到另一个地址中
// new_NSLog就是替换后的方法了
static void (*orig_NSLog)(NSString *format, ...);

@implementation SafeLog

void(new_NSLog)(NSString *format, ...)
{
    va_list args;
    if (format) {
        va_start(args, format);
        NSString *message = [[NSString alloc] initWithFormat:format arguments:args];
        #ifdef DEBUG
            orig_NSLog(@"%@", message);
        #endif
        va_end(args);
    }
}

+ (void)load
{
    rebind_symbols((struct rebinding[1]){ {"NSLog", new_NSLog, (void *)&orig_NSLog} }, 1);
}

@end
```

## 3. CocoPods 指定版本号带 ~> 与不带的区别

- 带 ~> 是指库版本号的一个范围。大于等于指定的版本号，小于高一位的版本号
- 不带 ~> 是指固定的版本号

```
pod 'aaa', '~> 0.1.2'  // 大于等于 0.1.2 且小于 0.2
pod 'bbb', '1.1' 版本号指定为 1.1

```

## 4. 查看当前 Pod 库被何处引用

出于某种原因经常会需要查看当前 Pod 库被何处引用了（你需要修改组件库A，然后A修改完之后，可能需要在依赖组件库A的地方去修改版本号。这时候就需要查询了，例子可能不优雅，但是确实有需要查询引用的情况），有轮子

- 先下载所需要的库
```Shell
gem install reversepoddependency
```
- 利用脚本在我们的组件库 repo 中去查询
```
specbackwarddependency /Users/liubinpeng/.cocoapods/repos/51xianqu-xq_specs(本地CocoPod repo地址) xq_baaidumapkit(组件库名称)
```

鉴于这个命令比较长，且本人使用的是 iTerm2+Zsh，所以将命令写入到 .zshrc 文件中， source 编译链接过可以快速使用。例如 `repoanalysis xq_baaidumapkit`
```Shell
alias repoanalysis='specbackwarddependency /Users/liubinpeng/.cocoapods/repos/51xianqu-xq_specs' 
```

![Pod组件库依赖分析](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2019-05-09-PodComponentAnalysis.png)

具体的操作步骤可以参考我的这个[文章](https://github.com/FantasticLBP/knowledge-kit/blob/master/第六部分%20开发杂谈/6.11.md)


## 5. lint 的时候安装一些神奇的依赖


在对 App 做应用包瘦身的时候发现了一些问题。某个组件库 lint 的时候通过终端的信息，发现安装了一些不是 podspec 里面指定的依赖仓库。百思不得其解，同事说可能是之前的某个版本依赖了这些项目。有了这个思路就好办事了。

![遇到问题](https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/2019-05-13-Cocopod-Lint-Cache.png)

- 打开本地的 `/Users/liubinpeng/.cocoapods/repos` 文件夹。查看本地的私有 repo 的管理的所有的项目，找到出问题的 repo，进去删掉有问题的 tag。
- 出问题的 repo 将远端的有问题的 tag 也删掉
- 删除远端的 repo 仓库的有问题的 tag。

## 6. lint 失败 - 报错为 `error: invalid task ('StripNIB...`
```Shell
Build system information
    error: invalid task ('StripNIB /Users/liubinpeng/Library/Developer/Xcode/DerivedData/App-fgbnpsgtrtstroctiqnanvyrfwyr/Build/Products/Release-iphonesimulator/XQLoginModule/SDGMemberCardBindViewController.nib') with mutable output but no other virtual output node (in target 'XQLoginModule')
```
原因为 xib 和图片资源都属于资源文件，不可以放在源文件（Classes）中，需要放在 Assets 中。如果放到 Classes 文件夹中 lint 会报错。

## 7. 一台电脑安装了最新版本的，出问题删除最新版 Xcode，下载旧版本 Xcode，pod install 失败

```Shell
You need at least git version 1.8.5 to use CocoaPods
```
- 可能是cocoapods安装成功了，但是链接Xcode的版本过低，所以需要更新Xcode
- 电脑安装了多个版本的Xcode，就需要修改链接Xcode路径，改成链接电脑比较高版本的Xcode。
   ```Shell
   sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer
   ```
## 8. 一台电脑安装了最新版本的，出问题删除最新版 Xcode，下载旧版本 Xcode，打开工程 Xib 报错

- sudo killall -9 com.apple.CoreSimulator.CoreSimulatorService
- xcrun simctl erase all


## 9. 开发电脑上安装了旧版本 Cocopods,Mac 系统升级后, pod lint 失败

解决方案: 将 **fourflusher** 仓库中上的 [find.rb]((https://raw.githubusercontent.com/CocoaPods/fourflusher/master/lib/fourflusher/find.rb)) 文件中的 ruby 脚本复制到本地的 fourflusher 下. 

查找本地 fourflusher 文件夹所在位置.
```Shell
gem which fourflusher
```
我的电脑 find.rb 文件所在位置.
`/Library/Ruby/Gems/2.6.0/gems/fourflusher-2.3.1/lib/fourflusher/find.rb`

注意: 文件保存需要权限,所以加 sudo

## 10. pod lint 产生的信息太多,一屏显示不全,但是出错之后我们可能需要去查看 error 信息,上下翻页不方便

解决方案: 利用脚本 ` >1.log 2>&1` 将当前的 pod lint 产生的信息写入文件.

完整代码

```Ruby
 pod lib lint --sources=****,**** --allow-warnings --verbose --use-libraries >1.log 2>&1
```


## 11. pod 库每次修改代码,主工程必须 clean 再安装才可以看到新改动的代码

解决方案: 
```ruby
install! 'cocoapods', :disable_input_output_paths => true
```

## 12. pod 库太多,每次构建编译都很耗费时间

```ruby
install! 'cocoapods', generate_multiple_pod_projects: true
```

## 13. 卸载旧版本 cocoapods 安装新的

```shell
 sudo gem uninstall cocoapods-core cocoapods cocoapods-deintegrate cocoapods-downloader cocoapods-plugins cocoapods-search cocoapods-stats cocoapods-trunk cocoapods-try coderay colored2 concurrent-ruby cocoapods-clean
sudo gem install cocoapods
```