Page 1
#WWDC17
© 2017 Apple Inc. All rights reserved. Redistribution or public display not permitted without written permission from Apple.
Kasia Wawer, iOS Keyboards Shuchen Li, iOS Keyboards James Magahern, iOS Keyboards
•The Keys to a Better Text Input Experience •Crafting a better typing experience in your app • Session 242
App Frameworks
Page 2
Create a Better Input Experience
Page 3
Create a Better Input Experience
•Integrate the keyboard into your layout
Page 4
Create a Better Input Experience
•Integrate the keyboard into your layout•Create dynamic input accessory views
Page 5
Create a Better Input Experience
•Integrate the keyboard into your layout•Create dynamic input accessory views•Make your app multilingual
Page 6
Create a Better Input Experience
•Integrate the keyboard into your layout•Create dynamic input accessory views•Make your app multilingual•Use traits for smarter QuickType
Page 7
Create a Better Input Experience
•Integrate the keyboard into your layout•Create dynamic input accessory views•Make your app multilingual•Use traits for smarter QuickType•Hardware keyboard support
Page 8
Create a Better Input Experience
•Integrate the keyboard into your layout•Create dynamic input accessory views•Make your app multilingual•Use traits for smarter QuickType•Hardware keyboard support•Custom input views
Page 9
Create a Better Input Experience
•Integrate the keyboard into your layout•Create dynamic input accessory views•Make your app multilingual•Use traits for smarter QuickType•Hardware keyboard support•Custom input views•Keyboard extension tips and best practices
Page 10
Kasia Wawer, iOS Keyboards
•Integrating the Keyboard into Your App •Adaptivity and input accessory views
Page 12
•Accounting for changing keyboard heights •Working with non-scrolling layouts •Working with scrolling layouts •Adding an input accessory view
Page 13
Accounting for the Keyboard
Page 14
Accounting for the Keyboard
Heights vary by language and settings
Page 15
Accounting for the Keyboard
Heights vary by language and settings
Page 16
Accounting for the Keyboard
Heights vary by language and settings
Page 17
Accounting for the Keyboard
Heights vary by language and settings
Page 18
Accounting for the Keyboard
Heights vary by language and settings
Page 19
Accounting for the Keyboard
Heights vary by language and settings
Register for notifications UIKeyboardDidShow UIKeyboardDidHide UIKeyboardDidChangeFrame
Page 20
Undocked and Split Keyboards
Page 21
Undocked and Split Keyboards
Dismissing and undocking both send Hide notifications
Page 22
Undocked and Split Keyboards
Dismissing and undocking both send Hide notifications
Frame change notifications will continue when undocked
Page 23
Undocked and Split Keyboards
Dismissing and undocking both send Hide notifications
Frame change notifications will continue when undocked
Track the most recent Hide or Show event
Page 26
Being in the Right Space
@objc func keyboardFrameChanged(_ notification: Notification) -> Void { if !keyboardIsHidden { guard let userInfo = notification.userInfo, let frame = userInfo[UIKeyboardFrameEndUserInfoKey] as? CGRect else { return } let convertedFrame = view.convert(frame, from: UIScreen.main.coordinateSpace) let intersectedKeyboardHeight = view.frame.intersection(convertedFrame).height } }
Page 27
Being in the Right Space
Keyboard is always in the screen coordinate space
@objc func keyboardFrameChanged(_ notification: Notification) -> Void { if !keyboardIsHidden { guard let userInfo = notification.userInfo, let frame = userInfo[UIKeyboardFrameEndUserInfoKey] as? CGRect else { return } let convertedFrame = view.convert(frame, from: UIScreen.main.coordinateSpace) let intersectedKeyboardHeight = view.frame.intersection(convertedFrame).height } }
Page 28
Being in the Right Space
Keyboard is always in the screen coordinate space
Convert the frame from screen coordinates
@objc func keyboardFrameChanged(_ notification: Notification) -> Void { if !keyboardIsHidden { guard let userInfo = notification.userInfo, let frame = userInfo[UIKeyboardFrameEndUserInfoKey] as? CGRect else { return } let convertedFrame = view.convert(frame, from: UIScreen.main.coordinateSpace) let intersectedKeyboardHeight = view.frame.intersection(convertedFrame).height } }
Page 29
Being in the Right Space
Keyboard is always in the screen coordinate space
Convert the frame from screen coordinates
Use the intersection of the converted keyboard frame and your view
@objc func keyboardFrameChanged(_ notification: Notification) -> Void { if !keyboardIsHidden { guard let userInfo = notification.userInfo, let frame = userInfo[UIKeyboardFrameEndUserInfoKey] as? CGRect else { return } let convertedFrame = view.convert(frame, from: UIScreen.main.coordinateSpace) let intersectedKeyboardHeight = view.frame.intersection(convertedFrame).height } }
Page 30
•Accounting for changing keyboard heights •Working with non-scrolling layouts •Working with scrolling layouts •Adding an input accessory view
Page 32
Create a custom UILayoutGuide and height constraint
Adaptive Keyboard-Inclusive Layouts
func setUpViews() { // ... view set up ... let keyboardGuide = UILayoutGuide() view.addLayoutGuide(keyboardGuide) heightConstraint = keyboardGuide.heightAnchor.constraint(equalToConstant: kDefaultHeight) heightConstraint.isActive = true // ... view set up ... }
Page 33
Create a custom UILayoutGuide and height constraint
Tie lowest view to top of your layout guide
Adaptive Keyboard-Inclusive Layouts
func setUpViews() { // ... keyboardGuide.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) .isActive = true bottomSpacer.bottomAnchor.constraint(equalTo: keyboardGuide.topAnchor).isActive = true // ... }
Page 34
Create a custom UILayoutGuide and height constraint
Tie lowest view to top of your layout guide
Adaptive Keyboard-Inclusive Layouts
func setUpViews() { // ... keyboardGuide.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) .isActive = true bottomSpacer.bottomAnchor.constraint(equalTo: keyboardGuide.topAnchor).isActive = true // ... }
Page 35
@objc func keyboardFrameChanged(_ notification: Notification) -> Void { if !keyboardIsHidden { // ... Convert frame ... UIView.animate(withDuration: 0.2) { heightConstraint.constant = intersectedKeyboardHeight view.layoutIfNeeded() } } }
Create a custom UILayoutGuide and height constraint
Tie lowest view to top of your layout guide
Use the converted frame to set the height constraint of layout guide
Adaptive Keyboard-Inclusive Layouts
Page 36
@objc func keyboardFrameChanged(_ notification: Notification) -> Void { if !keyboardIsHidden { // ... Convert frame ... UIView.animate(withDuration: 0.2) { heightConstraint.constant = intersectedKeyboardHeight view.layoutIfNeeded() } } }
Create a custom UILayoutGuide and height constraint
Tie lowest view to top of your layout guide
Use the converted frame to set the height constraint of layout guide
Adaptive Keyboard-Inclusive Layouts
Page 37
•Accounting for changing keyboard heights •Working with non-scrolling layouts •Working with scrolling layouts •Adding an input accessory view
Page 39
Scrolling Views and Keyboards
@objc func keyboardFrameChanged(_ notification: Notification) -> Void { if !keyboardIsHidden { // ... Convert frame ... scrollView.contentInset.bottom = intersectedKeyboardHeight // ... Handle content scrolling ... } }
Page 40
Scrolling Views and Keyboards
Make sure the keyboard is visible
@objc func keyboardFrameChanged(_ notification: Notification) -> Void { if !keyboardIsHidden { // ... Convert frame ... scrollView.contentInset.bottom = intersectedKeyboardHeight // ... Handle content scrolling ... } }
Page 41
Scrolling Views and Keyboards
Make sure the keyboard is visible
Convert the frame and get the height
@objc func keyboardFrameChanged(_ notification: Notification) -> Void { if !keyboardIsHidden { // ... Convert frame ... scrollView.contentInset.bottom = intersectedKeyboardHeight // ... Handle content scrolling ... } }
Page 42
Scrolling Views and Keyboards
Make sure the keyboard is visible
Convert the frame and get the height
Set content insets appropriately
@objc func keyboardFrameChanged(_ notification: Notification) -> Void { if !keyboardIsHidden { // ... Convert frame ... scrollView.contentInset.bottom = intersectedKeyboardHeight // ... Handle content scrolling ... } }
Page 43
Scrolling Views and Keyboards
Make sure the keyboard is visible
Convert the frame and get the height
Set content insets appropriately
Handle scrolling the content if needed
@objc func keyboardFrameChanged(_ notification: Notification) -> Void { if !keyboardIsHidden { // ... Convert frame ... scrollView.contentInset.bottom = intersectedKeyboardHeight // ... Handle content scrolling ... } }
Page 44
UITableViewController
Sets insets for you
Handle scrolling the content if needed
Page 45
UITableViewController
Sets insets for you
Handle scrolling the content if needed
@objc func keyboardFrameChanged(_ notification: Notification) -> Void { let bottomRow = IndexPath(row: items.count - 1, section: 0) tableView.scrollToRow(at: bottomRow, at: UITableViewScrollPosition.bottom, animated: true) }
Page 46
•Accounting for changing keyboard heights •Working with non-scrolling layouts •Working with scrolling layouts •Adding an input accessory view
Page 48
Accessorizing the Keyboard
Page 49
Host view controller returns true for canBecomeFirstReponder
Accessorizing the Keyboard
Page 50
Host view controller returns true for canBecomeFirstReponder
Use custom view or view controller • For view, override inputAccessoryView • For view controller, override inputAccessoryViewController
Accessorizing the Keyboard
Page 51
Host view controller returns true for canBecomeFirstReponder
Use custom view or view controller • For view, override inputAccessoryView • For view controller, override inputAccessoryViewController
Changing height sends frame change notifications
Accessorizing the Keyboard
Page 52
Making Dynamic Input Accessory Views
Send
Page 53
Making Dynamic Input Accessory Views
Use expanding view to define height
Send
Page 54
Making Dynamic Input Accessory Views
Use expanding view to define height
Pin to top and bottom of content view Send
Page 55
Making Dynamic Input Accessory Views
Use expanding view to define height
Pin to top and bottom of content view
Use or define intrinsicContentSize
Send
expandingTextView.textContainer.heightTracksTextView = true expandingTextView.isScrollEnabled = false
Page 56
Making Dynamic Input Accessory Views
Use expanding view to define height
Pin to top and bottom of content view
Use or define intrinsicContentSize
Send
I’ll let you know if Ican come by then.
expandingTextView.textContainer.heightTracksTextView = true expandingTextView.isScrollEnabled = false
Page 57
// Using intrinsicContentSize to determine height
override var intrinsicContentSize: CGSize { var newSize = self.bounds.size newSize.height = kMinimumHeight if expandingTextView.bounds.size.height > 0.0 { newSize.height = expandingTextView.bounds.size.height + kVerticalPadding } if newSize.height > kMaximumHeight { newSize.height = kMaximumHeight } return newSize }
Page 58
// Using intrinsicContentSize to determine height
override var intrinsicContentSize: CGSize { var newSize = self.bounds.size newSize.height = kMinimumHeight if expandingTextView.bounds.size.height > 0.0 { newSize.height = expandingTextView.bounds.size.height + kVerticalPadding } if newSize.height > kMaximumHeight { newSize.height = kMaximumHeight } return newSize }
Page 59
// Using intrinsicContentSize to determine height
override var intrinsicContentSize: CGSize { var newSize = self.bounds.size newSize.height = kMinimumHeight if expandingTextView.bounds.size.height > 0.0 { newSize.height = expandingTextView.bounds.size.height + kVerticalPadding } if newSize.height > kMaximumHeight { newSize.height = kMaximumHeight } return newSize }
Page 60
// Using intrinsicContentSize to determine height
override var intrinsicContentSize: CGSize { var newSize = self.bounds.size newSize.height = kMinimumHeight if expandingTextView.bounds.size.height > 0.0 { newSize.height = expandingTextView.bounds.size.height + kVerticalPadding } if newSize.height > kMaximumHeight { newSize.height = kMaximumHeight } return newSize }
Page 61
// Using intrinsicContentSize to determine height
override var intrinsicContentSize: CGSize { var newSize = self.bounds.size newSize.height = kMinimumHeight if expandingTextView.bounds.size.height > 0.0 { newSize.height = expandingTextView.bounds.size.height + kVerticalPadding } if newSize.height > kMaximumHeight { newSize.height = kMaximumHeight } return newSize }
Page 62
// Using intrinsicContentSize to determine height
override var intrinsicContentSize: CGSize { var newSize = self.bounds.size newSize.height = kMinimumHeight if expandingTextView.bounds.size.height > 0.0 { newSize.height = expandingTextView.bounds.size.height + kVerticalPadding } if newSize.height > kMaximumHeight { newSize.height = kMaximumHeight } return newSize }
Page 64
Shuchen Li, iOS Keyboards
•Making Your App Feel Magical •Using context to enrich text input experience
Page 65
•Multilingual •Being aware of context •The new “smarts” •Marked text •Hardware keyboard
Page 68
Remembering User Selected Keyboard
Look up Identifier
Set Selected Keyboard
Your App
User Defaults
<unique identifier 1> : en_US
<unique identifier 4> : pl_PL<unique identifier 3> : zh_Hans
…
<unique identifier 2> : en_US
User-selected Keyboard
Context Identifier String
Page 69
Remembering User Selected Keyboard
Look up Identifier
Set Selected Keyboard
Your App
User Defaults
<unique identifier 1> : en_US
<unique identifier 4> : pl_PL<unique identifier 3> : zh_Hans
…
<unique identifier 2> : en_US
User-selected Keyboard
Context Identifier String
Page 71
ChatInputAccessoryView
becomesFirstResponder
Page 72
ChatInputAccessoryView
becomesFirstResponder
Page 73
ChatInputAccessoryView
ConversationViewController
becomesFirstResponder
Page 74
ChatInputAccessoryView
ConversationViewController
Navigation Controller
becomesFirstResponder
Page 75
becomesFirstResponder
ChatInputAccessoryView
ConversationViewController
Navigation Controller
Page 76
Text Input Context Identifier
class ConversationViewController: UITableViewController, UITextViewDelegate {
// ... other code ...
override var textInputContextIdentifier: String? {
// Returning some unique identifier here allows the keyboard to remember
// which language the user was typing in when they were last communicating
// with this person.
// It can be anything, as long as it's unique to each
// recipient (here we're just returning the name)
return self.conversation?.otherParticipant
}
// ... other code ...
}
Page 77
Text Input Context Identifier
class ConversationViewController: UITableViewController, UITextViewDelegate {
// ... other code ...
override var textInputContextIdentifier: String? {
// Returning some unique identifier here allows the keyboard to remember
// which language the user was typing in when they were last communicating
// with this person.
// It can be anything, as long as it's unique to each
// recipient (here we're just returning the name)
return self.conversation?.otherParticipant
}
// ... other code ...
}
Page 78
Kasia Wawer, iOS Keyboards
•Demo •Give your app a memory
Page 79
UIResponder to Remember Keyboard
textInputContextIdentifier
UITextInputMode
Page 80
•Multilingual •Being aware of context •The new “smarts” •Marked text •Hardware keyboard
Page 81
Being Aware of Context
UIKeyboardType
UITextContentTypes
Page 82
QuickType personal information
Page 83
QuickType personal information
Page 85
QuickType address
Page 86
QuickType address
Page 88
QuickType sources
(From Maps)
Page 89
UITextContentType
Provides contextual predictions
Displays on QuickType bar
Increase Usage of Your App With Proactive Suggestions WWDC 2016
Page 90
Log In
UITextContentTypeUsername
UITextContentTypePassword
Page 91
Log In
UITextContentTypeUsername
UITextContentTypePassword
Page 92
Content Types for Password AutoFill
Introducing Password AutoFill for Apps WWDC 2017
NEW
Log In
UITextContentTypeUsername
UITextContentTypePassword
Page 93
•Multilingual •Being aware of context •The new “smarts” •Marked text •Hardware keyboard
Page 94
Smart Quote and Smart DashNEW
Page 95
Smart Quote and Smart Dash
SF Hello "a" “a”
Helvetica Neue "a" “a”
Lucida Grande "a" “a”
Avenir "a" “a”
Myriad Set "a" “a”
NEW
Page 96
Smart Quote and Smart Dash
SF Hello "a" “a”
Helvetica Neue "a" “a”
Lucida Grande "a" “a”
Avenir "a" “a”
Myriad Set "a" “a”
NEW
Page 97
Smart Quote and Smart Dash
Hyphen: 1-dash - ➜ -SF Hello "a" “a”
Helvetica Neue "a" “a”
Lucida Grande "a" “a”
Avenir "a" “a”
Myriad Set "a" “a”
NEW
Page 98
Smart Quote and Smart Dash
Hyphen: 1-dash - ➜ -
En dash: 2-dash - - ➜ –
SF Hello "a" “a”
Helvetica Neue "a" “a”
Lucida Grande "a" “a”
Avenir "a" “a”
Myriad Set "a" “a”
NEW
Page 99
Smart Quote and Smart Dash
Hyphen: 1-dash - ➜ -
En dash: 2-dash - - ➜ –
Em dash: 3-dash - - - ➜ —
SF Hello "a" “a”
Helvetica Neue "a" “a”
Lucida Grande "a" “a”
Avenir "a" “a”
Myriad Set "a" “a”
NEW
Page 100
Smart Insertion and Deletion
Vivian will bring Misiu and Jiwang to the party.Vivian will bring Misiuand Jiwangto the party.
Page 101
Smart Insertion and Deletion
Vivian will bring Misiu and Jiwang to the party.Vivian will bring Misiuand Jiwangto the party.
Page 102
Smart Insertion and Deletion
Vivian will bring Misiu and Jiwang to the party.Vivian will bring Misiu to the party.
Page 103
Smart Insertion and Deletion
Vivian will bring Misiu and Jiwang to the party.Vivian will bring Misiu and Jiwang to the party.
Page 104
Smart Insertion and Deletion
Vivian will bring Misiu and Jiwang to the party.Vivian will bring Misiu and Jiwang to the party.
Page 105
Smart Insertion and Deletion
Vivian will bring Misiu and Jiwang to the party.Vivian will bring Misiu and Jiwang to the party.
Page 106
Smart Insertion and Deletion
Vivian will bring Misiu and Jiwang to the party.Vivian will bring Misiuand Jiwangto the party.
Page 107
Smart Insertion and Deletion
Vivian will bring Misiu and Jiwang to the party.Vivian will bring Misiuand Jiwangto the party.
Page 108
UITextInputTraits
Page 109
UITextInputTraits
.default
.yes
.no
Page 110
UITextInputTraits
.default
.yes
.no
Understand your text entry
Page 111
•Multilingual •Being aware of context •The new “smarts” •Marked text •Hardware keyboard
Page 112
Marked text search
Page 113
Marked Text
Internationalization Best Practices WWDC 2016
Page 114
•Giving text widget a memory •Being aware of context •The new “smarts” •Marked text •Hardware keyboard
Page 115
Working with Hardware Keyboard
Key commands for hardware keyboards
Page 116
// UIKeyCommand
class ConversationViewController: UITableViewController, UITextViewDelegate {
// ... some code ...
override var keyCommands: [UIKeyCommand]? { return [ // Command + Down arrow goes to the next conversation UIKeyCommand(input: UIKeyInputDownArrow, modifierFlags: .command, action: #selector(switchToConversationKeyCommandInvoked(sender:)), discoverabilityTitle: NSLocalizedString("GO_TO_NEXT_CONVERSATION", comment: "")), // Command + Up arrow goes to the previous conversation UIKeyCommand(input: UIKeyInputUpArrow, modifierFlags: .command, action: #selector(switchToConversationKeyCommandInvoked(sender:)), discoverabilityTitle: NSLocalizedString("GO_TO_PREV_CONVERSATION", comment: "")) ] }
//... some code ...
}
Page 117
// UIKeyCommand
class ConversationViewController: UITableViewController, UITextViewDelegate {
// ... some code ...
override var keyCommands: [UIKeyCommand]? { return [ // Command + Down arrow goes to the next conversation UIKeyCommand(input: UIKeyInputDownArrow, modifierFlags: .command, action: #selector(switchToConversationKeyCommandInvoked(sender:)), discoverabilityTitle: NSLocalizedString("GO_TO_NEXT_CONVERSATION", comment: "")), // Command + Up arrow goes to the previous conversation UIKeyCommand(input: UIKeyInputUpArrow, modifierFlags: .command, action: #selector(switchToConversationKeyCommandInvoked(sender:)), discoverabilityTitle: NSLocalizedString("GO_TO_PREV_CONVERSATION", comment: "")) ] }
//... some code ...
}
Page 118
// UIKeyCommand
class ConversationViewController: UITableViewController, UITextViewDelegate {
// ... some code ...
override var keyCommands: [UIKeyCommand]? { return [ // Command + Down arrow goes to the next conversation UIKeyCommand(input: UIKeyInputDownArrow, modifierFlags: .command, action: #selector(switchToConversationKeyCommandInvoked(sender:)), discoverabilityTitle: NSLocalizedString("GO_TO_NEXT_CONVERSATION", comment: "")), // Command + Up arrow goes to the previous conversation UIKeyCommand(input: UIKeyInputUpArrow, modifierFlags: .command, action: #selector(switchToConversationKeyCommandInvoked(sender:)), discoverabilityTitle: NSLocalizedString("GO_TO_PREV_CONVERSATION", comment: "")) ] }
//... some code ...
}
Page 119
// UIKeyCommand
class ConversationViewController: UITableViewController, UITextViewDelegate {
// ... some code ...
override var keyCommands: [UIKeyCommand]? { return [ // Command + Down arrow goes to the next conversation UIKeyCommand(input: UIKeyInputDownArrow, modifierFlags: .command, action: #selector(switchToConversationKeyCommandInvoked(sender:)), discoverabilityTitle: NSLocalizedString("GO_TO_NEXT_CONVERSATION", comment: "")), // Command + Up arrow goes to the previous conversation UIKeyCommand(input: UIKeyInputUpArrow, modifierFlags: .command, action: #selector(switchToConversationKeyCommandInvoked(sender:)), discoverabilityTitle: NSLocalizedString("GO_TO_PREV_CONVERSATION", comment: "")) ] }
//... some code ...
}
Page 121
•Multilingual •Being aware of context •The new “smarts” •Marked text •Hardware keyboard
Page 122
•Multilingual •Being aware of context •The new “smarts” •Marked text •Hardware keyboard
Page 123
James Magahern, iOS Keyboards
•Creating Custom Input Views •Accessible input for cats, dogs, and more
Page 127
Custom Accessible Input Views for Pets
Page 128
Custom Accessible Input Views for Pets
Our pets have no way to talk back
Page 129
Custom Accessible Input Views for Pets
Our pets have no way to talk back
Cats and dogs have trouble using QWERTY
Page 130
Custom Accessible Input Views for Pets
Our pets have no way to talk back
Cats and dogs have trouble using QWERTY
Limited vocabulary
Page 133
UIInputView
UIInputViewController
Page 134
UIInputView
UIInputViewController
Page 135
textDocumentProxy
UIInputView
UIInputViewController
Page 136
Providing a Custom Input View
class ConversationViewController: UITableViewController, UITextViewDelegate {
Page 137
Providing a Custom Input View
class ConversationViewController: UITableViewController, UITextViewDelegate {
private let customInputView = AnimalInputView()
override var canBecomeFirstResponder: Bool { return true }
Page 138
Providing a Custom Input View
class ConversationViewController: UITableViewController, UITextViewDelegate {
private let customInputView = AnimalInputView()
override var canBecomeFirstResponder: Bool { return true }
override var inputView: UIInputView? { // Return an instance of our custom UIInputView subclass return customInputView } // ... other code ... }
Page 139
Screenshot of the pet keyboard running in Messages
Page 140
James Magahern, iOS Keyboards
•Demo •Converting to a keyboard extension
Page 141
Converting to a Keyboard Extension
Page 142
Converting to a Keyboard Extension
Create a new target
Page 143
Converting to a Keyboard Extension
Create a new target
Set up your UIInputViewController subclass
Page 144
Converting to a Keyboard Extension
Create a new target
Set up your UIInputViewController subclass
Users can now enable keyboard from your settings bundle
Page 145
New APIs in iOS 11NEW
Page 146
New APIs in iOS 11
Selected text
NEW
Page 147
New APIs in iOS 11
Selected text
documentIdentifier handle
NEW
Page 148
New APIs in iOS 11
Selected text
documentIdentifier handle
Ability to query for full access
NEW
Page 149
Other Third Party Keyboard APIs
Page 150
Other Third Party Keyboard APIs
Incorporate the system input menu
Page 151
Other Third Party Keyboard APIs
Incorporate the system input menu
Personalization with the supplementary lexicon
Page 152
Other Third Party Keyboard APIs
Incorporate the system input menu
Personalization with the supplementary lexicon
Multilingual support
Page 153
Designing for User Trust
Page 154
Designing for User Trust
Privacy
Page 155
Designing for User Trust
Privacy
Enhance with user data
Page 156
Designing for User Trust
Privacy
Enhance with user data
Requesting full access
Page 157
Full Access and Privacy
Page 158
Full Access and Privacy
Value in not asking for full access
Page 159
Full Access and Privacy
Value in not asking for full access
Communicating with your main app
Page 160
Full Access and Privacy
Value in not asking for full access
Communicating with your main app
Networking
Page 161
Full Access and Privacy
Value in not asking for full access
Communicating with your main app
Networking
Current location
Page 162
Full Access and Privacy
Value in not asking for full access
Communicating with your main app
Networking
Current location
Address book
Page 163
Full Access and Privacy
Value in not asking for full access
Communicating with your main app
Networking
Current location
Address book
Keyboard needs to work without it
Page 164
Summary
Design your app with the keyboard in mind
Use advanced traits to enhance the user’s experience
Building keyboard extensions is a lot easier than you think
Page 165
More Informationhttps://developer.apple.com/wwdc17/242
Page 166
Related Sessions
Introducing Password AutoFill for Apps WWDC 2017
Localizing for Xcode 9 WWDC 2017
Increase Usage of Your App With Proactive Suggestions WWDC 2016
Internationalization Best Practices WWDC 2016
Mysteries of Auto Layout, Part 1 WWDC 2015
Page 167
Labs
Cocoa Touch and Haptics Lab Technology Lab C Fri 12:00PM–1:50PM