Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xcode 12 - SwiftUI preview doesn't work on Swift Package when have another Swift Package as dependencies - 'previewInstances' message to agent

I have an issue on SwiftUI preview in a view located in a Swift Package when my code imports a control or value from an other swift package.

import Foundation
import SwiftUI
import Common

struct AppointmentListItem: View {
    var appointment: Appointment
    var body: some View {
        VStack{
            HStack(spacing: 10){
               //Client Info
                Image(self.appointment.client.profilePicture)
                   .resizable()
                   .aspectRatio(contentMode: .fill)
                   .frame(width: 35, height: 35)
                   .clipShape(Circle())
                   .shadow(radius: 10)
                   .overlay(Circle().stroke(Color.white, lineWidth: 1.5))
                Text(self.appointment.client.fullName)
                   .font(.system(size: 18))
                   .bold()
                   .frame(maxWidth: .infinity, alignment: .leading)
                Text(self.appointment.getHourAndMinutes()).bold()
               //Detail info
               Button(action: {
                   withAnimation{
                       print("Go to details")
                   }
               }){
                   Image(systemName: "ellipsis")
                       .font(.system(size: 18))
                       .frame(width: 20, height: 20)
                    .rotationEffect(Angle.init(degrees: 90))
               }
            }
            .padding()
        }
        .foregroundColor(Color.white)
        .background(RoundedRectangle(cornerRadius: 20)
                        .fill(Color.hippoPrimary)// <- this color is part of Common package
        )
    }
}

If I remove or change .fill(Color.hippoPrimary) the preview is available.

The error provided by Xcode is the following:

RemoteHumanReadableError: Failed to update preview.

The preview process appears to have crashed.

Error encountered when sending 'previewInstances' message to agent.

==================================

|  RemoteHumanReadableError: The operation couldn’t be completed. (BSServiceConnectionErrorDomain error 3.)
|  
|  BSServiceConnectionErrorDomain (3):
|  ==BSErrorCodeDescription: OperationFailed

This is my Package.swift file:

// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "TodayAppointments",
    platforms: [
        .iOS(.v13)
    ],
    products: [
        // Products define the executables and libraries a package produces, and make them visible to other packages.
        .library(
            name: "TodayAppointments",
            targets: ["TodayAppointments"]),
    ],
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
        .package(path: "../Common")
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages this package depends on.
        .target(
            name: "TodayAppointments",
            dependencies: ["Common"]),
        .testTarget(
            name: "TodayAppointmentsTests",
            dependencies: ["TodayAppointments"]),
    ]
)

In the Common Package, the Colors are defined this way:

public extension Color {
    static let hippoPrimary = Color("Primary", bundle: .module)
    static let progressBarBackground = Color("ProgressBarBackground", bundle: .module)
    static let textBackground = Color("TextBackground", bundle: .module)
    static let textColor = Color("TextColor", bundle: .module)
    static let appleSignInBackground = Color("AppleSignInBackground", bundle: .module)
    static let buttonActionText = Color("Text", bundle: .module)
}

The build hasn't errors so I understand that the dependencies are ok, sounds like a IDE.

Thanks in Advance.

like image 456
Carlos Rodrigo Avatar asked Oct 26 '20 15:10

Carlos Rodrigo


People also ask

How do I run preview in SwiftUI?

There are two shortcuts that you should remember. Both of them will make your life easier during the development cycle of your SwiftUI views. Cmd + Option + Enter shows or hides previews. Cmd + Option + P runs the previews.

How do I add a package to SwiftUI?

To use the Swift package in any Xcode project, choose File > Add Package… and key in the package URL in the search bar. Xcode should then show you the package description and version. Click Add Package to download and add the package to your project.

Is SwiftUI the same as Swift?

SwiftUI helps you build great-looking apps across all Apple platforms with the power of Swift — and surprisingly little code. You can bring even better experiences to everyone, on any Apple device, using just one set of tools and APIs.


2 Answers

Workaround for both iOS and macOS (not tested with Catalyst):

extension Foundation.Bundle {
    static var swiftUIPreviewsCompatibleModule: Bundle {
        final class CurrentBundleFinder {}

        /* The name of your local package, prepended by "LocalPackages_" for iOS and "PackageName_" for macOS. You may have same PackageName and TargetName*/
        let bundleNameIOS = "LocalPackages_TargetName"
        let bundleNameMacOs = "PackageName_TargetName"

        let candidates = [
            /* Bundle should be present here when the package is linked into an App. */
            Bundle.main.resourceURL,

            /* Bundle should be present here when the package is linked into a framework. */
            Bundle(for: CurrentBundleFinder.self).resourceURL,

            /* For command-line tools. */
            Bundle.main.bundleURL,

            /* Bundle should be present here when running previews from a different package (this is the path to "…/Debug-iphonesimulator/"). */
            Bundle(for: CurrentBundleFinder.self).resourceURL?.deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent(),
            Bundle(for: CurrentBundleFinder.self).resourceURL?.deletingLastPathComponent().deletingLastPathComponent(),
        ]

        for candidate in candidates {
            let bundlePathiOS = candidate?.appendingPathComponent(bundleNameIOS + ".bundle")
            let bundlePathMacOS = candidate?.appendingPathComponent(bundleNameMacOs + ".bundle")

            if let bundle = bundlePathiOS.flatMap(Bundle.init(url:)) {
                return bundle
            } else if let bundle = bundlePathMacOS.flatMap(Bundle.init(url:)) {
                return bundle
            }
        }

        fatalError("unable to find bundle")
    }
}

Then replace calls to Bundle.module with Bundle.swiftUIPreviewsCompatibleModule.

like image 141
Nikita Patskov Avatar answered Oct 07 '22 07:10

Nikita Patskov


Update 1:

Sorry my last post was not accurate. This is a bug in Xcode with no work around. Just submitted to Apple a bug report (FB8880328). Also, posted a details write up with example code w/ repro steps here. Direct link to GitHub project: https://github.com/ryanholden8/SwiftUI-Preview-Failing-Test-Project

Old Post:

Got this exact error doing the same thing, putting colors in a separate package. This post helped me get to the bottom of it. I deleted the default class that is generated in the colors package. However, I did not delete the unit test that was based on that default class.

In short: Delete the auto-generated unit test in your Common package. Or make sure all the unit tests pass.

like image 3
ryanholden8 Avatar answered Oct 07 '22 06:10

ryanholden8