I'm trying to run Live Activities and Dynamic Island activities on my actual iPhone 15 Pro Max (Not the simulated iPhone). However, when I run the app, I get the error The operation couldn’t be completed. User has denied activities for this target. As you scroll, you'll see where I'm having the issue. What should I do?
import SwiftUI
import WidgetKit
import Foundation
import ActivityKit
struct HomeView: View {
@State private var currentTime = Date()
var body: some View {
NavigationView {
ScrollView {
VStack {
ZStack { // No need to specify alignment here for individual items
Image("TrexlerLibraryPicture")
.resizable()
.aspectRatio(contentMode: .fit)
VStack {
Text(libraryClosingText())
.foregroundColor(.white)
.padding([.top, .leading]) // Adds padding to the top and leading sides, moving the text towards the top left
.font(.title2)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)// Aligns text to the top leading edge
Spacer() // Pushes both texts to their respective edges
Text("Welcome Emanuel!")
.foregroundColor(.white)
.padding([.bottom, .leading]) // Adds padding to the bottom and leading edges
.font(.title)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomLeading) // Aligns to bottom leading
}
}
.navigationTitle("Home")
// LOOK HERE! IT'S THIS CODE!!!
}.onAppear() {
do {
_ = try LiveActivityManager.startActivity(timeRemaining: calculateTimeRemaining())
print("Hello, it made it ")
}
catch {
print(error
.localizedDescription)
}
}
.onReceive(Timer.publish(every: 60, on: .main, in: .common).autoconnect()) { _ in
// This block is executed every minute
self.currentTime = Date() // Update the current time
}
VStack {
HStack {
ServiceTiles(tile: ServiceTile(picture: "DeSalesLibraryE-Resources", title: "How to Guide"))
ServiceTiles(tile: ServiceTile(picture: "BookaStudyRoom", title: "Book a Study Room"))
}
}
Spacer()
VStack {
HStack {
ServiceTiles(tile: ServiceTile(picture: "LibraryBookTech", title: "Book Technology"))
ServiceTiles(tile: ServiceTile(picture: "library3dmodel", title: "Book 3D Anatomical Model"))
}
}
Spacer()
VStack {
HStack {
ServiceTiles(tile: ServiceTile(picture: "IntLoanArticleReqPicture", title: "Interlibrary Loan Article Request"))
ServiceTiles(tile: ServiceTile(picture: "IntLibLoanBookReqPicture", title: "Interlibrary Loan Book Request"))
}
}
Spacer()
VStack {
HStack {
NavigationLink(destination: ContactUsView()) {
ServiceTiles(tile: ServiceTile(picture: "ContactUs", title: "Contact Us"))
}
HStack {
NavigationLink(destination: LibraryStaffView()) {
ServiceTiles(tile: ServiceTile(picture: "LibraryStaffPicture", title: "Library Staff"))
}
}
}
}
}
}
}
func libraryClosingText() -> String {
let closingTime = Calendar.current.date(bySettingHour: 21, minute: 0, second: 0, of: currentTime) ?? Date()
let now = currentTime // Use the updated current time
// Format the closing time as a string
let formatter = DateFormatter()
formatter.timeStyle = .short
let closingTimeString = formatter.string(from: closingTime)
// Calculate the difference in minutes
let difference = Calendar.current.dateComponents([.minute], from: now, to: closingTime).minute ?? 0
if (difference < 0)
{
return "The Library is closed"
}
else
{
return "The Library closes at \(closingTimeString) today (In \(difference) Minutes)"
}
}
func calculateTimeRemaining() -> String {
// Implementation of your time calculation logic
// Placeholder example:
let closingTime = Calendar.current.date(bySettingHour: 21, minute: 0, second: 0, of: Date())!
let now = Date()
let remaining = Calendar.current.dateComponents([.minute], from: now, to: closingTime).minute ?? 0
if remaining <= 0 {
return "Closed"
} else {
return "\(remaining) minutes"
}
}
}
#Preview {
HomeView()
}
Here's the other files that might help
import Foundation
import ActivityKit
class LiveActivityManager {
@discardableResult
static func startActivity(timeRemaining: String) throws -> String {
var activity: Activity<ClosingTimeAttributes>?
let initialState = ClosingTimeAttributes.ContentState(timeRemaining: timeRemaining)
do {
activity = try Activity.request(attributes: ClosingTimeAttributes(), contentState: initialState, pushType: nil)
guard let id = activity?.id else { throw LiveActivityErrorType.failedToGetID }
return id // Ensure this returns a String representation of the ID
} catch {
throw error
}
}
static func listAllAttributes() -> [[String:String]] {
let sortedActivities = Activity<ClosingTimeAttributes>.activities.sorted { $0.id > $1.id }
return sortedActivities.map { ["timeRemaining": $0.contentState.timeRemaining] }
}
static func endAllActivities() async {
for activity in Activity<ClosingTimeAttributes>.activities {
await activity.end(dismissalPolicy: .immediate)
}
}
static func endActivity(_ id: String) async {
// Assuming 'id' is a String that represents a UUID, we need to find the corresponding Activity
// by matching its UUID string representation with 'id'
await Activity<ClosingTimeAttributes>.activities.first { $0.id == id }?.end(dismissalPolicy: .immediate)
}
static func updateActivity(id: String, timeRemaining: String) async {
// Here also, 'id' is a String. We match it against the uuidString representation of each Activity's UUID
let updatedContentState = ClosingTimeAttributes.ContentState(timeRemaining: timeRemaining)
let activity = Activity<ClosingTimeAttributes>.activities.first { $0.id == id }
await activity?.update(using: updatedContentState)
}
enum LiveActivityErrorType: Error {
case failedToGetID
}
}
import Foundation
import ActivityKit
struct ClosingTimeAttributes: ActivityAttributes {
public struct ContentState: Codable, Hashable {
var timeRemaining: String
}
}
ClosingTimeBundle
import WidgetKit
import SwiftUI
@main
struct ClosingTimeBundle: WidgetBundle {
var body: some Widget {
ClosingTime()
}
}
ClosingTime.swift
import WidgetKit
import SwiftUI
import Trexler_Library
struct ClosingTime: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: ClosingTimeAttributes.self ) {context in
VStack(alignment: .center) {
VStack(alignment: .center) {
HStack {
Image(systemName: "takeoutbag.and.cup.and.straw.fill")
.resizable().aspectRatio(contentMode: .fit)
.frame(width: 14, height: 14)
.foregroundColor(.yellow)
Spacer()
Text("~ \(context.state.timeRemaining)")
.font(.system(size: 14))
.bold()
}
.padding(.horizontal, 10)
VStack {
HStack {
Image(systemName: "figure.outdoor.cycle")
.resizable().aspectRatio(contentMode: .fit)
.frame(width: 44, height: 44)
.foregroundColor(.yellow)
VStack(spacing: 0) {
HStack {
Text("Your food is on delivery")
.font(.system(size: 20))
.bold()
Spacer()
}
}
}
.padding(.horizontal, 30)
}
}
HStack {
VStack(alignment: .leading) {
Text("From")
.font(.system(size: 8))
Text(context.state.timeRemaining)
.font(.system(size: 14))
.bold()
}
Spacer()
VStack(alignment: .trailing) {
Text("To")
.font(.system(size: 8))
Text(context.state.timeRemaining)
.font(.system(size: 14))
.bold()
}
}
.frame(height: 20)
.padding(.horizontal, 10)
HStack {
ProgressView(value: CGFloat((context.state.timeRemaining as NSString).floatValue), total: 100)
.tint(.yellow)
.background(.white)
}
.padding(.horizontal, 10)
}
.frame(height: 160)
.background(.black)
} dynamicIsland: { context in
DynamicIsland {
DynamicIslandExpandedRegion(.center) {
VStack {
HStack {
Image(systemName: "takeoutbag.and.cup.and.straw.fill")
.resizable().aspectRatio(contentMode: .fit)
.frame(width: 14, height: 14)
.foregroundColor(.yellow)
Spacer()
Text("~ \(context.state.timeRemaining)")
.font(.system(size: 14))
.bold()
}
.padding(.horizontal, 10)
VStack {
HStack {
Image(systemName: "figure.outdoor.cycle")
.resizable().aspectRatio(contentMode: .fit)
.frame(width: 44, height: 44)
.foregroundColor(.yellow)
VStack(spacing: 0) {
HStack {
Text("Your food is on delivery")
.font(.system(size: 20))
.bold()
Spacer()
}
HStack {
Button(action: {}, label: {
HStack {
Image(systemName: "phone.fill")
.resizable().aspectRatio(contentMode: .fit)
.frame(width: 14, height: 14)
.foregroundColor(.white)
Text("Call")
.font(.system(size: 10))
.foregroundStyle(.white)
}
})
.buttonBorderShape(.capsule)
Spacer()
}
}
}.padding(.horizontal, 30)
}
}
}
DynamicIslandExpandedRegion(.bottom) {
HStack {
VStack(alignment: .leading) {
Text("From")
.font(.system(size: 8))
Text(context.state.timeRemaining)
.font(.system(size: 14))
.bold()
}
Spacer()
VStack(alignment: .leading) {
Text("To")
.font(.system(size: 8))
Text(context.state.timeRemaining)
.font(.system(size: 14))
.bold()
}
}
.frame(height: 20)
.padding(.horizontal, 10)
}
} compactLeading: {
Image(systemName: "clock")
.resizable().aspectRatio(contentMode: .fit)
.frame(width: 14, height: 14)
.foregroundColor(.yellow)
} compactTrailing: {
Text(context.state.timeRemaining)
} minimal: {
Image(systemName: "takeoutbag.and.cup.and.straw.fill")
.resizable().aspectRatio(contentMode: .fit)
.frame(width: 14, height: 14)
.foregroundColor(.yellow)
}
}
}
}