一、前言

  • Cocoapods 有很多比较实用的小插件,比如 cocoapods-open ( 执行 pod open 可以直接打开 .xcworkspace 文件),这些插件 gem 都有特定的目录分层。一开始以为自己要从零开始配置,后来发现 cocoapods-plugin 本身就提供了用来创建一个模版工程的 create 命令。
  • 输入以下命令即可创建一个模版工程:
// 安装
gem install cocoapods-plugins
// 创建
pod plugins create NAME [TEMPLATE_URL]
  • 在这个需求中,创建一个 author 子命令,输入:
pod plugins create author
  • 当前路径下会生成 cocoapods-author 目录,其结构如下:
.
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── cocoapods-author.gemspec
├── lib
│   ├── cocoapods-author
│   │   ├── command
│   │   │   └── author.rb
│   │   ├── command.rb
│   │   └── gem_version.rb
│   ├── cocoapods-author.rb
│   └── cocoapods_plugin.rb
└── spec├── command│   └── author_spec.rb└── spec_helper.rb
  • author.rb 的初始内容如下:
module Podclass Command# This is an example of a cocoapods plugin adding a top-level subcommand# to the 'pod' command.## You can also create subcommands of existing or new commands. Say you# wanted to add a subcommand to `list` to show newly deprecated pods,# (e.g. `pod list deprecated`), there are a few things that would need# to change.## - move this file to `lib/pod/command/list/deprecated.rb` and update#   the class to exist in the the Pod::Command::List namespace# - change this class to extend from `List` instead of `Command`. This#   tells the plugin system that it is a subcommand of `list`.# - edit `lib/cocoapods_plugins.rb` to require this file## @todo Create a PR to add your plugin to CocoaPods/cocoapods.org#       in the `plugins.json` file, once your plugin is released.#class Author < Command# pod plugins list 时,展示的概要信息self.summary = 'Short description of cocoapods-author.'# --help / 命令错误时展示的描述信息self.description = <<-DESCLonger description of cocoapods-author.DESC# --help / 命令错误时展示的参数信息self.arguments = 'NAME'def initialize(argv)@name = argv.shift_argumentsuperend# 校验方法(查看文件是否存在等)def validate!superhelp! 'A Pod name is required.' unless @nameend# 运行命令def runUI.puts "Add your implementation for the cocoapods-author plugin in #{__FILE__}"endendend
end
  • 如何创建 list 的子命令 deprecated:
    • 移动目标文件至 lib/pod/command/list/deprecated.rb,并且将这个子命令类放进 Pod::Command::List 命名空间中;
    • 更改子命令类的父类为 List;
    • 在 lib/cocoapods_plugins.rb 中载入该文件。
  • 如果不需要子命令,直接继承 Command 就可以。

二、获取 Podfile untagged 组件名

  • 如下所示的人方法返回没有依赖 tag 的组件哈希,为了简单处理,直接获取 target_definitions 第一个元素的 dependencies 作为工程的依赖进行遍历:
UNTAGGED_FLAGS = [:path, :git, :branch, :commit]def load_untageed_dependencies_hashfile_path = Dir.pwd + '/Podfile'raise %Q[没有找到 Podfile,请确认是否在 Podfile 所在文件夹\n] unless File.file?(file_path)podfile = Podfile.from_file(file_path)dependencies = podfile.to_hash['target_definitions'].first['dependencies']# UI.puts dependenciesuntageed_dependencies = dependencies.select do |dependency|tagged = trueif dependency.kind_of? Hashfirst = dependency.values.first.firstif first.kind_of? Hash tagged = first.keys.reduce(true) do |result, flag|!UNTAGGED_FLAGS.include?(flag) & resultendelsif first.kind_of? Stringtagged = true   endelsif dependency.is_a?(String)tagged = true end!taggedenduntageed_dependencies.reduce({}) do |result, dependency|result.merge(dependency)end
end

三、获取本地私有源获取组件的作者

  • 获取本地私有源的组件作者:
def load_pod_authors(spec_files)author_hash = {}  spec_files.each do |file|if !file.nil? && File.file?(file)podspec = Specification.from_file(file)   pod_authors = podspec.attributes_hash['authors']if pod_authors.kind_of? Hashauthor = pod_authors.keys.firstelsif pod_authors.kind_of? Arrayauthor = pod_authors.firstelseauthor = pod_authorsendauthor = author.downcaseif !author.nil? && !podspec.name.nil?author_hash[author] =  author_hash[author].nil? ? [] : author_hash[author]author_hash[author].append(podspec.name)endendendauthor_hash
end
  • 获取组员信息:
