Asset Plugin Library
Library: https://github.com/ratnesh-jain/AssetPluginLibrary
Utilizing the local Swift Package Manager (SPM) for Apple platform development offers a plethora of advantages:
- Enhanced compile time: SPM efficiently manages dependencies, reducing compilation times.
- Isolated feature creation: SPM facilitates the creation of isolated features, enhancing testability.
- Improved Xcode preview integration: Swift package targets/modules seamlessly integrate with Xcode preview functionality, allowing for rapid iteration and refined UI development.
Since the release of Xcode 15, it automatically generates source code for type-safe asset access, a highly beneficial feature. This includes both Xcode project's Asset Catalogs and from Swift packages.
However, there's currently a limitation wherein Xcode doesn't generate public methods for xcassets within Swift packages. To address this gap, our library offers a solution akin to Xcode's functionality.
Let's explore the issue further and discover how leveraging the AssetPluginLibrary can effectively mitigate it
The Problem
Create a Swift package and add a folder inside the Sources
directory named "Resources". Now let add Asset catelogue to the newly created Resources
directory.
Let's add few images to the Media
Asset Catelog.

Now if we build the package, Xcode will generate some code to access the media assets as shown below.

As we will see, this generated code does not have any access control modifiers, which is internal by default. This will cause the access to the Resources module only, but we need to access these across other features creating Views for user interfaces.
The Solution
We can now add the AssetPluginLibrary as a dependency to our package.
let package = Package(
name: "Application",
platforms: [.iOS(.v17)],
products: [
.library(
name: "Application",
targets: ["Application"]),
],
dependencies: [
+ .package(url: "https://github.com/ratnesh-jain/AssetPluginLibrary", .upToNextMajor(from: "0.0.1")),
],
targets: [
.target(name: "Resources", dependencies: []),
.target(
name: "Application", dependencies: ["Resources"]),
.testTarget(
name: "ApplicationTests",
dependencies: ["Application"]),
]
)
Example Source: Package.swift
As we add this library as a package dependency, and it exports a SwiftPackagePlugin, Xcode will now shows an plugin action Generate Asset Resources
to the our Package's context menu as shown below.

Xcode will now preset a modal for selecting module in which we have .xcassets
file which is Resources
in this example.
- NOTE: For Xcode to show
Resources
as a input option, we need to make theResources
target as a product first as below.
let package = Package(
name: "Application",
platforms: [.iOS(.v17)],
products: [
// Products define the executables and libraries a package produces, making them visible to other packages.
.library(
name: "Application",
targets: ["Application"]),
+ .library(
+ name: "Resources",
+ targets: ["Resources"]
+ ),
],

This plugin action will create a new swift file called AssetResource
in which it generates all the code similar to Xcode but with public access control modifier as shown in screenshot below.

Now we can import the Resources module to our Application module, and we can access the newly generated assets using a new Image initialiser Image(asset: ImageAssetResource)
.
import Foundation
import Resources
import SwiftUI
public struct AppFeature: View {
public var body: some View {
VStack {
+ Image(asset: .appleMaps)
.resizable()
.aspectRatio(contentMode: .fit)
+ Image(asset: .swiftScript)
.resizable()
.aspectRatio(contentMode: .fit)
+ Image(asset: .swiftui)
.resizable()
.aspectRatio(contentMode: .fit)
}
}
}
Example: Application.swift

We trust you find this article insightful and informative. Thank you for reading.