Как показать экранное время для iOS?IOS

Программируем под IOS
Ответить
Anonymous
 Как показать экранное время для iOS?

Сообщение Anonymous »

Я знаю, что мы не можем получить доступ к отчету о времени использования экрана в виде необработанных данных, но мы можем показать его на экране. Я пытаюсь это сделать, но получаю следующие ошибки:
LaunchServices: store (null) or url (null) was nil: Error Domain=NSOSStatusErrorDomain Code=-54 "process may not map database" UserInfo={NSDebugDescription=process may not map database, _LSLine=72, _LSFunction=_LSServer_GetServerStoreForConnectionWithCompletionHandler}
Attempt to map database failed: permission was denied. This attempt will not be retried.
Failed to initialize client context with error Error Domain=NSOSStatusErrorDomain Code=-54 "process may not map database" UserInfo={NSDebugDescription=process may not map database, _LSLine=72, _LSFunction=_LSServer_GetServerStoreForConnectionWithCompletionHandler}

Все настройки я выполнил. У меня есть только сомнения по поводу постановки новой цели, а я этого не делал. Может ли кто-нибудь подсказать, как это исправить, или необходимо добавить цель и, если да, то как это сделать?
Мой код:
import SwiftUI
import DeviceActivity
import FamilyControls

@available(iOS 16.0, *)
struct ScreenTimeInputView: View {
let onSubmit: ([String: Any]) -> Void
let onCancel: () -> Void

// MARK: - Screen Time
@State private var selection = FamilyActivitySelection()
@State private var filter = DeviceActivityFilter()
@State private var context: DeviceActivityReport.Context =
.init(rawValue: "Total Activity")

enum Step {
case picker
case report
}

@State private var step: Step = .picker

// MARK: - Your existing state
@State private var rows: [CategoryUsageRow] = []
@State private var inputs: [String: UserCategoryInput] = [:]

var body: some View {
NavigationView {
VStack(spacing: 0) {

// ===== TOP =====
VStack(alignment: .leading, spacing: 12) {
Text("Screen Time (by categories)")
.font(.title3).bold()

if rows.isEmpty {
Text("Loading…")
.foregroundColor(.secondary)

} else {
switch step {

case .picker:
FamilyActivityPicker(selection: $selection)

Button("Save selection") {
saveSelectionAndBuildReport()
}
.buttonStyle(.borderedProminent)

case .report:
DeviceActivityReport(context, filter: filter)
}
}
}
.padding()
.frame(maxWidth: .infinity)
.frame(height: UIScreen.main.bounds.height * 0.45)

Divider()

// ===== BOTTOM (unchanged) =====
VStack(alignment: .leading, spacing: 12) {
Text("Enter your values")
.font(.title3).bold()

if rows.isEmpty {
Text("No categories yet")
.foregroundColor(.secondary)
} else {
ScrollView {
VStack(spacing: 12) {
ForEach(rows) { r in
CategoryInputRow(
title: r.categoryTitle,
input: bindingForCategory(r.categoryId)
)
Divider()
}
}
}
}

Button(action: sendToFlutter) {
Text("Send to Flutter")
.frame(maxWidth: .infinity)
}
.buttonStyle(.borderedProminent)
}
.padding()
.frame(maxWidth: .infinity)
.frame(height: UIScreen.main.bounds.height * 0.45)
}
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .topBarLeading) {
Button("Close") { onCancel() }
}
}
.onAppear {
loadRealScreenTimeCategories()
}
}
}

// MARK: - Core logic

private func saveSelectionAndBuildReport() {
Task {
do {
try await AuthorizationCenter.shared
.requestAuthorization(for: .individual)

let startOfDay = Calendar.current.startOfDay(for: Date())
let endOfDay = Calendar.current.date(
byAdding: .day,
value: 1,
to: startOfDay
)!

let interval = DateInterval(start: startOfDay, end: endOfDay)

await MainActor.run {
filter = DeviceActivityFilter(
segment: .daily(during: interval),
users: .all,
devices: .all,
applications: selection.applicationTokens,
categories: selection.categoryTokens
)

step = .report
}

} catch {
print("❌ Screen Time authorization failed:", error)
}
}
}

// MARK: - Bindings

private func bindingForCategory(_ id: String) -> Binding {
if inputs[id] == nil {
inputs[id] = UserCategoryInput()
}
return Binding(
get: { inputs[id] ?? UserCategoryInput() },
set: { inputs[id] = $0 }
)
}

// MARK: - Demo data
private func loadRealScreenTimeCategories() {
let demo: [CategoryUsageRow] = [
.init(categoryId: "social", categoryTitle: "Social", realMinutes: 132),
.init(categoryId: "entertainment", categoryTitle: "Entertainment", realMinutes: 87),
.init(categoryId: "productivity", categoryTitle: "Productivity", realMinutes: 54),
.init(categoryId: "games", categoryTitle: "Games", realMinutes: 12),
.init(categoryId: "education", categoryTitle: "Education", realMinutes: 9),
.init(categoryId: "utilities", categoryTitle: "Utilities", realMinutes: 6),
.init(categoryId: "other", categoryTitle: "Other", realMinutes: 3),
]

rows = demo
for r in demo where inputs[r.categoryId] == nil {
inputs[r.categoryId] = UserCategoryInput()
}
}

// MARK: - Flutter bridge
private func sendToFlutter() {
let categories: [[String: Any]] = rows.map { r in
let inp = inputs[r.categoryId] ?? UserCategoryInput()
return [
"categoryId": r.categoryId,
"categoryTitle": r.categoryTitle,
"realMinutes": r.realMinutes,
"inputMinutesText": inp.minutesText
]
}

let payload: [String: Any] = [
"timestamp": Date().timeIntervalSince1970,
"categories": categories
]

onSubmit(payload)
}
}


Подробнее здесь: https://stackoverflow.com/questions/798 ... me-for-ios
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «IOS»