def load_boss_keeper_membersmember_hash = {}@memebrs_hash.uniq.map.each do |nickname| reform_memeber_hash_proc = -> nickname, realname donickname = nickname.downcase unless !nickname.nil?pinyin = Pinyin.t(nickname, splitter: '').downcaseif pinyin != nickname member_hash[nickname] = realnameendmember_hash[pinyin] = realnameendif nickname.kind_of? Hashname = nickname.keys.first.dup.force_encoding("UTF-8")nickname.values.first.append(name).each do |nickname|reform_memeber_hash_proc.call(nickname, name)enddef load_pod_authors(spec_files)author_hash = {}  spec_files.each do |file|if !file.nil? && File.file?(file)podspec = Specification.from_file(file)   pod_authors = podspec.attributes_hash['authors']if pod_authors.kind_of? Hashauthor = pod_authors.keys.firstelsif pod_authors.kind_of? Arrayauthor = pod_authors.firstelseauthor = pod_authorsendauthor = author.downcaseif !author.nil? && !podspec.name.nil?author_hash[author] =  author_hash[author].nil? ? [] : author_hash[author]author_hash[author].append(podspec.name)endendendauthor_hash
endelsereform_memeber_hash_proc.call(nickname, nickname)endendmember_hash
end
  • 如果 @ 组员需要手机号码,那么该部分数据可以从本地的 yaml 文件读取:
file_path = File.join(File.dirname(__FILE__),"boss_keeper_members.yaml")
yaml_hash =
beginYAML.load_file(file_path)
rescue Psych::SyntaxError, Errno::EACCES, Errno::ENOENT{}
end@memebrs_hash = yaml_hash['members']
@mobiles = yaml_hash["mobiles"].reduce({}){ |result, mobile| result.merge(mobile) }
  • 由于作者一栏存在用花名、原名、昵称的情况,所以 yaml 文件基本格式如下:
members:
- 青木:- tripleCCmobiles:
- 青木:- 1xxxxxxx

四、匹配本地存储的组员名

  • 首先匹配是组内组员管理的组件,如果是其它组创建的组件,暂时忽略:
def load_valid_pod_authors_hashauthors_hash = {}@pod_authors.each do |name, pods|member_name = @boss_keeper_members[name.downcase]if !member_name.nil?member_name = member_name.downcaseauthor_pods = authors_hash[member_name].nil? ? [] : authors_hash[member_name]authors_hash[member_name] = author_pods.append(pods).flattenendendauthors_hash
end
  • 然后将结果和未指定 tag 的组件哈希匹配:
def load_untageed_dependencies_authors_hashauthors_hash = {}valid_pod_authors = load_valid_pod_authors_hashuntageed_dependencies_hash = load_untageed_dependencies_hashuntageed_dependencies_hash.keys.each do |pod|valid_pod_authors.each do  |author, pods|if pods.include?(pod)authors_hash[author] = authors_hash[author].nil? ? [] : authors_hash[author]authors_hash[author].append(pod)endendendauthors_hash
end

五、整合发送

  • 通过 git rev-parse --abbrev-ref HEAD 获取当前所在分支,然后根据作者、组件名、手机号码创建 curl 命令并执行:
def post_message_to_ding_talkcurrent_branch = `git rev-parse --abbrev-ref HEAD`.stripuntageed_dependencies_authors_hash = load_untageed_dependencies_authors_hashuntageed_dependencies_authors_hash.each do |author, pods|content = author + ",#{current_branch}分支" + ",下面的仓库打个版本:" + pods.join(',')if !@mobiles[author].nil?mobile = @mobiles[author].firstendcurl = %Q[curl 'https://oapi.dingtalk.com/robot/send?access_token=xxxxxxx' \-H 'Content-Type: application/json' \-d '{"msgtype": "text", "text": {"content": "#{content}"},"at": {"atMobiles": ["#{mobile}"], "isAtAll": false}}']# UI.puts curlKernel.system curlend
end
  • 如果后续对这个插件进行扩展的话,还应该考虑根据私有源自动生成 Podfile,解决封版时需要手动修改 Podfile 的情况,麻烦而且可能存在把版本号写错的情况。

