1

I am following along the tutorial at https://www.youtube.com/watch?v=AUOoalBwxos

However, the ActivityKit API used to start and end the live activity have been deprecated in iOS 16.2.

I have figured out how to update the start method to the new API by replacing activity = try? Activity<TimeTrackingAttributes>.request(attributes: attributes, contentState: state, pushType: nil) with:

let activityContent = ActivityContent(state: state, staleDate: Calendar.current.date(byAdding: .hour, value: 3, to: Date())!)

do {
    let myActivity = try Activity<TimeTrackingAttributes>.request(attributes: attributes, content: activityContent, pushType: nil)
    print("Requested MyActivity live activity. ID: \(myActivity.id)")
} catch let error {
    print("Error requesting live activity: \(error.localizedDescription)")
}

However, I am having trouble ending the live activity started with the new API. With the old, deprecated API, I could start and end my live activity. But when I use the old end API, I get the message end(using:dismissalPolicy:)' was deprecated in iOS 16.2: Use end(content:dismissalPolicy:) instead. The old ‘end’ API does not end the activity started with the new 'start' API.

Would anyone be able to offer some advice for how to end a live activity with the new ActivityKit API in iOS 16.2?

Documentation for the new API: https://developer.apple.com/documentation/activitykit/activity/end(_:dismissalpolicy:)

Documentation for the old API: https://developer.apple.com/documentation/activitykit/activity/end(using:dismissalpolicy:)

The full code for ContentView:

import SwiftUI
import ActivityKit

struct ContentView: View {
    @State private var isTrackingTime: Bool = false
    
    @State private var startTime: Date? = nil
    
    @State private var activity: Activity<TimeTrackingAttributes>? = nil;
    
    var body: some View {
        NavigationView {
            VStack {
                if let startTime {
                    Text(startTime, style: .relative)
                }
                
                Button {
                    isTrackingTime.toggle()
                    
                    if isTrackingTime {
                        startTime = .now
                        
                        // start the live activity
                        let attributes = TimeTrackingAttributes()
                        guard let startTime else { return }
                        let state = TimeTrackingAttributes.ContentState(startTime: startTime)
                        
                        activity = try? Activity<TimeTrackingAttributes>.request(attributes: attributes, contentState: state, pushType: nil)
                        
                        // TODO: how to match the new 'start' API to the new 'end' API ?
//                        let activityContent = ActivityContent(state: state, staleDate: Calendar.current.date(byAdding: .hour, value: 3, to: Date())!)
//                        do {
//                            let myActivity = try Activity<TimeTrackingAttributes>.request(attributes: attributes, content: activityContent, pushType: nil)
//                            print("Requested MyActivity live activity. ID: \(myActivity.id)")
//                        } catch let error {
//                            print("Error requesting live activity: \(error.localizedDescription)")
//                        }
                    } else {
                        // end the live activity
                        guard let startTime else { return }
                        let state = TimeTrackingAttributes.ContentState(startTime: startTime)
                        
                        // TODO: how to match the new 'end' API to the new 'start' API ?
                        Task {
                             await activity?.end(using: state, dismissalPolicy: .immediate)
                        }
                        
                        self.startTime = nil
                    }
                } label: {
                    Text(isTrackingTime ? "STOP" : "START")
                        .fontWeight(.light)
                        .foregroundColor(.white)
                        .frame(width: 200, height: 200)
                        .background(Circle().fill(isTrackingTime ? .red : .green))
                }
                .navigationTitle("Basic Time Tracker")
            }
        }
    }
}

The full code for TimeTrackingAttributes:

import Foundation
import ActivityKit

struct TimeTrackingAttributes: ActivityAttributes {
    public typealias TimeTrackingStatus = ContentState
    
    public struct ContentState: Codable, Hashable {
        var startTime: Date
    }
}
  • Isn't just the parameter name dropped? `await activity?.end(state, dismissalPolicy: .immediate)` – fruitcoder Feb 08 '23 at 15:26
  • 1
    Thank you for the response. When I do that (`await activity?.end(state, dismissalPolicy: .immediate)`), I get the error: `Cannot convert value of type 'TimeTrackingAttributes.ContentState' to expected argument type 'ActivityContent?'` – silentfilozofer Feb 09 '23 at 12:30
  • 1
    Further, if I pass in an ActivityContent created from that state (`let activityContent = ActivityContent(state: state, staleDate: nil)`), the end does not end the live activity even I press the "stop" button (unlike earlier). – silentfilozofer Feb 09 '23 at 12:32

1 Answers1

0

It worked for me:

func stopLiveActivity() {
    let state = TimeTrackingAttributes.TimeTrackingStatus(endTime: .now) 

    Task {
        let content = ActivityContent(state: state, staleDate: .now)
        await activity?.end(content, dismissalPolicy: .immediate)
    }
}

This code ends the activity immediately by creating content with staleDate: .now and dismissalPolicy: .immedite

  • Thank you for contributing to the Stack Overflow community. This may be a correct answer, but it’d be really useful to provide additional explanation of your code so developers can understand your reasoning. This is especially useful for new developers who aren’t as familiar with the syntax or struggling to understand the concepts. **Would you kindly [edit] your answer to include additional details for the benefit of the community?** – Jeremy Caney Jul 07 '23 at 18:01