I have a UIKit app (it perfectly handles and does APNS), I add an ActivityAttributes
and thus launch an activity.
So that's TestAttributes
;
notice that is used in the Widget TestWidg
;
and is used as the content in the Activity#request
.
Gotta get that "in" the target somehow so I put it in a TestWidgBundle
, all code below.
This all runs perfectly and when you lactivities.test()
. You get a token et al,
** check true
** activity ID woot 0384DF90-795E-487A-ADAC-185203E25F22
** traverse ok
** token woot gPk5RJkfAi/dCrZG4GVc7/4E48uQ...Po3vz+9jKcD4C4qjg+M=
Naturally I
etc etc.
BUT the live activity never appears.
Surely, I'm doing something conceptually wrong in that I have not actually put the Widget / WidgetBundle in the project - ???
ie the project in question has only one Target, the main iOS build.
I have run other projects (eg test projects from the web) on my phones, sims, which clearly show Live Activities / Happy Island appearing correctly.
Does struct TestWidgBundle: WidgetBundle
need something more than it's declaration to add the new target, or ?
import UIKit
import ActivityKit
import WidgetKit
import SwiftUI
/// singleton for Live Activity Feat. "dynamic island" etc
let lactivities = Lactivities.shared
/// access using `lactivities.`
final class Lactivities: NSObject {
static let shared = Lactivities()
private override init() { super.init() }
///Give it a go ...
func test() {
print("** check", ActivityAuthorizationInfo().areActivitiesEnabled )
let att = TestAttributes(name: "test")
let cs = TestAttributes.ContentState(news: "test")
let cont = ActivityContent.init(state: cs, staleDate: nil, relevanceScore: 1.0)
do {
let activity = try Activity.request(attributes: att, content: cont, pushType: .token)
print("** activity ID woot", activity.id)
Task {
for await pushToken in activity.pushTokenUpdates {
print("** token woot", pushToken.base64EncodedString()
)
}
}
}
catch let error { print("** lactivity ERR!!!!", error) }
print("** traverse ok")
}
}
.. and the structs ..
struct TestAttributes: ActivityAttributes {
public struct ContentState: Codable, Hashable {
var news: String
}
var name: String
}
struct TestWidg: Widget {
var body: some WidgetConfiguration {
ActivityConfiguration(for: TestAttributes.self) { context in
SimpleView(state: context.state, stuff: context.attributes)
} dynamicIsland: { context in
DynamicIsland { DynamicIslandExpandedRegion(.bottom) {
VStack { Text(context.attributes.name) } }
} compactLeading: { Text(context.attributes.name)
} compactTrailing: { Image(systemName: "testtube.2")
} minimal: { Image(systemName: "testtube.2")
}
}
}
}
struct SimpleView: View {
let state: TestAttributes.ContentState
let stuff: TestAttributes
var body: some View {
VStack {
Text(state.news)
Text(stuff.name)
}
}
}
and here it is! ...
///Here it is!
struct TestWidgBundle: WidgetBundle {
var body: some Widget {
TestWidg()
}
}
// end of file
It's possible this info may help people googling here. I really can't see how to "do it in code" but as a workaround,
in the Xcode project, just tap "Add Target -> Widget", you do need to select both live activity and intent; take care to embed in your relevant target, not the default one.
tip it appears one part of the Xcode example automation does not work: simply in your main target, you have add a compile sources for specifically the "NameLiveActivity.swift" source file. That would seem to be the only other necessary step.
(And you have to manually update CFBundleVersion in the new target you made.)
If you do these things it would seem that the sample code in the question, for example, will work.