Build Features Not Apps

73
BUILD FEATURES, NOT APPS @NATASHATHEROBOT

Transcript of Build Features Not Apps

Page 1: Build Features Not Apps

BUILD FEATURES, NOT APPS

@NATASHATHEROBOT

Page 2: Build Features Not Apps

SWIFT ROBOT▸ NatashaTheRobot.com▸ @NatashaTheNomad▸ This Week in Swift▸ Swift Jobs▸ try! Swift

Page 3: Build Features Not Apps
Page 4: Build Features Not Apps

Most smartphone users download 0 apps per month

Page 5: Build Features Not Apps

An average app loses up to 95% of users within the first month

Page 6: Build Features Not Apps

!!!

Page 7: Build Features Not Apps
Page 8: Build Features Not Apps
Page 9: Build Features Not Apps

!"

Page 10: Build Features Not Apps

FEATURE:

NOTIFICATIONS

Page 11: Build Features Not Apps
Page 12: Build Features Not Apps
Page 13: Build Features Not Apps
Page 14: Build Features Not Apps

FEATURE:

SPEECH RECOGNITION

Page 15: Build Features Not Apps
Page 16: Build Features Not Apps
Page 17: Build Features Not Apps

"As speech recognition accuracy goes from say 95% to 99%, all of us in the room will from barely using it today to using it all the time. Most

people underestimate the difference between 95% and 99% accuracy - 99% is a game changer" - Andrew NG, Chief Scientist at Baidu

Page 18: Build Features Not Apps

SIRI INTENTS▸ Audio or video calling▸ Messaging▸ Payments

▸ Searching photos▸ Workouts▸ Ride booking

Page 19: Build Features Not Apps

FEATURE:

EXTENSIONS

Page 20: Build Features Not Apps
Page 21: Build Features Not Apps
Page 22: Build Features Not Apps
Page 23: Build Features Not Apps
Page 24: Build Features Not Apps

"It took Line Messenger almost four months to find its first two million

users ...

Page 25: Build Features Not Apps

… but after stickers were launched, it took only two days to find the next

million...

Page 26: Build Features Not Apps

The company now makes over $270M a year just from selling stickers."

Page 27: Build Features Not Apps

THE FUTURE?

Page 28: Build Features Not Apps
Page 29: Build Features Not Apps

! -> "

Page 30: Build Features Not Apps

ARCHITECTING FOR FEATURES

Page 31: Build Features Not Apps

▸ Frameworks all the things!▸ Vectorize Images▸ NSUserActivity FTW

Page 32: Build Features Not Apps
Page 33: Build Features Not Apps
Page 34: Build Features Not Apps

!

Page 35: Build Features Not Apps
Page 36: Build Features Not Apps
Page 37: Build Features Not Apps

OPEN VS PUBLIC

Page 38: Build Features Not Apps
Page 39: Build Features Not Apps

let rootURL = FileManager.default().containerURLForSecurityApplicationGroupIdentifier("group.com.NatashaTheRobot.MyFavoriteGelato")

Page 40: Build Features Not Apps

let defaults = UserDefaults(suiteName: "group.com.NatashaTheRobot.MyFavoriteGelato")

Page 41: Build Features Not Apps
Page 42: Build Features Not Apps

! + ⌚ + #

Page 43: Build Features Not Apps
Page 44: Build Features Not Apps
Page 45: Build Features Not Apps
Page 46: Build Features Not Apps

MULTIPLATFORM, SINGLE-SCHEME XCODE PROJECTS

by Max Howell on PromiseKit.org

Page 47: Build Features Not Apps

FRAMEWORKS▸ DRY

▸ App Groups▸ iCloud Key-Value Storage▸ Cross-Platform

Page 48: Build Features Not Apps

VECTORIZE IMAGES

Page 49: Build Features Not Apps

.PDF

Page 50: Build Features Not Apps
Page 51: Build Features Not Apps
Page 52: Build Features Not Apps
Page 53: Build Features Not Apps
Page 54: Build Features Not Apps

iceCreamImageView.tintColor = .purple

Page 55: Build Features Not Apps
Page 56: Build Features Not Apps

VECTORIZE IMAGES▸ Single Scale PDFs

▸ Template Image for Icons

Page 57: Build Features Not Apps

NSUSERACTIVITY FTW

Page 58: Build Features Not Apps

// AppDelegatefunc application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool{

if userActivity.activityType == NSUserActivityTypeBrowsingWeb, let webpageURL = userActivity.webpageURL {

// separate webpageURL using NSURLComponents // present the correct View Controller if valid // otherwise, open link in Safari } return false}

Page 59: Build Features Not Apps
Page 60: Build Features Not Apps
Page 61: Build Features Not Apps
Page 62: Build Features Not Apps
Page 63: Build Features Not Apps
Page 64: Build Features Not Apps

CREATING AN ACTIVITY// GelatoDetailViewController

override func viewDidLoad() { super.viewDidLoad() // other config here

let activity = NSUserActivity(activityType: "com.natashatherobot.GelatoFinder.gelato")

// will show up as this in Spotlight Search Results activity.title = gelato.name

// Other keywords to search by activity.keywords = Set([gelato.name, "gelato"])

// should be handed off to another device? activity.isEligibleForHandoff = true // should be indexed in App History? activity.isEligibleForSearch = true // should be eligible for indexing for any user of this application? activity.isEligibleForPublicIndexing = true

// Avoid deallocating before indexing, // global variable declared in UIResponder class userActivity = activity

// don't forget to activate! userActivity!.becomeCurrent()

}

Page 65: Build Features Not Apps

SAVE UNIQUE INFO// GelatoDetailViewController

override func viewDidLoad() { // create activity and other config here activity.delegate = self activity.needsSave = true // assign to userActivity, etc}

extension GelatoDetailViewController: NSUserActivityDelegate { func userActivityWillSave(_ userActivity: NSUserActivity) { // info needed to recreate activity! userActivity.userInfo = ["index": gelatoIndex] }}

Page 66: Build Features Not Apps

RESTORE ACTIVITY// AppDelegate

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool{ let mainController = (window!.rootViewController! as! UINavigationController).viewControllers.first mainController?.restoreUserActivityState(userActivity) return true}

Page 67: Build Features Not Apps

RESTORE ACTIVITY// GelatoListTableViewController

override func restoreUserActivityState(_ activity: NSUserActivity) { if let index = activity.userInfo?["index"] as? Int { searchedGelatoIdentifier = index performSegue(withIdentifier: "showGelato", sender: self) }}

Page 68: Build Features Not Apps

RESTORE ACTIVITY// GelatoListTableViewController

override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if let gelatoDetailVC = segue.destination as? GelatoDetailViewController { let index = tableView.indexPathForSelectedRow?.row ?? searchedGelatoIdentifier ?? 0 gelatoDetailVC.gelato = gelatoFlavors[index] gelatoDetailVC.gelatoIndex = index }}

Page 69: Build Features Not Apps
Page 70: Build Features Not Apps

NSUSERACTIVITY▸ Handoff

▸ Universal Links▸ Search▸ Location

▸ Contextual Reminders▸ Contact Interactions

Page 71: Build Features Not Apps
Page 72: Build Features Not Apps

▸ Frameworks all the things!▸ Vectorize Images▸ NSUserActivity FTW

Page 73: Build Features Not Apps

BUILD FEATURES, NOT APPS

@NATASHATHEROBOT