Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Cross-platform Swift

Cross-platform Swift

Swift is now not only available on all four Apple platforms, but also on Linux — and possibly soon elsewhere as well. Each platform has some peculiarities, but we want to write at least some of our code in a way that works on all of them, e.g. to share a piece of business logic between our iOS application and the server-side. This talk gives an overview on which APIs are available cross-platform and how we can effectively build components that work everywhere.

9d2ea021919ff81e02d48530aae191bd?s=128

Boris Bügling

June 16, 2016
Tweet

Transcript

  1. CROSS-PLATFORM SWIFT ALTCONF, JUNE 2016 BORIS BÜGLING - @NEONACHO

  2. COCOAPODS

  3. CONTENTFUL

  4. None
  5. None
  6. CROSS- PLATFORM SWIFT

  7. WHY SWIFT?

  8. YA TU SABES

  9. None
  10. !

  11. WHICH PLATFORMS CAN WE TARGET?

  12. APPLE PLATFORMS ▸ macOS ! ▸ iOS " ▸ watchOS

    ⌚ ▸ tvOS $ ▸ carOS %
  13. FRAMEWORKS SHARED BETWEEN APPLE PLATFORMS CFNetwork.framework CoreData.framework CoreFoundation.framework CoreGraphics.framework CoreLocation.framework

    CoreText.framework Foundation.framework ImageIO.framework Security.framework
  14. THERE'S MORE DEPENDING ON THE SUBSET WE TARGET Accelerate.framework AudioToolbox.framework

    AudioUnit.framework AVFoundation.framework AVKit.framework CloudKit.framework CoreBluetooth.framework
  15. THERE'S MORE DEPENDING ON THE SUBSET WE TARGET CoreImage.framework CoreMedia.framework

    CoreVideo.framework EventKit.framework GameController.framework GameKit.framework GLKit.framework MapKit.framework
  16. THERE'S MORE DEPENDING ON THE SUBSET WE TARGET MediaAccessibility.framework Metal.framework

    MobileCoreServices.framework SceneKit.framework SpriteKit.framework StoreKit.framework SystemConfiguration.framework
  17. UIKIT When only targeting iOS and tvOS

  18. NIBS ! If you don't feel like copy-pasting stuff between

    NIBs ! https://github.com/neonichu/bohne
  19. OPEN SOURCE SWIFT ▸ Linux

  20. OPEN SOURCE SWIFT ▸ FreeBSD (https://github.com/apple/swift/pull/713) ▸ Windows / Cygwin

    (https://github.com/apple/swift/pull/1108) ▸ Android (https://github.com/apple/swift/pull/1442)
  21. None
  22. IMPORTING JNI INTO SWIFT module CJavaVM [system] { header "jni.h"

    link "jvm" export * }
  23. CALLING JAVA USING JNI FROM SWIFT import CJavaVM var vm:

    UnsafeMutablePointer<JavaVM> = nil let env = create_vm(&vm) let jni = env.pointee.pointee let hello_class = jni.FindClass(env, "helloWorld") let main_method = jni.GetStaticMethodID(env, hello_class, "main", "([Ljava/lang/String;)V") jni.CallStaticVoidMethodA(env, hello_class, main_method, [])
  24. A REALLY LONG WAY TO GO !

  25. FRAMEWORKS SHARED BETWEEN all PLATFORMS Foundation.framework https://github.com/apple/swift-corelibs-foundation

  26. FOUNDATION IS INCOMPLETE AND SOMETIMES DIFFERENT FROM OS X #if

    os(Linux) let index = p.startIndex.distanceTo(p.startIndex.successor()) path = NSString(string: p).substringFromIndex(index) #else path = p.substringFromIndex(p.startIndex.successor()) #endif
  27. APPLE'S GOAL ▸ Be compatible with Swift 3.0 ▸ Scheduled

    to ship by the end of 2016
  28. SOME THINGS IN THE STANDARD LIBRARY MIGHT NOT BE AVAILABLE

    #if _runtime(_ObjC) // Excluded due to use of dynamic casting and Builtin.autorelease, neither // of which correctly work without the ObjC Runtime right now. // See rdar://problem/18801510 [...] public func getVaList(args: [CVarArgType]) -> CVaListPointer {
  29. EVEN LIBC IS PROBLEMATIC #if os(Linux) import Glibc #else import

    Darwin.C #endif
  30. E.G. STRUCT MEMBERS CAN BE COMPLETELY DIFFERENT let flags =

    GLOB_TILDE | GLOB_BRACE | GLOB_MARK if system_glob(cPattern, flags, nil, &gt) == 0 { #if os(Linux) let matchc = gt.gl_pathc #else let matchc = gt.gl_matchc #endif
  31. => IT'S COMPLICATED

  32. BUT ONLY RIGHT NOW

  33. HOW TO SHARE CODE BETWEEN THEM

  34. ▸ Shared files ▸ Shared frameworks ▸ Shared packages

  35. SHARED FILES

  36. BUILD CONFIGURATIONS ▸ os(): OSX, iOS, watchOS, tvOS, Linux ▸

    arch(): x86_64, arm, arm64, i386
  37. USING BUILD CONFIGURATIONS #if os(OSX) print("Running on OS X") #elseif

    os(watchOS) print("Running on watchOS") #else print("Running on any platform but OS X and watchOS") #end
  38. CAN ALSO BE USED TO DISTINGUISH VERSIONS (SE-0020) #if swift(>=2.2)

    print("Active!") #else this! code! will! not! parse! or! produce! diagnostics! #endif
  39. OR TO SEE IF YOUR CODE IS BEING BUILT BY

    SWIFTPM #if SWIFT_PACKAGE import Foundation #endif
  40. SHARED FRAMEWORKS

  41. [XCODE 7 BETA] LINKING DUAL (IPHONEOS AND WATCHOS) FRAMEWORKS WITH

    SAME PRODUCT NAME CAUSES ARCHIVE TO FAIL http://openradar.appspot.com/22392501
  42. SHARED PACKAGES/LIBRARIES ▸ CocoaPods ▸ Carthage ▸ Swift Package Manager

  43. COCOAPODS "platforms" : { "osx" : "10.10", "ios": "8.0", "watchos":

    "2.0", "tvos": "9.0" }
  44. IF A POD DOES NOT SUPPORT A CERTAIN PLATFORM ▸

    Fork and add it ▸ Submit a PR ▸ For the adventurous ! https://github.com/orta/cocoapods-expert-difficulty
  45. COCOAPODS AVOIDS 22392501 ▸ Each duplicated target gets scoped ▸

    <.../Build/Debug-iphoneos/Pods-UserTarget/*.framework>
  46. CONCHE ▸ Deprecated now, but nice example of what package

    manifests enable $ conche build Downloading Dependencies -> PathKit 0.5.0 -> Commander 0.5.0 Building Dependencies -> PathKit -> Commander Building Conche Building Entry Points -> conche -> .conche/bin/conche
  47. CARTHAGE ▸ Essentially a nicer way to do shared frameworks

  48. SWIFT PACKAGE MANAGER ▸ Currently the only way to target

    Linux ▸ Does not support iOS, watchOS or tvOS, though
  49. SWIFT PACKAGE MANAGER ▸ No real platform syntax, but can

    use build configs: import PackageDescription var package = Package() #if os(Linux) let target = Target(name: "LinuxSources/foo") package.targets.append(target) #endif
  50. CURRENT STATUS ▸ Use swiftpm for OS X and Linux

    ▸ Use CocoaPods for the iOS-ish platforms ▸ Use build configurations to distinguish
  51. DEVELOPMENT ENVIRONMENT

  52. ▸ Xcode ▸ Xcode + Swift Toolchain ▸ Any editor

    + swift build
  53. None
  54. SWIFT VERSIONS $ cat .swift-version swift-2.2-SNAPSHOT-2015-12-22-a ▸ Is read by

    either chswift or swiftenv
  55. HOW TO TEST/DEVELOP FOR LINUX?

  56. IBM SWIFT SANDBOX ▸ No third party dependencies ▸ Limited

    to 65535 characters in a source file
  57. DOCKER Easiest way on OS X: dlite https://github.com/nlf/dlite/releases $ brew

    install dlite docker $ sudo dlite install $ docker run -it ubuntu bash
  58. DOCKER ▸ A Swift Dockerfile e.g. https://github.com/IBM-MIL/Samples/tree/master/docker- swift $ docker

    build -t swift ./ $ docker run -it swift /bin/bash $ docker ps # Get 'CONTAINER ID' ▸ or docker pull swiftdocker/swift
  59. DOCKER If you don't want to create new containers all

    the time: $ docker start XXXX $ docker exec -it XXXX /bin/bash $ docker stop XXXX
  60. HEROKU ▸ https://github.com/neonichu/swift-buildpack ▸ https://github.com/kylef/heroku-buildpack-swift $ heroku run bash

  61. CI

  62. TRAVIS CI os: - linux - osx language: generic sudo:

    required dist: trusty osx_image: xcode7.2 install: - curl -sL https://gist.github.com/kylef/ 5c0475ff02b7c7671d2a/raw/ 621ef9b29bbb852fdfd2e10ed147b321d792c1e4/swiftenv-install.sh | bash script: - . ~/.swiftenv/init
  63. PRACTICAL EXAMPLE

  64. EMOJI! ! " # $ % & ' ( )

    * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F
  65. ELECTRONIC-MOJI import Foundation import Regex extension Character { public var

    unicodeName: String { let mutableString = NSMutableString(string: "\(self)") CFStringTransform(mutableString, nil, kCFStringTransformToUnicodeName, false) let unicodeName = "\(mutableString)".lowercaseString let regex = Regex(".*\\{(.*)\\}") return regex.match(unicodeName)?.captures.first.flatMap { $0 } ?? unicodeName } } extension CollectionType where Generator.Element == Character { public func findUnicodeName(term: String) -> [Character] { let regex = Regex(".*\(term).*") return self.filter { regex.matches($0.unicodeName) } } }
  66. FRANK Frank is a DSL for quickly writing web applications

    in Swift with type- safe path routing. https://github.com/nestproject/Frank
  67. import Emoji import Frank get { _ in return "Hello

    !\n" } get(*) { (_, name: String) in return (EMOJI.findUnicodeName(name) .map { "\($0)" } .first ?? "¯\\_(ϑ)_/¯") + "\n" }
  68. DEMO

  69. .build/debug/example [2016-04-26 10:21:09 +0200] [65201] [INFO] Listening at http://0.0.0.0:8000 (65201)

    [2016-04-26 10:21:09 +0200] [65202] [INFO] Booting worker process with pid: 65202 [worker] GET / - 200 OK [worker] GET /glasses - 200 OK [worker] GET /nerd - 200 OK $ curl http://localhost:8000 Hello ! $ curl http://localhost:8000/glasses " $ curl http://localhost:8000/nerd #
  70. EMOJI SEARCH KEYBOARD https://github.com/neonichu/emoji-search-keyboard

  71. CLI TOOL $ electronic-moji bird !

  72. CONCLUSION ▸ It's complicated :) ▸ Still a lot of

    code can be shared ▸ Swift 3.0 will help a lot
  73. THANK YOU!

  74. REFERENCES ▸ https://swift.org ▸ https://github.com/neonichu/freedom ▸ https://github.com/kylef/swiftenv ▸ https://github.com/nestproject/Frank ▸

    https://speakerdeck.com/jpsim/practical-cross-platform-swift ▸ https://speakerdeck.com/kylef/end-to-end-building-a-web-
  75. “Experienced engineer examines comments in a legacy module” — =>

    http://classicprogrammerpaintings.com
  76. @NeoNacho boris@contentful.com http://buegling.com/talks