iOS之深入解析如何编写自己的CocoaPods插件相关推荐

  1. iOS组件化系列之RubyMine如何调试Cocoapods插件

    前言 Cocoapods大家应该非常熟悉了,但是一般很少有人去看源码,那就更少人去写插件了,如果要全局掌控工程架构,那必须熟悉这些插件的使用,而且还有个问题,即使你写插件,但是网上根本找不到资料告诉你 ...

  2. iOS之深入解析消息转发objc_msgSend的应用场景

    一.消息转发 现有如下示例: id o = [NSObject new]; [o lastObject]; 执行上面代码,程序会崩溃并抛出以下异常: [NSObject lastObject]: un ...

  3. iOS事件全面解析 (触摸事件、手势识别、摇晃事件、耳机线控)

    -- iOS事件全面解析 概览 iPhone的成功很大一部分得益于它多点触摸的强大功能,乔布斯让人们认识到手机其实是可以不用按键和手写笔直接操作的,这不愧为一项伟大的设计.今天我们就针对iOS的触摸事 ...

  4. ReactNative与iOS通信原理解析-通信篇

    文章首发个人博客: ReactNative与iOS通信原理解析-通信篇 导语:其实原本是想编写一篇  react-native (下文简称 rn) 在  iOS 中如何实现  jsbridge 的文章 ...

  5. iOS基础-数据解析方法初步总结-(XML,JSON欢迎指正)

    小时候的记忆与大家一起分享,愿君安好! 解析的基本概念 解析: 从事先规定好的格式中提取数据 解析的前提: 提前约定好格式,数据提供方按照格式提供数据,数据获取方则按照格式获取数据 OS开发常见的解析 ...

  6. iOS Sprite Kit教程之编写程序以及Xcode的介绍

    iOS Sprite Kit教程之编写程序以及Xcode的介绍 Xcode界面介绍 一个Xcode项目由很多的文件组成,例如代码文件.资源文件等.Xcode会帮助开发者对这些文件进行管理.所以,Xco ...

  7. Xamarin iOS教程之编辑界面编写代码

    Xamarin iOS教程之编辑界面编写代码 Xamarin iOS的Interface Builder Interface Builder被称为编辑界面.它是一个虚拟的图形化设计工具,用来为iOS应 ...

  8. iOS之深入解析dyld与ObjC关联的底层原理

    App启动与dylb加载 我们知道 dyld 的加载过程,即在 App 启动启动执行 main 函数之前,dylb 主要作了环境变量配置.共享缓存.主程序的初始化.插入动态库.链接主程序.链接动态库. ...

  9. iOS之深入解析objc_msgSend消息转发机制的底层原理

    一.抛砖引玉 objc_msgSend() 消息发送的过程就是 通过 SEL 查找 IMP 的过程 . objc_msgSend() 是用 汇编语言 实现的,使用汇编实现的优势是: 消息发送的过程需要 ...

最新文章

  1. 7-9将灰度转为彩色
  2. T.38 and the future
  3. ruby之添加当前文件路径到$LOAD_PATH
  4. 文本分类有哪些论文中很少提及却对性能有重要影响的tricks?
  5. 2020腾讯二次元营销通案
  6. 二叉树、多叉树子路径遍历
  7. 一文带你了解人工智能最新进展:AI从业者如何选择技术路线?
  8. Ural1297 最长回文子串(后缀数组+RMQ)
  9. 奇虎周鸿祎:创业者不要太偏执
  10. 用 JavaScript 编写日历
  11. 2020最新部编人教小学语文状元大课堂课件教案习题全套
  12. 电脑录屏怎么把声音录进去?这些方法可以帮到你!
  13. 藤子不二雄博物馆之行
  14. Vue中的过滤器(管道)
  15. yolo3各部分代码(超详细)
  16. 生育登记服务制度啥意思?生育服务证和准生证一回事吗?生育那些事
  17. VerilogHDL二分频代码
  18. 深度学习Python环境打包到另外一台电脑(详细教程)
  19. css实现文字旋转360度
  20. 速写为什么要把人画丑?骨骼肌肉比画的更像加分

热门文章

  1. RedHat5.5_X64 Linux安装oracle 11.2.0.3 报错
  2. Win7 修改默认Administrator 密码方法
  3. Python异常体系结构图
  4. mybatis 一对一与一对多collection和association的使用
  5. 构造 Codeforces Round #275 (Div. 2) C. Diverse Permutation
  6. QDir, QFileInfo 和 QDirIterator 区别
  7. linux下能ping ip不能ping域名详解
  8. autocad.net中判断当前被激活的空间
  9. 笔记本输入法, u、i 等字母变成了数字
  10. 输入A、B,输出A+B