/// Key technologies ActivityKit / MVVM / UserNotifications / PostgreSQL / Structured Concurrency / SwiftUI / UIBezierPath / Vapor / Vapor_Queues / XCTest
I published the app to the App Store!🎉
App Store Links
There are various apps to discourage smartphone use. Some of them discourage smartphone use by giving rewards to users such as character items, based on the amount of time they do not use their phones. But I have had the experience of that backfired because I was looking forward to the rewards. I thought, for some people including me, the inclusion of game elements may in fact cause people rather to be distracted by their phones. And I wondered, instead of rewarding people, If I gave them a punishment based on use time, people would refrain from using their phones.
In this app, I feature a creepy eye on lock screen, blood vessels of which bleed according to smartphone usage during bedtime. With Live Activities that was introduced in iOS 16, the application can reflect smartphone usage to the eye icon in real time manner. In addition, I implemented summary report functionality so that users can identify trends about their smartphone usage time. This will help them to understand when they use their phones too much, how tired their eyes feel when they use them too much, etc.
Once you set the time, you will receive notification at the bedtime.
When you tap the notification, time recording starts. After the moment, every time you unlock smartphone (and open the application), the app records the time you start using smartphone.
Before you stop using smartphone, you will tap sleep button, which will records the timing you will go to sleep.
At the same timing as 3., Live Activity is triggered and you will see an eye on the lock screen, which will bloodshoot as you spend time using smartphone.
With default specification, Live Activity is terminated 8 hours after it is triggered. (see Apple documentation).
Its state properties are thrown away as well. With this behaviour, when you get up in the morning, you will see an icon saying "you spent 0 min 0 sec" without some devices like the image below.
I solved this problem using silent remote notification and Vapor/Queues.
The idea is to send a signal 5 minutes before Live Activity is forced to terminated, and thereby retain the eye icon state for next morning.
While user is sleeping, application will receive a silent notification in the background and use a method to terminate Live Activity in a notification delegate method. This will prevent the lock screen from being reset the next morning.
I used following technologies to achieve this.
With Vapor/Queues, you can set a task regulary or at specific timing.
struct ActivityInfo: Codable { let pushToken: String } struct BackgroundLiveActivitiesUpdateJob: AsyncJob { typealias Payload = ActivityInfo func dequeue(_ context: Queues.QueueContext, _ payload: ActivityInfo) async throws { // this method will send silent remote notification to a client try await APNSManager.sendBackgroundNotification(token: payload.pushToken, client: APNSManager.getClient(), activityInfo: payload) } }
// in configure method, register Job let bgLiveActivityJob = BackgroundLiveActivitiesUpdateJob() app.queues.add(bgLiveActivityJob)
// in configure method, run worker try app.queues.startInProcessJobs(on: .default)
// inside route handler function try await req.queue.dispatch( BackgroundLiveActivitiesUpdateJob.self, activityInfo, delayUntil: dispatchDate )
You can receive remote notification using
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) async -> UIBackgroundFetchResult
Inside the delegate, I ended the ongoing Live Activity.
This will keep the eye icon up-to-date even 8 hours after its start.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) async -> UIBackgroundFetchResult { await Activities.terminateActivity() return .noData // always return no data (regardless termination succeeds or not) }