Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

COCOAPODS

Slide 3

Slide 3 text

CONTENTFUL

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

CROSS- PLATFORM SWIFT

Slide 7

Slide 7 text

WHY SWIFT?

Slide 8

Slide 8 text

YA TU SABES

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

!

Slide 11

Slide 11 text

WHICH PLATFORMS CAN WE TARGET?

Slide 12

Slide 12 text

APPLE PLATFORMS ▸ macOS ! ▸ iOS " ▸ watchOS ⌚ ▸ tvOS $ ▸ carOS %

Slide 13

Slide 13 text

FRAMEWORKS SHARED BETWEEN APPLE PLATFORMS CFNetwork.framework CoreData.framework CoreFoundation.framework CoreGraphics.framework CoreLocation.framework CoreText.framework Foundation.framework ImageIO.framework Security.framework

Slide 14

Slide 14 text

THERE'S MORE DEPENDING ON THE SUBSET WE TARGET Accelerate.framework AudioToolbox.framework AudioUnit.framework AVFoundation.framework AVKit.framework CloudKit.framework CoreBluetooth.framework

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

THERE'S MORE DEPENDING ON THE SUBSET WE TARGET MediaAccessibility.framework Metal.framework MobileCoreServices.framework SceneKit.framework SpriteKit.framework StoreKit.framework SystemConfiguration.framework

Slide 17

Slide 17 text

UIKIT When only targeting iOS and tvOS

Slide 18

Slide 18 text

NIBS ! If you don't feel like copy-pasting stuff between NIBs ! https://github.com/neonichu/bohne

Slide 19

Slide 19 text

OPEN SOURCE SWIFT ▸ Linux

Slide 20

Slide 20 text

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)

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

IMPORTING JNI INTO SWIFT module CJavaVM [system] { header "jni.h" link "jvm" export * }

Slide 23

Slide 23 text

CALLING JAVA USING JNI FROM SWIFT import CJavaVM var vm: UnsafeMutablePointer = 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, [])

Slide 24

Slide 24 text

A REALLY LONG WAY TO GO !

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

APPLE'S GOAL ▸ Be compatible with Swift 3.0 ▸ Scheduled to ship by the end of 2016

Slide 28

Slide 28 text

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 {

Slide 29

Slide 29 text

EVEN LIBC IS PROBLEMATIC #if os(Linux) import Glibc #else import Darwin.C #endif

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

=> IT'S COMPLICATED

Slide 32

Slide 32 text

BUT ONLY RIGHT NOW

Slide 33

Slide 33 text

HOW TO SHARE CODE BETWEEN THEM

Slide 34

Slide 34 text

▸ Shared files ▸ Shared frameworks ▸ Shared packages

Slide 35

Slide 35 text

SHARED FILES

Slide 36

Slide 36 text

BUILD CONFIGURATIONS ▸ os(): OSX, iOS, watchOS, tvOS, Linux ▸ arch(): x86_64, arm, arm64, i386

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

OR TO SEE IF YOUR CODE IS BEING BUILT BY SWIFTPM #if SWIFT_PACKAGE import Foundation #endif

Slide 40

Slide 40 text

SHARED FRAMEWORKS

Slide 41

Slide 41 text

[XCODE 7 BETA] LINKING DUAL (IPHONEOS AND WATCHOS) FRAMEWORKS WITH SAME PRODUCT NAME CAUSES ARCHIVE TO FAIL http://openradar.appspot.com/22392501

Slide 42

Slide 42 text

SHARED PACKAGES/LIBRARIES ▸ CocoaPods ▸ Carthage ▸ Swift Package Manager

Slide 43

Slide 43 text

COCOAPODS "platforms" : { "osx" : "10.10", "ios": "8.0", "watchos": "2.0", "tvos": "9.0" }

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

COCOAPODS AVOIDS 22392501 ▸ Each duplicated target gets scoped ▸ <.../Build/Debug-iphoneos/Pods-UserTarget/*.framework>

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

CARTHAGE ▸ Essentially a nicer way to do shared frameworks

Slide 48

Slide 48 text

SWIFT PACKAGE MANAGER ▸ Currently the only way to target Linux ▸ Does not support iOS, watchOS or tvOS, though

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

CURRENT STATUS ▸ Use swiftpm for OS X and Linux ▸ Use CocoaPods for the iOS-ish platforms ▸ Use build configurations to distinguish

Slide 51

Slide 51 text

DEVELOPMENT ENVIRONMENT

Slide 52

Slide 52 text

▸ Xcode ▸ Xcode + Swift Toolchain ▸ Any editor + swift build

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

SWIFT VERSIONS $ cat .swift-version swift-2.2-SNAPSHOT-2015-12-22-a ▸ Is read by either chswift or swiftenv

Slide 55

Slide 55 text

HOW TO TEST/DEVELOP FOR LINUX?

Slide 56

Slide 56 text

IBM SWIFT SANDBOX ▸ No third party dependencies ▸ Limited to 65535 characters in a source file

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

HEROKU ▸ https://github.com/neonichu/swift-buildpack ▸ https://github.com/kylef/heroku-buildpack-swift $ heroku run bash

Slide 61

Slide 61 text

CI

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

PRACTICAL EXAMPLE

Slide 64

Slide 64 text

EMOJI! ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F

Slide 65

Slide 65 text

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) } } }

Slide 66

Slide 66 text

FRANK Frank is a DSL for quickly writing web applications in Swift with type- safe path routing. https://github.com/nestproject/Frank

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

DEMO

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

EMOJI SEARCH KEYBOARD https://github.com/neonichu/emoji-search-keyboard

Slide 71

Slide 71 text

CLI TOOL $ electronic-moji bird !

Slide 72

Slide 72 text

CONCLUSION ▸ It's complicated :) ▸ Still a lot of code can be shared ▸ Swift 3.0 will help a lot

Slide 73

Slide 73 text

THANK YOU!

Slide 74

Slide 74 text

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-

Slide 75

Slide 75 text

“Experienced engineer examines comments in a legacy module” — => http://classicprogrammerpaintings.com

Slide 76

Slide 76 text

@NeoNacho [email protected] http://buegling.com/talks