Slide 1

Slide 1 text

Closed source is best source Cocoaheads Montreal - 11/2016

Slide 2

Slide 2 text

Hi, I'm Romain · @Palleas on Github, Twitter... · iOS developer at Mirego · I love Continuous Integration (it's a disease)

Slide 3

Slide 3 text

Context · Currently working on a project for a super secret client I can't tell you about but OMG it's cool · Working on reusable components for other teams in the company · Unable to give them access to the sources (for now)

Slide 4

Slide 4 text

Creating the framework

Slide 5

Slide 5 text

Creating the framework let emojis = ["!", """, "#", "$"] public func nicify(_ string: String) -> String { let emoji = emojis[Int(arc4random_uniform(UInt32(emojis.count)))] return "\(string) \(emoji)" }

Slide 6

Slide 6 text

Building the framework (⌘ + B)

Slide 7

Slide 7 text

Using the framework in a "sandbox"

Slide 8

Slide 8 text

Using the framework in a "sandbox"

Slide 9

Slide 9 text

Using the framework in a "sandbox"

Slide 10

Slide 10 text

Thank You! Questions ?

Slide 11

Slide 11 text

(Kidding)

Slide 12

Slide 12 text

Running the app on a device (iPhone 7+) Framework is not working on device !

Slide 13

Slide 13 text

That's not how you release a framework

Slide 14

Slide 14 text

Solutions ? · Cocoapods-packager · Carthage · Sweat, tears and command line

Slide 15

Slide 15 text

Cocoapods-packager · Does not seem to play well with Swi! · Not actively maintained by the community https://github.com/CocoaPods/cocoapods- packager

Slide 16

Slide 16 text

Carthage · Carthage is cool · Carthage is slow · Carthage mostly-only works with Github https://github.com/Carthage/Carthage

Slide 17

Slide 17 text

Sweat, tears and command line · Customize the whole process · Learn a lot about frameworks · Still rely on cocoapods

Slide 18

Slide 18 text

Disclaimer I have never done anything like that before

Slide 19

Slide 19 text

The goal · Build a framework · Put it on a server somewhere · Make it available via Cocoapods over HTTPS

Slide 20

Slide 20 text

And CI the shit out of it

Slide 21

Slide 21 text

Let's go back to the framework we built

Slide 22

Slide 22 text

Digging into the framework

Slide 23

Slide 23 text

Switching to the command line with lipo Lipo is a command line tool to interact with The lipo command creates or operates on universal files.

Slide 24

Slide 24 text

Switching to the command line with lipo lipo -info BeingNiceIsNice.framework/BeingNiceIsNice Architectures are: i386 x86_64 Architectures are: * i386 * x86_64

Slide 25

Slide 25 text

Devices architectures iPhone architectures are: * armv7 * armv7s * armv64

Slide 26

Slide 26 text

We need to build for the devices and the simulator...

Slide 27

Slide 27 text

... and merge the products into one framework

Slide 28

Slide 28 text

Building the framework (simulator) xcodebuild -scheme BeingNiceIsNice -arch i386 -arch x86_64 -sdk iphonesimulator only_active_arch=no

Slide 29

Slide 29 text

Building the framework (iphone) xcodebuild -scheme BeingNiceIsNice -arch armv7 -arch armv7s -arch armv64 -sdk iphoneos only_active_arch=no

Slide 30

Slide 30 text

Merging the frameworks? Lipo is a command line tool to interact with universal files. So let's interact. lipo -create -output "BeingNiceIsNice.framework/BeingNiceIsNice" \ "build/Release-iphoneos/BeingNiceIsNice.framework/BeingNiceIsNice" \ "build/Release-iphonesimulator/BeingNiceIsNice.framework/BeingNiceIsNice"

Slide 31

Slide 31 text

Add the missing slices · Copy the *.swiftmodule file from the simulator framework to the new one cp -r "BeingNiceIsNice.framework/Modules/BeingNiceIsNice.swiftmodule/" "BeingNiceIsNice.framework/Modules/BeingNiceIsNice.swiftmodule"

Slide 32

Slide 32 text

Checking $ lipo -info BeingNiceIsNice.framework/BeingNiceIsNice Architectures are: i386 x86_64 arvv7 armv7s arm64

Slide 33

Slide 33 text

What did we do? · Built the framework for the simulator architectures · Built the framework for the devices architectures · Merged two frameworks into a single one

Slide 34

Slide 34 text

Now for the fun part: Fastlane

Slide 35

Slide 35 text

Fastlane · Fastlane is the easiest way to automate building and releasing apps (seriously) · Written in ruby · 500+ contributors · Great documentation · Great community

Slide 36

Slide 36 text

Fastfile platform :ios do # ... desc "Deploy a new version to the App Store" lane :release do # release the framework end end

Slide 37

Slide 37 text

Packaging with fastlane · Bump the version number · Build the project · Zip the framework · Make it available via cocoapods

Slide 38

Slide 38 text

Bump the version number new_version = version_bump_podspec('BeingNiceIsNice.podspec') set_info_plist_value( path: 'BeingNiceIsNice/Info.plist', key: "CFBundleShortVersionString", value: new_version )

Slide 39

Slide 39 text

Build the project sh('build-script-from-earlier.sh')

Slide 40

Slide 40 text

Zip the framework zip( path: "BeingNiceIsNice.framework", output_path: "BeingNiceIsNice-#{new_version}.zip" )

Slide 41

Slide 41 text

Upload the framework somewhere scp( host: 'some-server.com', username: 'somebody', upload: { src: "BeingNiceIsNice-#{new_version}.zip" } )

Slide 42

Slide 42 text

Cocoapods trivia · Podfile · podspec · Specs repository

Slide 43

Slide 43 text

Make it available via cocoapods Pod::Spec.new do |s| s.name = "BeingNiceIsNice" s.version = "0.4.6" # ... s.source = { :http => "http://some-server.com/BeingNiceIsNice-#{s.version}.zip" } s.vendored_frameworks = "BeingNiceIsNice.framework" end

Slide 44

Slide 44 text

Make it available via cocoapods pod_push( path: "BeingNiceIsNice.podspec", repo: 'secret-podspecs' )

Slide 45

Slide 45 text

Using the framework source 'secret-podspecs' # ⚠ target 'BeingNiceIsHard' do # Comment the next line if you're not using Swift and don't want to use dynamic frameworks use_frameworks! pod 'BeingNiceIsNice' end

Slide 46

Slide 46 text

Bonus · Run the test with scan · Generate the documentation: jazzy · ...

Slide 47

Slide 47 text

Thank you! Questions ?