Generate images and colors inside a Swift package

I saw that now, Xcode 15 beta can help us generate our assets to facilitate the access instead of passing the color/image name.

I saw that ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS should be true in Xcode 15 beta to make this happen.

How can we set this value to true in the case of a Swift Package?

Tried this, but it's not working:

// swift-tools-version: 5.9

import PackageDescription

let package = Package(
    name: "Common",
	platforms: [.iOS(.init(stringLiteral: "17"))],
    products: [
        .library(
            name: "Common",
            targets: ["Common"]),
    ],
    dependencies: [],
    targets: [
        .target(
            name: "Common",
			dependencies: [],
			resources: [
				.process("Resources")
			],
			swiftSettings: [.define("ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS")]
		),
        .testTarget(
            name: "CommonTests",
            dependencies: ["Common"]),
    ]
)
1 Like

Those extensions are generated by Xcode invoking actool with a set of arguments to produce .swift source files based on the project's assets.

SPM doesn't have support for that directly, but you might be able to write a build plug-in that does the same invocation (look at Xcode's build log to see what flags it's passing) and then wire that source file into the rest of the build.

1 Like

At least Xcode 15 beta 3 generates asset symbols automatically for packages, as per release notes.

So, it might be that future releases will also generate symbol extensions.

From what I'm seeing build logs have a Generate asset symbols invocation for each Swift Package target (when building an Xcode based target that links to packages or in isolation), and for some reason not only --generate-swift-asset-symbols is passed when actool is called for them but also --generate-swift-asset-symbol-extensions NO which disables the generation of symbol extensions.

Am running Xcode 15 Beta 4, but and not even seeing the "Generate asset symbols" step in the build logs for my local Swift Package. What am I doing wrong?

Ok, Xcode 15 Beta 5 is now generating the asset symbols correctly, but the extensions are still not being generated. :frowning_face:

is it possible to expose these generate symbol outside the package in the main app or other package

Does anybody know if it's possible to turn off this symbol generation? It's causing conflicts with existing symbols in our code, and the quickest (temporary) workaround would be to disable this new generation. But, I don't think you can set a build setting like ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS=NO via SPM.

Are there any other clever workarounds to get it to skip or ignore this new generation?

1 Like

I am also interested in this.
In addition, I would love to know how to get the ShapeStyle & Color extension generated for color resources that are part of an Xcode project. The "Asset symbol generation" does seem to be incomplete for Swift packages...

any one able to generate symbols from package yet?

anyone know if you can make these extensions public? We have a design system swift package and would like to expose all of our colors/icons in this way.

8 Likes

I'm really interested in this as well, using XCode 15.0.1 we still don't have access to the generated symbols outside the swift package manager.

1 Like

There actually is a workaround to use Assets from a Package in other Packages or in the App.

You can create the target as you did.
The swiftSettings: [.define("ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS")]
is not necessary for this workaround.

You just need to create a public extension on Image like

public extension Image {
static var yourImage: Image { .init(.yourImage as ImageResource) }

init(_ image: Image) {
        self = image
    }
}

The .yourImage is the image from your asset catalog, which is automatically generated.

As soon as the public auto-generation works you can just delete the extension and there should be no changes on the call side.

For colors you can use sth like:

public extension Color {

static var customColor: Color { .init(.customColor) }
}

public extension ShapeStyle where Self == Color {

static var customColor: SwiftUI.Color { .init(.customColor) }
}

Color seems to work without the extra init method.