ARTICLE AD BOX
I know that we can't access the screen time report as raw data, but we can show it on screen. I'm trying to do this, but I am getting these errors:
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}I did all set ups. I only have doubts about the set up of a new target, and I didn't do it. Can someone suggest how to fix it, or is it necessary to add a target and, if so, how should it be done?
My code:
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<UserCategoryInput> { 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) } }