Sign in Join
Wiki copytemporary

Locating the macOS application resources directory: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: Locating the macOS application resources directory

OldNewLine
1+*(macOS only)*
2+
3+Resources are data files that live outside of your application’s executable file. The resources directory is where you should store these files (eg your image files, sound files, icon files and other data files necessary for your application's operation). The contents of this directory may be further divided into subdirectories where you can store localized and non-localized versions of your resource files.
4+
5+## macOS File Storage Overview
6+
7+## Application Resources Directory
8+
9+The basic structure of the [[Application Bundle|application bundle]] is:
10+
11+ MyApp.app/
12+ Contents/
13+ Info.plist
14+ MacOS/
15+ Resources/
16+
17+A more complex application bundle layout can be seen in my [[Add an Apple Help Book to your macOS app|Apple Help Book article]].
18+
19+## Using a CFBundle object
20+
21+CFBundle allows you to use a folder hierarchy called a bundle to organize and locate many types of application resources including images, sounds, localized strings, and executable code.
22+
23+Set out below are two ways to find the location of the Resources directory using the Core Foundation bundle object.
24+
25+The first way is to retrieve the bundle directory (ie MyApp.app/) and concatenate the standard Contents and Resources directories to create the full Resources directory path like so:
26+
27+``` pascal
28+...
29+
30+{$modeswitch objectivec1}
31+
32+interface
33+
34+Uses
35+ MacOSAll;
36+
37+...
38+
39+function GetBundlePath(): string;
40+var
41+ pathRef: CFURLRef;
42+ pathCFStr: CFStringRef;
43+ pathStr: shortstring;
44+ status: Boolean = false;
45+begin
46+ pathRef := CFBundleCopyBundleURL(CFBundleGetMainBundle());
47+ pathCFStr := CFURLCopyFileSystemPath(pathRef, kCFURLPOSIXPathStyle);
48+
49+ status := CFStringGetPascalString(pathCFStr, @pathStr, 255, CFStringGetSystemEncoding());
50+
51+ if(status = true) then
52+ Result := pathStr
53+ else
54+ raise Exception.Create('Error in GetBundlePath()');
55+end;
56+
57+...
58+
59+procedure TForm1.MenuItem1Click(Sender: TObject);
60+begin
61+ ShowMessage(GetBundlePath + PathDelim + 'Contents' + PathDelim + 'Resources' + PathDelim);
62+end;
63+```
64+
65+The second way is to actually interrogate the application bundle for the full path to its Resources directory without the need to concatenate any directories as shown here:
66+
67+``` pascal
68+...
69+
70+{$modeswitch objectivec1}
71+
72+interface
73+
74+Uses
75+ ...
76+ MacOSAll,
77+ CocoaAll;
78+
79+...
80+
81+function GetResourcesPath(): string;
82+var
83+ pathStr: shortstring;
84+ status: Boolean = false;
85+begin
86+ status := CFStringGetPascalString(CFStringRef(NSBundle.mainBundle.resourcePath), @pathStr, 255, CFStringGetSystemEncoding());
87+
88+ if(status = true) then
89+ Result := pathStr + PathDelim
90+ else
91+ raise Exception.Create('Error in GetResourcesPath()');
92+end;
93+
94+...
95+
96+procedure TForm1.MenuItem1Click(Sender: TObject);
97+begin
98+ ShowMessage(GetResourcesPath);
99+end;
100+```
101+
102+If you just want to retrieve the directory in which your application bundle is located, it is a simple matter of extracting it from the `GetBundlePath()` function above like this:
103+
104+``` pascal
105+...
106+
107+Uses
108+ SysUtils,
109+ ...
110+
111+...
112+
113+procedure TForm1.MenuItem1Click(Sender: TObject);
114+begin
115+ ShowMessage(ExtractFilePath(GetBundlePath));
116+end;
117+```
118+
119+## Using an NSBundle object
120+
121+Apple uses bundles to represent applications, frameworks, plug-ins, and many other specific types of content. Bundles organize their contained resources into well-defined subdirectories, and bundle structures vary depending on the platform and the type of the bundle. By using a bundle object, you can access a bundle's resources without knowing the structure of the bundle. The bundle object provides a single interface for locating items, taking into account the bundle structure, user preferences, available localizations, and other relevant factors. Any executable can use a bundle object to locate resources, either inside an application’s bundle or in a known bundle located elsewhere. You don't use a bundle object to locate files in a container directory or in other parts of the file system.
122+
123+The unit below demonstrates how to find the application bundle directory, the bundle resources directory and various other bundle paths using the Foundation NSBundle object.
124+
125+``` pascal
126+unit Unit1;
127+
128+{$mode objfpc}{$H+}
129+{$modeswitch objectivec1}
130+
131+interface
132+
133+uses
134+ Classes,
135+ Forms,
136+ Dialogs, // Needed for ShowMessage
137+ StdCtrls, // Needed for Buttons
138+ SysUtils, // Needed for pathdelimiter
139+ CocoaAll, // Needed for NSBundle
140+ CocoaUtils; // Needed for NSStringToString
141+
142+type
143+
144+ { TForm1 }
145+
146+ TForm1 = class(TForm)
147+ Button1: TButton;
148+ Button2: TButton;
149+ Button3: TButton;
150+ Button4: TButton;
151+ Button5: TButton;
152+ Button6: TButton;
153+ Button7: TButton;
154+ procedure Button1Click(Sender: TObject);
155+ procedure Button2Click(Sender: TObject);
156+ procedure Button3Click(Sender: TObject);
157+ procedure Button4Click(Sender: TObject);
158+ procedure Button5Click(Sender: TObject);
159+ procedure Button6Click(Sender: TObject);
160+ procedure Button7Click(Sender: TObject);
161+ private
162+
163+ public
164+
165+ end;
166+
167+var
168+ Form1: TForm1;
169+
170+implementation
171+
172+{$R *.lfm}
173+
174+Function GetMainBundlePath: string;
175+begin
176+ Result := NSStringToString(NSBundle.mainBundle.bundlePath);
177+end;
178+
179+function GetExecutablePath : string;
180+begin
181+ Result := NSStringToString(NSBundle.mainBundle.executablePath);
182+end;
183+
184+function GetResourcesPath : string;
185+begin
186+ Result := NSStringToString(NSBundle.mainBundle.resourcePath) + PathDelim;
187+end;
188+
189+Function GetSoundResourcePath(Sound: NSString): string;
190+begin
191+ Result := NSStringToString(NSBundle.mainBundle.pathForSoundResource(Sound));
192+end;
193+
194+Function GetBundleIdentifier : string;
195+begin
196+ Result := NSStringToString(NSBundle.mainBundle.bundleIdentifier);
197+end;
198+
199+Function GetSharedSupportPath : string;
200+begin
201+ Result := NSStringToString(NSBundle.mainBundle.sharedSupportPath);
202+end;
203+
204+Function GetPathForImageResource(Image: NSString) : string;
205+begin
206+ Result := NSStringToString(NSBundle.mainBundle.pathForImageResource(Image));
207+end;
208+
209+{ TForm1 }
210+
211+procedure TForm1.Button1Click(Sender: TObject);
212+begin
213+ ShowMessage(GetExecutablePath);
214+end;
215+
216+procedure TForm1.Button2Click(Sender: TObject);
217+begin
218+ ShowMessage(GetResourcesPath);
219+end;
220+
221+procedure TForm1.Button3Click(Sender: TObject);
222+begin
223+ ShowMessage(GetMainBundlePath);
224+end;
225+
226+procedure TForm1.Button4Click(Sender: TObject);
227+begin
228+ // Find path to the Glass.aiff sound file in the resources directory
229+ ShowMessage(GetSoundResourcePath(NSStr('Glass')));
230+end;
231+
232+procedure TForm1.Button5Click(Sender: TObject);
233+begin
234+ ShowMessage(GetBundleIdentifier);
235+end;
236+
237+procedure TForm1.Button6Click(Sender: TObject);
238+begin
239+ ShowMessage(GetSharedSupportPath);
240+end;
241+
242+procedure TForm1.Button7Click(Sender: TObject);
243+begin
244+ // Find path to world1.png in resources directory
245+ ShowMessage(GetPathForImageResource(NSStr('world1')));
246+end;
247+
248+end.
249+```
250+
251+You can also simplify the above by omitting the CocoaUtils unit (losing access to NSStringToString) and use the UTF8String function. For example:
252+
253+``` pascal
254+function GetExecutablePath : string;
255+begin
256+ //Result := NSStringToString(NSBundle.mainBundle.executablePath);
257+ Result := NSBundle.mainBundle.executablePath.UTF8String;
258+end;
259+```
260+
261+## See also
262+
263+- [[Locating macOS significant directories]]
264+- [[Locating macOS app support, preferences folders]]
265+- [[Locating the macOS tmp directory]]
266+
267+## External links
268+
269+- [Apple: Bundle Programming Guide](https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html).
270+- [Apple: Core Foundation CFBundle Overview](https://developer.apple.com/documentation/corefoundation/cfbundle-s0a).
271+- [Apple: NSBundle class](https://developer.apple.com/documentation/foundation/nsbundle).
272+
273+---
274+*From the Free Pascal wiki, page "Locating the macOS application resources directory", as it stood on 2021-03-26 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
275+Category: Code Snippets
276+Category: macOS

Back to history