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

Cross-platform Swift

Cross-platform Swift

A talk about writing Swift targeting multiple platforms. Given at App Builders 🇨🇭 2016.

Boris Bügling

April 26, 2016
Tweet

More Decks by Boris Bügling

Other Decks in Programming

Transcript

  1. !

  2. THERE'S MORE DEPENDING ON THE SUBSET WE TARGET Accelerate.framework AudioToolbox.framework

    AudioUnit.framework AVFoundation.framework AVKit.framework CloudKit.framework CoreBluetooth.framework
  3. 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
  4. THERE'S MORE DEPENDING ON THE SUBSET WE TARGET MediaAccessibility.framework Metal.framework

    MobileCoreServices.framework SceneKit.framework SpriteKit.framework StoreKit.framework SystemConfiguration.framework
  5. NIBS ! If you don't feel like copy-pasting stuff between

    NIBs ! https://github.com/neonichu/bohne
  6. 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)
  7. 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, [])
  8. 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
  9. 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 {
  10. 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
  11. 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
  12. 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
  13. OR TO SEE IF YOUR CODE IS BEING BUILT BY

    SWIFTPM #if SWIFT_PACKAGE import Foundation #endif
  14. [XCODE 7 BETA] LINKING DUAL (IPHONEOS AND WATCHOS) FRAMEWORKS WITH

    SAME PRODUCT NAME CAUSES ARCHIVE TO FAIL http://openradar.appspot.com/22392501
  15. 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
  16. COCOAPODS AVOIDS 22392501 ▸ Each duplicated target gets scoped ▸

    <.../Build/Debug-iphoneos/Pods-UserTarget/*.framework>
  17. 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
  18. SWIFT PACKAGE MANAGER ▸ Currently the only way to target

    Linux ▸ Does not support iOS, watchOS or tvOS, though
  19. 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
  20. CURRENT STATUS ▸ Use swiftpm for OS X and Linux

    ▸ Use CocoaPods for the iOS-ish platforms ▸ Use build configurations to distinguish
  21. 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
  22. 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
  23. 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
  24. CI

  25. 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
  26. EMOJI! ! " # $ % & ' ( )

    * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F
  27. 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) } } }
  28. FRANK Frank is a DSL for quickly writing web applications

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

    !\n" } get(*) { (_, name: String) in return (EMOJI.findUnicodeName(name) .map { "\($0)" } .first ?? "¯\\_(ϑ)_/¯") + "\n" }
  30. .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://0.0.0.0:8000 Hello ! $ curl http://0.0.0.0:8000/glasses " $ curl http://localhost:8000/nerd #
  31. CONCLUSION ▸ It's complicated :) ▸ Still a lot of

    code can be shared ▸ Swift 3.0 will help a lot
  32. 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-