$30 off During Our Annual Pro Sale. View Details »

Closed source is best source

Closed source is best source

Releasing a private Swift framework using Cocoapods, Fastlane and some command line tools.

Romain Pouclet

November 19, 2016
Tweet

More Decks by Romain Pouclet

Other Decks in Programming

Transcript

  1. Closed source is best
    source
    Cocoaheads Montreal - 11/2016

    View Slide

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

    View Slide

  3. 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)

    View Slide

  4. Creating the framework

    View Slide

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

    View Slide

  6. Building the framework (⌘ + B)

    View Slide

  7. Using the framework in a "sandbox"

    View Slide

  8. Using the framework in a "sandbox"

    View Slide

  9. Using the framework in a "sandbox"

    View Slide

  10. Thank You!
    Questions ?

    View Slide

  11. (Kidding)

    View Slide

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

    View Slide

  13. That's not how you release
    a framework

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  18. Disclaimer
    I have never done anything like
    that before

    View Slide

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

    View Slide

  20. And CI the shit out of it

    View Slide

  21. Let's go back to the
    framework we built

    View Slide

  22. Digging into the framework

    View Slide

  23. 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.

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  27. ... and merge the products
    into one framework

    View Slide

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

    View Slide

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

    View Slide

  30. 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"

    View Slide

  31. 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"

    View Slide

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

    View Slide

  33. 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

    View Slide

  34. Now for the fun part:
    Fastlane

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  42. Cocoapods trivia
    · Podfile
    · podspec
    · Specs repository

    View Slide

  43. 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

    View Slide

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

    View Slide

  45. 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

    View Slide

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

    View Slide

  47. Thank you!
    Questions ?

    View Slide