Added a WidgetBuilder to my extension so I could include a second type of widget for my app. I keep getting this error in a popup when building it onto my device.
Details
SendProcessControlEvent:toPid: encountered an error: Error Domain=com.apple.dt.deviceprocesscontrolservice Code=8 "Failed to show Widget 'com.identifier' error: Error Domain=SBAvocadoDebuggingControllerErrorDomain Code=2 "Please specify the widget kind in the scheme's Environment Variables using the key '_XCWidgetKind' to be one of: 'QuoteWidget', 'RandomWidget'" UserInfo={NSLocalizedDescription=Please specify the widget kind in the scheme's Environment Variables using the key '_XCWidgetKind' to be one of: 'QuoteWidget', 'RandomWidget'}." UserInfo={NSLocalizedDescription=Failed to show Widget 'com.identifiert' error: Error Domain=SBAvocadoDebuggingControllerErrorDomain Code=2 "Please specify the widget kind in the scheme's Environment Variables using the key '_XCWidgetKind' to be one of: 'QuoteWidget', 'RandomWidget'" UserInfo={NSLocalizedDescription=Please specify the widget kind in the scheme's Environment Variables using the key '_XCWidgetKind' to be one of: 'QuoteWidget', 'RandomWidget'}., NSUnderlyingError=0x12f915290 {Error Domain=SBAvocadoDebuggingControllerErrorDomain Code=2 "Please specify the widget kind in the scheme's Environment Variables using the key '_XCWidgetKind' to be one of: 'QuoteWidget', 'RandomWidget'" UserInfo={NSLocalizedDescription=Please specify the widget kind in the scheme's Environment Variables using the key '_XCWidgetKind' to be one of: 'QuoteWidget', 'RandomWidget'}}}
Domain: DTXMessage
Code: 1
--
Heres the before and after code.
Before adding the second widget:
import WidgetKit
import SwiftUI
import Foundation
let testBook = Book(id: UUID(), name: "Name", author: "Author", genre: "Error", page: "0", total: "77")
public enum AppGroup: String {
case Livre = "group.com.idetifier"
public var containerURL: URL {
switch self {
case .Livre:
return FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: self.rawValue)!
}
}
}
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), book: testBook)
}
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
let entry = SimpleEntry(date: Date(), book: testBook)
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
let currentDate = Date()
let entryDate = Calendar.current.date(byAdding: .minute, value: 30, to: currentDate)!
let books: [Book] = self.load("list")
let entry = SimpleEntry(date: currentDate, book: books.randomElement() ?? testBook)
let timeline = Timeline(entries: [entry], policy: .after(entryDate))
completion(timeline)
}
func load<T: Decodable>(_ filename: String) -> T {
let groupDirectory = AppGroup.Livre.containerURL
let groupURL = groupDirectory
.appendingPathComponent(filename)
.appendingPathExtension("json")
return try! JSONDecoder().decode(T.self, from: Data(contentsOf: groupURL))
}
}
struct SimpleEntry: TimelineEntry {
let date: Date
let book: Book
}
struct PlaceholderView: View {
var body: some View {
RandomWidgetView(book: testBook)
.redacted(reason: .placeholder)
}
}
struct LivreWidgetEntryView : View {
@Environment(\.widgetFamily) var family
var entry: Provider.Entry
@ViewBuilder
var body: some View {
switch family {
case .systemSmall:
RandomWidgetView(book: entry.book, size: .small)
case .systemMedium:
RandomWidgetView(book: entry.book, size: .medium)
case .systemLarge:
RandomWidgetView(book: entry.book, size: .large)
default:
RandomWidgetView(book: entry.book, size: .small)
}
}
}
@main
struct LivreWidget: Widget {
let kind: String = "LivreWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
LivreWidgetEntryView(entry: entry)
}
.configurationDisplayName("Progress of a random book")
.description("This widget shows the progress from a random book in your Library")
.supportedFamilies([.systemSmall, .systemMedium])
}
}
and after adding the second widget:
import WidgetKit
import SwiftUI
import Foundation
@main
struct LivreWidgetBuilder: WidgetBundle {
init() {}
@WidgetBundleBuilder
var body: some Widget {
RandomWidget()
QuoteWidget()
}
}
let testBook = Book(id: UUID(), name: "Name", author: "Author", genre: "Error", page: "0", total: "77", quotes: ["Quote"])
public enum AppGroup: String {
case Livre = "group.com.identifier"
public var containerURL: URL {
switch self {
case .Livre:
return FileManager.default.containerURL(
forSecurityApplicationGroupIdentifier: self.rawValue)!
}
}
}
//MARK: Random book widget
struct RandomProvider: TimelineProvider {
func placeholder(in context: Context) -> RandomSimpleEntry {
RandomSimpleEntry(date: Date(), book: testBook)
}
func getSnapshot(in context: Context, completion: @escaping (RandomSimpleEntry) -> ()) {
let entry = RandomSimpleEntry(date: Date(), book: testBook)
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
let currentDate = Date()
let entryDate = Calendar.current.date(byAdding: .minute, value: 30, to: currentDate)!
let books: [Book] = self.load("list")
let entry = RandomSimpleEntry(date: currentDate, book: books.randomElement() ?? testBook)
let timeline = Timeline(entries: [entry], policy: .after(entryDate))
completion(timeline)
}
func load<T: Decodable>(_ filename: String) -> T {
let groupDirectory = AppGroup.Livre.containerURL
let groupURL = groupDirectory
.appendingPathComponent(filename)
.appendingPathExtension("json")
return try! JSONDecoder().decode(T.self, from: Data(contentsOf: groupURL))
}
}
struct RandomSimpleEntry: TimelineEntry {
let date: Date
let book: Book
}
struct RandomPlaceholderView: View {
var body: some View {
RandomWidgetView(book: testBook)
.redacted(reason: .placeholder)
}
}
struct RandomWidgetEntryView : View {
@Environment(\.widgetFamily) var family
var entry: RandomProvider.Entry
@ViewBuilder
var body: some View {
switch family {
case .systemSmall:
RandomWidgetView(book: entry.book, size: .small)
case .systemMedium:
RandomWidgetView(book: entry.book, size: .medium)
case .systemLarge:
RandomWidgetView(book: entry.book, size: .large)
default:
RandomWidgetView(book: entry.book, size: .small)
}
}
}
struct RandomWidget: Widget {
let kind: String = "RandomWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: RandomProvider()) { entry in
RandomWidgetEntryView(entry: entry)
}
.configurationDisplayName("Random book progress")
.description("This widget shows the progress from a random book in your Library")
.supportedFamilies([.systemSmall, .systemMedium])
}
}
//MARK: Quote Widget
struct QuoteProvider: TimelineProvider {
func placeholder(in context: Context) -> QuoteSimpleEntry {
QuoteSimpleEntry(date: Date(), book: testBook)
}
func getSnapshot(in context: Context, completion: @escaping (QuoteSimpleEntry) -> ()) {
let entry = QuoteSimpleEntry(date: Date(), book: testBook)
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
let currentDate = Date()
let entryDate = Calendar.current.date(byAdding: .minute, value: 30, to: currentDate)!
let books: [Book] = self.load("list")
let entry = QuoteSimpleEntry(date: currentDate, book: books.randomElement() ?? testBook)
let timeline = Timeline(entries: [entry], policy: .after(entryDate))
completion(timeline)
}
func load<T: Decodable>(_ filename: String) -> T {
let groupDirectory = AppGroup.Livre.containerURL
let groupURL = groupDirectory
.appendingPathComponent(filename)
.appendingPathExtension("json")
return try! JSONDecoder().decode(T.self, from: Data(contentsOf: groupURL))
}
}
struct QuoteSimpleEntry: TimelineEntry {
let date: Date
let book: Book
}
struct QuotePlaceholderView: View {
var body: some View {
QuoteWidgetView(book: testBook)
.redacted(reason: .placeholder)
}
}
struct QuoteWidgetEntryView : View {
@Environment(\.widgetFamily) var family
var entry: QuoteProvider.Entry
var body: some View {
QuoteWidgetView(book: entry.book, size: .small)
}
}
struct QuoteWidget: Widget {
let kind: String = "QuoteWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: QuoteProvider()) { entry in
QuoteWidgetEntryView(entry: entry)
}
.configurationDisplayName("Quote widget")
.description("This widget shows a random quote from a random book in your Library")
.supportedFamilies([.systemMedium])
}
}
The widgets seem to work, but I'm trying to find out why i'm getting this popup error.