Slide 1

Slide 1 text

COCOAPODS PLUGINS COCOAHEADS BERLIN, JULY 2014 BORIS BÜGLING - @NEONACHO

Slide 2

Slide 2 text

YO

Slide 3

Slide 3 text

AGENDA ▸ CocoaPods itself ▸ Useful plugins ▸ How to build your own plugin

Slide 4

Slide 4 text

COCOAPODS

Slide 5

Slide 5 text

THE DE-FACTO DEPENDENCY MANAGER

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

▸ Core ▸ cocoapods-downloader ▸ Xcodeproj ▸ CLAide ▸ CocoaPods

Slide 8

Slide 8 text

CORE spec = Pod::Specification.from_file('CPDColors.podspec') puts spec.name puts spec.version $ ./core.rb CPDColors 0.1.0

Slide 9

Slide 9 text

COCOAPODS-DOWNLOADER def download_head! hg! %|clone #{url} #{@target_path.shellescape}| [...] end def download_revision! hg! %|clone "#{url}" --rev '#{options[:revision]}' #{@target_path [...] end def download_tag! hg! %|clone "#{url}" --updaterev '#{options[:tag]}' #{@target_path [...] end

Slide 10

Slide 10 text

XCODEPROJ wrkspace = Xcodeproj::Workspace.new_from_xcworkspace( 'CPDColors/Example/Demo.xcworkspace') puts wrkspace.schemes $ ./xcodeproj.rb {"Demo"=>"/Users/boris/Projects/CPDColors/Example/Demo.xcodeproj", "Pods"=>"/Users/boris/Projects/CPDColors/Example/Pods/Pods.xcodeproj"}

Slide 11

Slide 11 text

CLAIDE argv = CLAide::ARGV.new(['tea', '--no-milk', '--sweetner=honey']) argv.shift_argument # => 'tea' argv.shift_argument # => nil argv.flag?('milk') # => false argv.flag?('milk') # => nil argv.option('sweetner') # => 'honey' argv.option('sweetner') # => nil

Slide 12

Slide 12 text

COCOAPODS $ pod install Analyzing dependencies Pre-downloading: `DBCamera` from `https://github.com/[...]` Downloading dependencies Installing ARASCIISwizzle (1.1.0) Installing Bolts (1.1.0) [...] Generating Pods project Integrating client project

Slide 13

Slide 13 text

COCOAPODS PLUGINS ▸ Add subcommands to pod, the tool ▸ Each plugin is a Gem ▸ Same access as built-in commands

Slide 14

Slide 14 text

USEFUL PLUGINS

Slide 15

Slide 15 text

$ pod trunk push

Slide 16

Slide 16 text

$ pod plugins list

Slide 17

Slide 17 text

▸ Uses https://github.com/CocoaPods/cocoapods.org/blob/master/ plugins.json

Slide 18

Slide 18 text

$ pod try BBUSegmentedViewController

Slide 19

Slide 19 text

$ pod lib docstats

Slide 20

Slide 20 text

$ pod lib testing

Slide 21

Slide 21 text

$ pod package ContentfulDeliveryAPI.podspec

Slide 22

Slide 22 text

$ pod roulette

Slide 23

Slide 23 text

HOW TO BUILD YOUR OWN PLUGIN

Slide 24

Slide 24 text

WHAT? ▸ Package a Pod as a static framework ▸ Including dependencies ▸ All supported platforms ▸ Generate a corresponding podspec

Slide 25

Slide 25 text

$ pod package AFNetworking.podspec

Slide 26

Slide 26 text

LET'S GET STARTED

Slide 27

Slide 27 text

$ pod plugins create cocoapods-packager

Slide 28

Slide 28 text

TEMPLATE ▸ Just a Git repo, similar to the pod template ▸ Reads as much from the environment as possible ▸ Result is installable, shippable

Slide 29

Slide 29 text

DEFINE THE COMMAND module Pod class Command class Package < Command self.summary = 'Package a podspec into a static library.' self.arguments = [['NAME', :required]] [...] end end end

Slide 30

Slide 30 text

PARSE THE SPEC def spec_with_path(path) if !path.nil? && Pathname.new(path).exist? @path = path Specification.from_file(path) end end

Slide 31

Slide 31 text

RUN def run if @spec builder = SpecBuilder.new(@spec) newspec = builder.spec_metadata @spec.available_platforms.each do |platform| build_in_sandbox(platform) newspec += builder.spec_platform(platform) end newspec += builder.spec_close File.open(@spec.name + '.podspec', 'w') { |file| file.write(newspec) } else help! 'Unable to find a podspec with path or name.' end end

Slide 32

Slide 32 text

FRAGMENT OF SPECGENERATOR s.#{platform.name}.platform = :#{platform.symbolic_name}, '#{platform.deployment_target}' s.#{platform.name}.preserve_paths = '#{fwk_base}' s.#{platform.name}.public_header_files = '#{fwk_base}/Versions/A/Headers/*.h' s.#{platform.name}.vendored_frameworks = '#{fwk_base}'

Slide 33

Slide 33 text

BUILD FOR A SPECIFIC PLATFORM def build_in_sandbox(platform) config.sandbox_root = 'Pods' config.integrate_targets = false config.skip_repo_update = true sandbox = install_pod(platform.name) UI.puts 'Building framework' xcodebuild versions_path, headers_path = create_framework_tree(platform.name.to_s) `cp #{sandbox.public_headers.root}/#{@spec.name}/*.h #{headers_path}` Pathname.new(config.sandbox_root).rmtree Pathname.new('Podfile.lock').delete end

Slide 34

Slide 34 text

INSTALL FROM GENERATED PODFILE def install_pod(platform_name) podfile = podfile_from_spec(platform_name, @spec.deployment_target(platform_name)) sandbox = Sandbox.new(config.sandbox_root) installer = Installer.new(sandbox, podfile) installer.install! sandbox end

Slide 35

Slide 35 text

GENERATE THAT PODFILE def podfile_from_spec(platform_name, deployment_target) name = @spec.name path = @path podfile = Pod::Podfile.new do platform(platform_name, deployment_target) if path pod name, :podspec => path else pod name, :path => '.' end end podfile end

Slide 36

Slide 36 text

$ rake install

Slide 37

Slide 37 text

$ pod package AFNetworking.podspec

Slide 38

Slide 38 text

▸ Push your repo to GH ▸ Release as Ruby Gem ▸ Send a PR to the cocoapods.org repo

Slide 39

Slide 39 text

$ git push $ rake release $ gem install cocoapods-packager

Slide 40

Slide 40 text

!

Slide 41

Slide 41 text

FUTURE ▸ cocoapods-testing ▸ cocoapods-coverage ▸ cocoapods-playgrounds ▸ ...

Slide 42

Slide 42 text

THANK YOU!

Slide 43

Slide 43 text

LINKS ▸ http://www.objc.io/issue-6/cocoapods-under-the-hood.html ▸ http://guides.cocoapods.org ▸ https://github.com/CocoaPods/Rainforest

Slide 44

Slide 44 text

HTTP://VU0.ORG/CP-PLUGINS @NEONACHO

Slide 45

Slide 45 text

IT'S A ZERO!