You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift实现8-16时段内步数达标条件化后台通知的技术问询

How to Implement Conditional Step Count Notifications (Background Execution)

Great question! Let's walk through exactly how to build this feature—from keeping your app running in the background to triggering those targeted notifications when users fall short of their step goal. Here's a step-by-step breakdown:

1. Set Up Background Task Scheduling

First, you need a reliable way to run periodic checks even when the app is in the background. The approach varies slightly by platform, but both have robust tools for this:

Android: Use WorkManager

WorkManager is Google's recommended tool for deferrable, periodic tasks that need to run reliably—even if the app is closed or the device restarts.

  • Create a Worker subclass that handles the step check and notification logic.
  • Schedule a periodic work request that runs every 30 minutes. We’ll add a time filter inside the worker to only execute checks between 8:00-16:00 (more on that later).
  • Example code to start the task when the user taps "Start":
val periodicRequest = PeriodicWorkRequestBuilder<StepCheckWorker>(30, TimeUnit.MINUTES)
    .setConstraints(Constraints.Builder()
        .setRequiredNetworkType(NetworkType.NOT_REQUIRED) // No network needed for step checks
        .build())
    .build()

WorkManager.getInstance(context).enqueueUniquePeriodicWork(
    "StepCheckTask",
    ExistingPeriodicWorkPolicy.REPLACE,
    periodicRequest
)
  • To stop the task (if you add a "Stop" button):
WorkManager.getInstance(context).cancelUniqueWork("StepCheckTask")

iOS: Use Background Tasks Framework

For iOS, use BGAppRefreshTask (lightweight, ideal for step checks) and enable the "Background App Refresh" capability in your Xcode project.

  • Register the task on app launch:
BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.yourapp.stepcheck", using: nil) { task in
    self.handleStepCheckTask(task: task as! BGAppRefreshTask)
}
  • Schedule the task when the user taps "Start":
let request = BGAppRefreshTaskRequest(identifier: "com.yourapp.stepcheck")
request.earliestBeginDate = Date().addingTimeInterval(30*60) // First run after 30 mins
do {
    try BGTaskScheduler.shared.submit(request)
} catch {
    print("Could not submit task: \(error)")
}
  • Inside the task handler, reschedule the next check after completing the current one to maintain the 30-minute interval.

2. Add Time Window Validation

Even with a 30-minute repeat schedule, we only want to execute checks between 8:00 AM and 4:00 PM. Add this check at the start of your background task:

Example Time Check Logic

// Android (Kotlin)
val currentHour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY)
if (currentHour < 8 || currentHour >= 16) {
    // Exit early—outside the target window
    Result.success()
    return
}
// iOS (Swift)
let currentHour = Calendar.current.component(.hour, from: Date())
if currentHour < 8 || currentHour >= 16 {
    // Exit early and reschedule for the next valid window
    task.setTaskCompleted(success: true)
    rescheduleStepCheckTask()
    return
}

3. Fetch Step Count Data

Next, retrieve the user's step count for the most recent 30-minute window. This requires requesting the necessary permissions first:

Android: Use Google Fit

  • Request the ACTIVITY_RECOGNITION permission in your manifest and at runtime.
  • Query steps from the last 30 minutes using Google Fit's History API:
val endTime = Calendar.getInstance().timeInMillis
val startTime = endTime - (30 * 60 * 1000) // 30 mins ago

val readRequest = DataReadRequest.Builder()
    .aggregate(DataType.TYPE_STEP_COUNT_DELTA, DataType.AGGREGATE_STEP_COUNT_DELTA)
    .bucketByTime(30, TimeUnit.MINUTES)
    .setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
    .build()

// Execute request and get total steps
val dataResult = Fitness.getHistoryClient(context, GoogleSignIn.getLastSignedInAccount(context)!!)
    .readData(readRequest)
    .await()

iOS: Use HealthKit

  • Enable the HealthKit capability and request read permission for HKObjectType.quantityType(forIdentifier: .stepCount).
  • Query steps from the last 30 minutes:
let healthStore = HKHealthStore()
let stepType = HKObjectType.quantityType(forIdentifier: .stepCount)!
let endDate = Date()
let startDate = endDate.addingTimeInterval(-30*60)

let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: .strictStartDate)
let query = HKStatisticsQuery(quantityType: stepType, quantitySamplePredicate: predicate, options: .cumulativeSum) { _, result, error in
    guard let result = result, let sum = result.sumQuantity() else { return }
    let steps = sum.doubleValue(for: HKUnit.count())
    // Handle step count here
}
healthStore.execute(query)

4. Trigger Notifications When Steps Are Too Low

Once you confirm the user has less than 200 steps in the 30-minute window, send a local notification:

Android: Create and Show Notification

  • Request the POST_NOTIFICATIONS permission (required for Android 13+).
  • Build and display the notification:
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

// Create notification channel (required for Android 8.0+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    val channel = NotificationChannel(
        "step_reminder",
        "Step Reminders",
        NotificationManager.IMPORTANCE_DEFAULT
    )
    notificationManager.createNotificationChannel(channel)
}

val notification = NotificationCompat.Builder(context, "step_reminder")
    .setContentTitle("Time to Move!")
    .setContentText("You've taken less than 200 steps in the last 30 minutes—get up and walk!")
    .setSmallIcon(R.drawable.ic_walk)
    .setPriority(NotificationCompat.PRIORITY_DEFAULT)
    .build()

notificationManager.notify(1, notification)

iOS: Schedule Local Notification

  • Request user permission to send notifications first.
  • Build and present the notification:
let content = UNMutableNotificationContent()
content.title = "Time to Move!"
content.body = "You've taken less than 200 steps in the last 30 minutes—let's get walking!"
content.sound = UNNotificationSound.default

let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil)
UNUserNotificationCenter.current().add(request) { error in
    if let error = error {
        print("Error sending notification: \(error)")
    }
}

Key Considerations

  • Battery Optimization: Both platforms have battery-saving features that might delay background tasks. On Android, ask users to exclude your app from battery optimization. On iOS, keep tasks efficient to avoid being throttled.
  • Permission Handling: Always handle cases where users deny permissions (e.g., show a friendly message explaining why the permission is needed).
  • Edge Cases: If the device is turned off during a check, WorkManager (Android) will retry when the device restarts. On iOS, the task will reschedule automatically.

内容的提问来源于stack exchange,提问作者Andrea

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:12:19