WWDC19 - Hipo/mobile-team-guidelines GitHub Wiki
Some key points for sessions in WWDC 2019.
When to Consider iPad Apps for Mac:
- Make iPad app available on the Mac
- Bring older Mac app to feature parity with iPad app
- Replace Mac app built on non-native technology
Not All Apps Are Candidates:
- iPhone-only apps
- Apps that are built around mobile features
Things You Get For Free:
- Default Menu Bar
- Window management
- Dark Mode
- Scroll Bars
- Settings
- Touch Bar Default Support
- Copy and paste
- Drag and drop
- Application lifecycle
Overview of API Differences
- APIs that have identical behavior
- APIs that are mapped to macOS functionality
- APIs that are unavailable
Mouse and Touch Events
- Hover
- Single-finger touch tracking
- Standard gestures
- Custom multi-touch code
Unavailable APIs
- Deprecated frameworks
- iOS-specific frameworks
- Hardware-specific frameworks
- Framework differences
iOS Specific Frameworks: ClassKit, HealthKit, HomeKit
Hardware Specific Frameworks: ARKit, CarPlay, VisionKit
Framework Differences: Core Location, Core Motion, Core Telephony, Core NFC, Core Bluetooth
API Availability: @unavailable(UIKitForMac), @available(macOS 10.10, UIKitForMac 13.0)
Conditionalizing Code: #if !targetEnvironment(UIKitForMac)
-
Overview
- URLs that represent your content both on the Web and in your app
- Available in your iOS, tvOS, and macOS apps
- Securely associated between your app and your website
- Recommended over custom URL schemes
-
Configuring Your Web Server
-
Install a valid HTTPS certificate
-
Add your apple-app-site-association file
- URLs and pattern-matching are ASCII
- Reduce download size when internationalizing
{ "applinks": { "apps": [], "details": [ { "appID": "ABCDE12345.com.example.app", "paths": [ "/path/*/filename" ] } } } ]
"appIDs": [ "ABCDE12345.com.example.lunch" ], "components": [ { "/": "/*/order/" }
-
-
Configuring Your App
<array> <string>applinks:www.example.com</string> <string>applinks:*.example.com</string> <string>applinks:xn--fhqz97e.example.xn--fiqs8s</string><!--上海海.example.中国--> </array> func application( _ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([ UserActivityRestoring]?) -> Void ) -> Bool- More specific subdomains have higher priority
-
Best Practices
- Fail gracefully
- Use the Smart App Banner
- Feedback is appreciated
-
Sign In with Apple
- Easier than passwords
- secure, verified accounts
- WatchOS, iPad, iOS, macOS
-
Password-based authentication
-
Autofill actions
import AuthenticationServices
let controller = ASAuthorizationController(authorizationRequests: [ ASAuthorizationPasswordProvider().createRequest() ])
controller.delegate = self
controller.presentationContextProvider = self
controller.performRequests()
-
-
Warnings for weak passwords
- Strong password option. Directs to change password section on app and autofills strong password.
- https://example.com/.well-known/change-password
-
OAuth sign-in
- More private sign-in
- Supporting multiple windows
- Migrating from SFAuthenticationSession
-
Overview
- Fast, easy account setup and sign in
- Prefilled information like name and email. User can choice which email to be shared.
- App receives id, verified email and full name. Two factor authenticated account.
- Applies in users other devices when they try to sign in again.
- Single tap, no filling.
- Hide my email options provides a new email address that routes to users email address. It is linked to verified email. Apple does not retain any messages.
- It is cross platform. iOS, macOS, watchOS, tvOS. Javascript api enables use in android, windows and web.
-
Integrating with your app
- Button → Authorization → Verification → Handling Changes
- ASAuthorizationAppleIDButton: Different styles are available
- Button → Authorization → Verification → Handling Changes
-
Authorization
let request = ASAuthorizationAppleIDProvider().createRequest() request.requestedScopes = [.fullName, .email] let controller = ASAuthorizationController(authorizationRequests: [request]) controller.delegate = self controller.presentationContextProvider = self controller.performRequests() -
Verification
func authorizationController( controller _: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization ) { if let credential = authorization.credential as? ASAuthorizationAppleIDCredential { // Create account in your system } } // didCompleteWithError for error checks `Received Data: User ID, Verification data, Account information
- Handling Session Changes:
- Stop using Apple ID with app
- Sign out of the device
- One tap sign in for existing accounts
- Integrates with iCloud Keychain passwords
- Handling Session Changes:
-
Cross-platform
- Simple browser-based login
- Similar to native API
- Native experience when using Safari
-
Best practices
- Only require account setup when necessary
- Only collect data that is required
- Respect email address that user chose to share
- Check for existing accounts on app startup
- Use real user indicator for best new account experience
- Always use the Button API
- Implement across all platforms
-
There are system colors that supports dark mode. systemBackground, secondarySystemBackground, tertiarySystemBackground Title Subtitle Placeholder Disabled
-
Four level of text colors; Primary Secondary Tertiary Quaternary
-
Color assets catalog makes things easier for supporting dark mode. It is enough to add different colors for different modes dark, light, etc... Then this colors changes automatically when mode is changed.
-
Also we can specify different images for different modes from
Image Assets CatalogfromAppearancesdrop down. -
Custom dynamic colors are also possible using
UITraitCollection. -
Layout is the best time to use traits; UIViewController.viewWillLayoutSubviews() UIView.layoutSubviews() UIViewController.viewDidLayoutSubviews()
-
overrideUserInterfaceStlyeis suitable to use if we need take control of color changes from system. -
Added new Status Bar style; .darkContent
-
Added new UIActivityIndicatorView styles; .medium, .large
-
Attributed strings must have a dynamic color set to .foregroundColor attribute to support dark mode.
- Data source and the UI state must always agree.
- Current approach is error prone. There is no centralized logic.
- No more use of
performBatchUpdates(). (Crashing, complexity) - New method apply() (Simple, automatic diffing)
- Single thruth for UI state
- Unique ids for sections/items. No more IndexPaths.
+apply() is safe to call from a background queue.
But always call exclusively from main or background queue.
Otherwise frame work will assert.