Skip to content

Instantly share code, notes, and snippets.

@zats
Last active January 7, 2025 21:47
Show Gist options
  • Save zats/ffd6b2c72b8753f043ec769c6c6739b5 to your computer and use it in GitHub Desktop.
Save zats/ffd6b2c72b8753f043ec769c6c6739b5 to your computer and use it in GitHub Desktop.
Internal SF Symbols

image

List of all the images in /Library/Developer/CoreSimulator/Volumes/iOS_21A328/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 17.0.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/SFSymbols.framework/CoreGlyphsPrivate.bundle/Assets.car

Extract using https://github.com/insidegui/AssetCatalogTinkerer etc

struct ContentView: View {
var body: some View {
let names = [
["appstore.app.dashed", "buildings.3d", "emoji.chicken.face"],
["person.text.rectangle.and.nfc", "secure.element", "laugh.bubble.tapback.2.he"],
["apple.news", "apple.podcasts.square.stack", "apple.slice"],
]
VStack(spacing: 20) {
Grid(horizontalSpacing: 20, verticalSpacing: 20) {
ForEach(names, id: \.self) { nameRow in
GridRow {
ForEach(nameRow, id: \.self) { name in
Image(privateSystemName: name)
.imageScale(.large)
.foregroundStyle(.tint)
.tint(Color(hue: .random(in: 0...1), saturation: 1, brightness: 0.7))
}
}
}
}
Text("Internal SF Symbols")
.font(.caption)
}
}
}
extension Image {
init(privateSystemName: String) {
self.init(uiImage: UIImage(privateSystemName: privateSystemName))
}
}
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface SFSCoreGlyphsBundle: NSObject
@property (nonatomic, class, readonly) NSBundle *private;
@end
@interface _UIAssetManager : NSObject
+ (instancetype)assetManagerForBundle:(NSBundle *)bundle;
- (UIImage *)imageNamed:(NSString *)name;
@end
@interface UIImage (SFSCoreGlyphsBundle)
- (instancetype)initWithPrivateSystemName:(NSString *)name;
@end
NS_ASSUME_NONNULL_END
#import "SFSymbols.h"
@implementation UIImage (SFCoreGlyphBundle)
- (instancetype)initWithPrivateSystemName:(NSString *)name {
NSBundle *const bundle = [NSClassFromString(@"SFSCoreGlyphsBundle") private];
_UIAssetManager *const assetManager = [_UIAssetManager assetManagerForBundle:bundle];
self = [[assetManager imageNamed:name] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
return self;
}
@end
@forcequitOS
Copy link

For anyone coming across this, I rewrote this as Swift since I wanted to use it in a Playground, usage is the same as the original.

import SwiftUI

class PrivateImage {
    private let baseImage: UIImage

    init?(privateSystemName name: String) {
        guard let bundleClass = NSClassFromString("SFSCoreGlyphsBundle") as AnyObject?,
              let bundle = bundleClass.perform(NSSelectorFromString("private"))?.takeUnretainedValue(),
              let assetManagerClass = NSClassFromString("_UIAssetManager") as AnyObject?,
              let assetManager = assetManagerClass.perform(NSSelectorFromString("assetManagerForBundle:"), with: bundle)?.takeUnretainedValue(),
              let baseImage = assetManager.perform(NSSelectorFromString("imageNamed:"), with: name)?.takeUnretainedValue() as? UIImage else {
            return nil
        }
        self.baseImage = baseImage
    }

    func imageAsset() -> Image? {
        Image(uiImage: self.baseImage.withRenderingMode(.alwaysTemplate))
    }
}

extension Image {
    init?(privateSystemName: String) {
        guard let privateImage = PrivateImage(privateSystemName: privateSystemName) else {
            return nil
        }
        self = privateImage.imageAsset() ?? Image(systemName: "questionmark.square.fill")
    }
}

@SamusAranX
Copy link

There are a few private icons that seem to either be multicolored by default, or have multicolor variants, such as activity.rings.closed, activity.rings.open, or apple.cycletracking.
That last one in particular also has the variants apple.cycletracking.circle and apple.cycletracking.circle.fill.

Is there a way to use the multicolor variants or to use .symbolVariant to derive the circled/filled versions from the base image?

@forcequitOS
Copy link

There are a few private icons that seem to either be multicolored by default, or have multicolor variants, such as activity.rings.closed, activity.rings.open, or apple.cycletracking. That last one in particular also has the variants apple.cycletracking.circle and apple.cycletracking.circle.fill.

Is there a way to use the multicolor variants or to use .symbolVariant to derive the circled/filled versions from the base image?

To my knowledge (as I was experimenting a lot with this implementation of private symbols), every type of modification that you’d want to do has to be done via a SymbolConfiguration within the implementation of private symbols, it can’t be done at a SwiftUI view level. The issue is that the only rendering modes you have access to are palette and hierarchical. I don’t believe there’s a way to access the default colors using this method, unfortunately, as the system treats them as generic symbols as if you’ve created them and added them to your app bundle.

If you want to use a SymbolConfiguration to experiment with it a bit, in my Swift rewrite, you can just use:
let symbolConfig = UIImage.SymbolConfiguration(scale: .large) // Use your symbol configuration here and
self.baseImage = baseImage.applyingSymbolConfiguration(symbolConfig)! at the end of the privateSystemName init.

In terms of symbolVariant, it seems easy enough* to write the logic for it manually if you truly wanted to, and I’m planning to make a package to make using private symbols easier in the not-too-distant future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment