A little basketball game simulator which generates some mock data to show how that live data can be displayed with live activities on the lock screen and in the dynamic island.
- Functionality
- Definitions
- Tech Stack
- Frameworks
- Device and OS Compatibility
- Screenshots
- Architecture
- How does it work?
- Learnings
- Contribution Guidelines
- Code Comments
- Pull Requests
- References
- Credits
This App shows Live Activity (live data updates):
- On the lock screen and on devices that don't support the Dynamic Island, a banner on top of the screen.
- in the compact version of the dynamic island
- in the expanded version of the dynamic island Dynamic Island: On devices that support the Dynamic Island (see list below), the App displays Live Activities on the leading and trailing side of the TrueDepth camera.
- LA: Live Activity
- LAs: Live Activities
- DI: Dynamic Island
- Golden State Warriors: is the home team
- Chicago Bulls: is the guest team.
- Xcode 14.2
- Swift 5.7.2
- SwiftUI
- WidgetKit
- ActivityKit
LAs are iPhone only.
- For LA: iPhone with iOS 16.1
- For DI: iPhone 14 Pro/Pro Max with iOS 16.1
App View | Banner iPhone 14 | Banner iPhone 14 Pro |
---|---|---|
LADI iPhone14Pro | LADI expanded iPhone14Pro |
---|---|
The App Architecture is built using the following patterns:
I am using the Model-View architectural pattern in order that the GameView can observe/listen to state changes in the GameModel and rerender its UI accordingly.
I am using the following design patterns to solve common challenges:
- Delegation Pattern: We know the Delegate and Protocol Pattern best from UIKit. Here we use it as 1to1 communication pattern in order that the GameModel class (as the delegate) can communicate with the GameSimulator class.
- By pressing the Start Game Simulation, the GameSimulator "factory" spits out a new GameState every 2 seconds. It is restricted to be started only once.
- By pressing Start Live Activity, the Live Activity can be started. It is restricted to be started only once.
- The Live Activity updates while the App is running in the background. This is only possible because the background mode 'Audio, AirPlay,...' is enabled.
- The GameView and the Live Activity updates with every (new) GameState change
- The GameModel is (the glue) between the GameView and the GameSimulator
- The GameSimulator stops automatically after 120 ball possessions in total
- Apple doc: Displaying live data
- Live activities can live for up to 8 hours at max.
- Completed (final state) Live Activity will stay on the Lock Screen for 4 hours.
- Live Activity has to be launched while the App is in the foreground.
- Live Activity can be updated while the App is running in the background.
- Live Activities are not Widgets but we need WidgetKit to build them with Widget Extension.
- It is highly likely that one is going to have also a Widget in combination with Live Activities.
- Live Activity vs Widget: a Widget can update itself, as a LA have to be updated from within the App.
- As soon you create a Widget Extension including LA, Xcode will generate some boilerplate code for you.
- When more than one LA is active the system chooses which LAs are visible and displays two using the minimal presentation
- IMPORTANT: In the App Target in the Info.plist we have to add the Key:
Supports Live Activities
and set its value toTrue
. - Use the new (iOS 16.2 ) struct
ActivityContent<State>
to describe the current state and config of a LA. - UI Banner on the Always-On display (iPhone 14 only) doesn't show any animations
- UI Banner on the regular lock screen shows animations
- Configuring background execution modes
- Remote Push Notifications
- Background Strategies
- Background processing There are different ways of how one can update a Live Activity while the App is running in the background. But be aware of that you have to have good reasons to BE ALLOWED of running your App in the background and doing updates, otherwise the AppStore reviewers will reject the App! Apple does not want that every App can just do stuff in the background and drain battery and impact device performance.
- AnyObject and Any are used for type erasure
- AnyObject, Any, and any: When to use which?
- All classes, class types, or class-only protocols can use
AnyObject
as their concrete type. - If possible try to use concrete types as it is more readable to your friends.
- By using it as our destination, we always need to cast and consider casting failures using the default implementation.
- Try to use concrete protocol instead, see here
- An instance of any type including function types can use
Any
. Any
is even more flexible thanAnyObject
by allowing you to cast instances of any type, but it makes code harder to predict and optimize for performance compared to using concrete types.- Dynamic memory is required to make this possible, taking away the possibility for the compiler to optimize this piece of code.
- Architecture vs Architectural Patterns vs Design Patterns
- Architecture: An architecture shows how we organize our code, or how the system will look like from 10000 meters above from the highest level of abstraction of our system design.
- Architecture: Software architecture refers to the fundamental structure underlying a system. It is the general conceptual design that informs the development and maintenance of software and defines what it can β and cannot β do.
- Architecture: A poor architecture can make changes to the software much harder than they need to be.
- Architectural Patterns: Are broad solutions how we can implement the chosen architecture.
- Design Patterns: Are accumulative best practices and experiences that developers used over the years to solve general problems.
- GitHub: We can use one of the following keywords to close an issue via a commit message:
close, closes, closed, fix, fixes, fixed, resolve, resolves, resolved
. The message MUST contain a string matching the following pattern:KEYWORD #ISSUENO
. For example:Closes/closes #1
or multiple issuesCloses #1, Resolves #2, Fixes #3
. credits
Follow the Arrange, Act and Assert Pattern for Unit Testing.
- Arrange inputs and targets:
- Does the test require any objects or special settings?
- Does it need to prep a database?
- Does it need to log into a web app?
- Act on target behavior:
- This step should call the function/method/API, or whatever needs to be tested.
- It should focus on the target behavior.
- Assert expected outcomes:
- This step should elicit some sort of response.
- Then the response should be judged for correctness.
Follow the Given-When-Then style to write the UI-Tests from a user perspective.
- Include "self documenting code."
- Additionally, include descriptive comments in order to improve readability. -Aim for comments that allow other programmers to understand your code without having to work through your entire classes/methods.
- Pull requests should be kept to a reasonable size.
- Pull requests should be descriptive, answer the following questions:
- What was the problem?
- What did you do to improve it?
- How do you know it is a working solution?/What tests did you do?
- Why do you believe this is the right solution?
- Why is this the best solution for the problem?
- Review/proofread your pull request before submission. Following this guide.
ππ½ Sean Allen
- CMD B: build the project
- CMD R: build and run the App in the simulator
- CMD SHIFT K: clean build folder
- CMD SHIFT O: open quick search
- CMD SHIFT J: highlight the selected open file in the navigator
- CMD SHIFT L: open up the library (Snippets, Media, Colors, SF Symbols)
Made with a π Simon Berner