Sign in Join
Wiki copytemporary

macOS File and Custom URL Scheme Associations: what changed

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

OldNewLine
11## Overview
22
33macOS does not have a central registry like Windows to which applications explicitly write information. Instead, every application with a graphical interface has a [[macOS property list files|property list file]] named `Info.plist`, roughly equivalent to a manifest in the Windows world, stored in its [[Application Bundle|application bundle]]. The `Info.plist` file may optionally include file type association and custom URL scheme information.
44
55macOS Launch Services is an API that enables a running application to open other applications or their document files in a way similar to the Finder or the Dock. Using Launch Services, an application can perform such tasks as:
66
77- Open (launch or activate) another application
88- Open a document or a URL (uniform resource locator) in another application
99- Identify the preferred application for opening a given document or URL
1010- Register information about the kinds of document files and URLs an application is capable of opening
1111- Obtain appropriate information for displaying a file or URL on the screen, such as its icon, display name, and kind string
1212- Maintain and update the contents of the Recent Items menu
1313
1414Launch Services automatically registers an application with the database the first time the application becomes known to the system. This can occur when:
1515
1616- The Finder reports an application has been added to the Applications folder.
1717- An application installer is run.
1818- When a document is opened that has no preferred application, the user is asked to select an application to use, and that application is registered with Launch Services.
1919- When the built-in Launch Services tool is run whenever you boot your Mac or login as a user. This tool scans the Applications folder looking for any new applications that have been placed there.
2020
2121When you open a document or URL, Launch Services is used to determine which application should open the item. Launch Services uses the following specific order:
2222
2323- If the user has manually set a file association, then Launch Services will use that application to open the document or URL.
2424- If the document has a file name extension, Launch Services will find all applications that list the extension as compatible.
2525- If the document has a four-character file type, Launch Services finds all applications that accept that file type.
2626- If more than one application is found, then:
2727 - If the document has a four-character creator type that matches an application:
2828 - Give preference to applications on the boot volume;
2929 - Give preference to applications on local volumes rather than remote volumes.
3030- If two or more applications still meet the criteria, give preference to the newest version.
3131
3232## Identifying the type of content in a file
3333
3434There are two primary techniques for identifying the type of content in a file:
3535
3636- Uniform Type Identifiers (UTIs)
3737- Filename extensions
3838
3939A UTI is a string that uniquely identifies a class of entities considered to have a "type". UTIs provide consistent identifiers for data on which all applications and services can recognise and rely. They are also more flexible than most other techniques because you can use them to represent any type of data, not just files and directories. Examples of UTIs include:
4040
4141- public.text — A public type that identifies text data.
4242- public.jpeg — A public type that identifies JPEG image data.
4343- com.apple.bundle — An Apple type that identifies a bundle directory.
4444- com.apple.application-bundle — An Apple type that identifies a bundled app.
4545
4646Whenever a UTI-based interface is available for specifying file types, you should prefer that interface over any others. Many macOS interfaces allow you to specify UTIs corresponding to the files or directories you want to work with.
4747
4848One way the system determines the UTI for a given file is by looking at its filename extension. A filename extension is a string of characters appended to the end of a file and separated from the main filename with a period. Each unique string of characters identifies a file of a specific type. For example, the .png extension identifies a file with image data in the portable network graphics format.
4949
5050Note: Because period characters are valid characters in macOS filenames, only the characters after the last period in a filename are considered part of the filename extension. Everything to the left of the last period is considered part of the filename itself.
5151
5252If your application defines custom file formats, you should register those formats and any associated filename extensions in your application's `Info.plist` file. The `CFBundleDocumentTypes` key specifies the file formats that your application recognises and is able to open. Entries for any custom file formats should include both a filename extension and UTI corresponding to the file contents. The system uses that information to direct files with the appropriate type to your application.
5353
5454## Simple MyEditor example application
5555
5656We shall start by creating a very simple editor application to which we will add our own custom file type extension. After that is working we will then add a custom URL scheme so that other applications (eg Safari) when faced with our custom URL scheme will offer to open files in our MyEditor application.
5757
5858- Start a new Lazarus application
5959- Drop a memo on the form
6060- Drop three buttons on the form
6161 - name one button btnOpen
6262 - name one button btnSave
6363 - name one button btnQuit
6464- Drop an OpenDialog on the form
6565- Drop a SaveDialog on the form
6666- Copy the button click handlers from the code below into your unit1.pas file
6767
6868``` pascal
6969procedure TForm1.btnOpenClick(Sender: TObject);
7070begin
7171 LoadMemo;
7272end;
7373
7474procedure TForm1.btnSaveClick(Sender: TObject);
7575begin
7676 SaveMemo;
7777end;
7878
7979procedure TForm1.btnQuitClick(Sender: TObject);
8080begin
8181 close;
8282end;
8383```
8484
8585- Go to the [[IDE Window: Object Inspector|Object Inspector]], select each button in turn, select the Events tab, select the OnClick event and double click the empty field. The correct event handler for each button should be chosen automatically.
8686- In the private section, before the public section, of TForm1 in the Interface section at the top of the unit add:
8787
8888``` pascal
8989 sTmp : string;
9090 procedure LoadMemo;
9191 procedure SaveMemo;
9292```
9393
9494- Add these two procedures after the button click handlers:
9595
9696``` pascal
9797procedure TForm1.LoadMemo;
9898begin
9999if OpenDialog1.Execute then
100100 sTmp:=OpenDialog1.Filename;
101101
102102if FileExists(sTmp) then
103103 memo1.Lines.LoadFromFile(sTmp)
104104 else
105105 showmessage('File not found: ' + sTmp);
106106end;
107107
108108procedure TForm1.SaveMemo;
109109begin
110110
111111if SaveDialog1.Execute then
112112 begin
113113 try
114114 memo1.Lines.SaveToFile(SaveDialog1.FileName);
115115 except on EStreamError do
116116 showmessage('Could not save file: ' + SaveDialog1.FileName);
117117 end;
118118 end
119119end;
120120```
121121
122122- Compile and run the application. You should be able to Open a file in the editor, Save a file and Quit the application.
123123
124124- If you encounter any errors, compare your unit1.pas against the full unit1.pas below and make any necessary corrections:
125125
126126``` pascal
127127unit Unit1;
128128
129129{$mode objfpc}{$H+}
130130
131131interface
132132
133133uses
134134 Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;
135135
136136type
137137
138138 { TForm1 }
139139
140140 TForm1 = class(TForm)
141141 btnOpen: TButton;
142142 btnSave: TButton;
143143 btnQuit: TButton;
144144 Memo1: TMemo;
145145 OpenDialog1: TOpenDialog;
146146 SaveDialog1: TSaveDialog;
147147 procedure btnOpenClick(Sender: TObject);
148148 procedure btnQuitClick(Sender: TObject);
149149 procedure btnSaveClick(Sender: TObject);
150150 private
151151 sTmp : string;
152152 procedure LoadMemo;
153153 procedure SaveMemo;
154154 public
155155
156156 end;
157157
158158var
159159 Form1: TForm1;
160160
161161implementation
162162
163163{$R *.lfm}
164164
165165{ TForm1 }
166166
167167procedure TForm1.btnOpenClick(Sender: TObject);
168168begin
169169 Form1.LoadMemo;
170170end;
171171
172172procedure TForm1.btnSaveClick(Sender: TObject);
173173begin
174174 Form1.SaveMemo;
175175end;
176176
177177procedure TForm1.btnQuitClick(Sender: TObject);
178178begin
179179 Form1.Close;
180180end;
181181
182182procedure TForm1.LoadMemo;
183183begin
184184if OpenDialog1.Execute then
185185 sTmp:=OpenDialog1.Filename;
186186
187187if FileExists(sTmp) then
188188 memo1.Lines.LoadFromFile(sTmp)
189189 else
190190 showmessage('File not found: ' + sTmp);
191191end;
192192
193193procedure TForm1.SaveMemo;
194194begin
195195if SaveDialog1.Execute then
196196 begin
197197 try
198198 memo1.Lines.SaveToFile(SaveDialog1.FileName);
199199 except on EStreamError do
200200 showmessage('Could not save file: ' + SaveDialog1.FileName);
201201 end;
202202 end
203203end;
204204
205205end.
206206```
207207
208208## Adding your custom file type extension
209209
210210Lazarus will have created an [[Application Bundle|application bundle]] for our MyEditor application. Use Finder to navigate to the project directory, right-click on the bundle directory MyEditor.app and select "Show package contents". Open the Contents subdirectory and you should see: a MacOS subdirectory, a Resources subdirectory, a Pkginfo file and the application's `Info.plist` [[macOS property list files|property list file]]. Open the file with TextEditor.app and the content should look very similar to this:
211211
212212``` xml
213213<?xml version="1.0" encoding="UTF-8"?>
214214<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
215215<plist version="1.0">
216216<dict>
217217 <key>CFBundleDevelopmentRegion</key>
218218 <string>English</string>
219219 <key>CFBundleExecutable</key>
220220 <string>MyEditor</string>
221221 <key>CFBundleName</key>
222222 <string>MyEditor</string>
223223 <key>CFBundleIdentifier</key>
224224 <string>com.company.MyEditor</string>
225225 <key>CFBundleInfoDictionaryVersion</key>
226226 <string>6.0</string>
227227 <key>CFBundlePackageType</key>
228228 <string>APPL</string>
229229 <key>CFBundleSignature</key>
230230 <string>MyEd</string>
231231 <key>CFBundleShortVersionString</key>
232232 <string>0.1</string>
233233 <key>CFBundleVersion</key>
234234 <string>1</string>
235235 <key>CSResourcesFileMapped</key>
236236 <true/>
237237 <key>CFBundleDocumentTypes</key>
238238 <array>
239239 <dict>
240240 <key>CFBundleTypeRole</key>
241241 <string>Viewer</string>
242242 <key>CFBundleTypeExtensions</key>
243243 <array>
244244 <string>*</string>
245245 </array>
246246 <key>CFBundleTypeOSTypes</key>
247247 <array>
248248 <string>fold</string>
249249 <string>disk</string>
250250 <string>****</string>
251251 </array>
252252 </dict>
253253 </array>
254254 <key>NSHighResolutionCapable</key>
255255 <true/>
256256</dict>
257257</plist>
258258```
259259
260260We will now add our custom filename extension to the property list so that MyEditor will be the default application used to open such files. Delete the highlighted lines and insert these replacement lines:
261261
262262``` xml
263263 <key>CFBundleTypeName</key>
264264 <string>My Custom File</string>
265265 <key>LSHandlerRank</key>
266266 <string>Owner</string>
267267 <key>CFBundleTypeRole</key>
268268 <string>Editor</string>
269269 <key>LSTypeIsPackage</key>
270270 <false/>
271271 <key>CFBundleTypeIconFile</key>
272272 <string>txt.icns</string>
273273 <key>CFBundleTypeExtensions</key>
274274 <array>
275275 <string>xyy</string>
276276 </array>
277277```
278278
279279Save the file. You will notice that we have changed the "role" from Viewer to Editor and we have added our custom file extension (xyy). If you only need to open files and not edit them, you should leave the "role" as viewer. We have also added an icon file "txt.icns" so that Finder will display your icon for your custom file extension.
280280
281281Now we need to add an OnDropFiles event handler to our form. Copy the following code into your unit1.pas file before the last line which contains **end.**:
282282
283283``` pascal
284284procedure TForm1.FormDropFiles(Sender: TObject;
285285 const FileNames: array of string);
286286begin
287287 memo1.Lines.LoadFromFile(FileNames[0]);
288288end;
289289```
290290
291291Go to the Object Inspector, choose Form1, select the Events tab and double-click the empty OnDropFiles field. FormDropFiles should be automatically added to the field. Now compile the application.
292292
293293As you have run MyEditor before, its original `Info.plist` file will have been cached in the Launch Service database and so the changes we made to it will not be noticed. The quickest way to fix this is to copy the MyEditor.app bundle to the Applications directory. As Lazarus only keeps a link to the executable file in the application bundle, before you copy the MyEditor application bundle, you will need to replace the file link with the executable file. Open an Applications \> Utilities \> Terminal and execute the following commands:
294294
295-` cd <your project directory>`\
296-` echo "Test file content" > test.xyy                // Create a test.xyy file while here`\
297-` rm MyEditor.app/Contents/MacOS/MyEditor            // remove the link to the executable from the bundle`\
298-` cp MyEditor MyEditor.app/Contents/MacOS/MyEditor   // copy the executable to the bundle `\
299-` cp -R MyEditor.app /Applications/                  // copy the application bundle to /Applications`\
300-` rm MyEditor.app/Contents/MacOS/MyEditor            // remove the executable from the bundle`\
301-` cd MyEditor.app/Contents/MacOS/MyEditor            `\
302-` ln -s ../../../MyEditor .                          // restore the link to the executable`
295+```text
296+ cd <your project directory>
297+ echo "Test file content" > test.xyy // Create a test.xyy file while here
298+ rm MyEditor.app/Contents/MacOS/MyEditor // remove the link to the executable from the bundle
299+ cp MyEditor MyEditor.app/Contents/MacOS/MyEditor // copy the executable to the bundle
300+ cp -R MyEditor.app /Applications/ // copy the application bundle to /Applications
301+ rm MyEditor.app/Contents/MacOS/MyEditor // remove the executable from the bundle
302+ cd MyEditor.app/Contents/MacOS/MyEditor
303+ ln -s ../../../MyEditor . // restore the link to the executable
304+```
303305
304306Now, from Finder, you should be able to double-click on your `test.xyy` file and receive the following dialog:
305307
306308![](/wiki-images/0/0e/Myeditor_dialog.png)
307309
308310Choose Open and MyEditor should open... and display the content of your `test.xyy` file. You can also drop the `test.xyy` file on the application's icon and it will open the file.
309311
310312## Adding your custom URL scheme
311313
312314Apple supports common URL schemes associated with system applications, such as http, https, ftp, and mailto. You can define your own custom scheme and register your application to support it. For this demonstration we are going to define the custom xyy:// scheme. So, when Safari comes across xyy://some_file, it will ask you if you want to use MyEditor to open it.
313315
314316For MyEditor to support a custom URL scheme, we need to do the following:
315317
3163181. Define the format for the scheme.
3173192. Register the scheme so that macOS directs appropriate URLs to MyEditor.
3183203. Handle the URLs that MyEditor receives.
319321
320322- Our format is trivial. What follows our custom URL scheme (xyy://) will just be a filename to open.
321323
322324- To register the URL scheme we return to MyEditor's `Info.plist` property list file which currently looks like this:
323325
324326``` xml
325327<?xml version="1.0" encoding="UTF-8"?>
326328<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
327329<plist version="1.0">
328330<dict>
329331 <key>CFBundleDevelopmentRegion</key>
330332 <string>English</string>
331333 <key>CFBundleExecutable</key>
332334 <string>MyEditor</string>
333335 <key>CFBundleName</key>
334336 <string>MyEditor</string>
335337 <key>CFBundleIdentifier</key>
336338 <string>com.company.MyEditor</string>
337339 <key>CFBundleInfoDictionaryVersion</key>
338340 <string>6.0</string>
339341 <key>CFBundlePackageType</key>
340342 <string>APPL</string>
341343 <key>CFBundleSignature</key>
342344 <string>MyEd</string>
343345 <key>CFBundleShortVersionString</key>
344346 <string>0.1</string>
345347 <key>CFBundleVersion</key>
346348 <string>1</string>
347349 <key>CSResourcesFileMapped</key>
348350 <true/>
349351 <key>CFBundleDocumentTypes</key>
350352 <array>
351353 <dict>
352354 <key>CFBundleTypeName</key>
353355 <string>My Custom File</string>
354356 <key>LSHandlerRank</key>
355357 <string>Owner</string>
356358 <key>CFBundleTypeRole</key>
357359 <string>Editor</string>
358360 <key>LSTypeIsPackage</key>
359361 <false/>
360362 <key>CFBundleTypeIconFile</key>
361363 <string>txt.icns</string>
362364 <key>CFBundleTypeExtensions</key>
363365 <array>
364366 <string>xyy</string>
365367 </array>
366368 <key>CFBundleTypeOSTypes</key>
367369 <array>
368370 <string>fold</string>
369371 <string>disk</string>
370372 <string>****</string>
371373 </array>
372374 </dict>
373375 </array>
374376 <key>NSHighResolutionCapable</key>
375377 <true/>
376378</dict>
377379</plist>
378380```
379381
380382- After the highlighted line above, insert the following lines into the property list file:
381383
382384``` xml
383385 <key>CFBundleURLTypes</key>
384386 <array>
385387 <dict>
386388 <key>CFBundleTypeRole</key>
387389 <string>Editor</string>
388390 <key>CFBundleURLName</key>
389391 <string>com.company.URLScheme</string>
390392 <key>CFBundleURLSchemes</key>
391393 <array>
392394 <string>xyy</string>
393395 </array>
394396 </dict>
395397 </array>
396398```
397399
398400- The final step we need to take care of is to handle the URLs that MyEditor receives. To do this we need to add some more code to unit1.pas. The lines to add are highlighted in the listing below which is now the final version of unit1.pas:
399401
400402``` pascal
401403unit Unit1;
402404
403405{$mode objfpc}{$H+}
404406{$modeswitch objectivec1}
405407
406408interface
407409
408410uses
409411 Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,
410412 Strutils, CocoaAll, MacOSAll;
411413
412414type
413415 THandlerProc = procedure(const url : string);
414416
415417 { TAppURLHandler }
416418
417419 TAppURLHandler = objcclass(NSObject)
418420 public
419421 procedure getUrlwithReplyEvent(event : NSAppleEventDescriptor; eventReply: NSAppleEventDescriptor);
420422 message 'getUrl:withReplyEvent:';
421423 public
422424 callBack : THandlerProc;
423425 end;
424426
425427 { TForm1 }
426428
427429 TForm1 = class(TForm)
428430 btnOpen: TButton;
429431 btnSave: TButton;
430432 btnQuit: TButton;
431433 Memo1: TMemo;
432434 OpenDialog1: TOpenDialog;
433435 SaveDialog1: TSaveDialog;
434436 procedure btnOpenClick(Sender: TObject);
435437 procedure btnQuitClick(Sender: TObject);
436438 procedure btnSaveClick(Sender: TObject);
437439 procedure FormCreate(Sender: TObject);
438440 procedure FormDropFiles(Sender: TObject; const FileNames: array of string);
439441 private
440442 sTmp : string;
441443 procedure LoadMemo;
442444 procedure SaveMemo;
443445 public
444446
445447 end;
446448
447449var
448450 Form1: TForm1;
449451 handler : TAppURLHandler;
450452 eventManager : NSAppleEventManager;
451453
452454implementation
453455
454456{$R *.lfm}
455457
456458{ TForm1 }
457459
458460// Handle my custom URL scheme
459461procedure HandleMyCustomURLProtocol(const FileName: string);
460462var
461463 FilePath : String;
462464begin
463465 FilePath := ReplaceStr(FileName, 'xyy://', ''); // ditch protocol scheme
464466 Form1.memo1.Lines.LoadFromFile(FilePath); // load file into memo
465467end;
466468
467469procedure TAppURLHandler.getUrlwithReplyEvent(event : NSAppleEventDescriptor; eventReply: NSAppleEventDescriptor);
468470var
469471 url : NSString;
470472begin
471473 url := event.paramDescriptorForKeyword(keyDirectObject).stringValue;
472474 callBack(url.UTF8String);
473475end;
474476
475477procedure RegisterURLHandler(HandlerProc : THandlerProc);
476478begin
477479 handler := TAppURLHandler.alloc.init;
478480 handler.callBack := HandlerProc;
479481 eventManager := NSAppleEventManager.sharedAppleEventManager;
480482 eventManager.setEventHandler_andSelector_forEventClass_andEventID(handler,ObjCSelector(handler.getUrlwithReplyEvent), kInternetEventClass,kAEGetURL);
481483end;
482484
483485// Form creation handler
484486procedure TForm1.FormCreate(Sender: TObject);
485487begin
486488 // Listen for protocol URLs
487489 RegisterURLHandler(@HandleMyCustomURLProtocol);
488490
489491 // if there is a filename on the command line
490492 if ParamCount > 0 then
491493 memo1.Lines.LoadFromFile(ParamStr(1));
492494end;
493495
494496procedure TForm1.btnOpenClick(Sender: TObject);
495497begin
496498 Form1.LoadMemo;
497499end;
498500
499501procedure TForm1.btnSaveClick(Sender: TObject);
500502begin
501503 Form1.SaveMemo;
502504end;
503505
504506procedure TForm1.btnQuitClick(Sender: TObject);
505507begin
506508 Form1.Close;
507509end;
508510
509511procedure TForm1.LoadMemo;
510512begin
511513if OpenDialog1.Execute then
512514 sTmp:=OpenDialog1.Filename;
513515
514516if FileExists(sTmp) then
515517 memo1.Lines.LoadFromFile(sTmp)
516518 else
517519 showmessage('File not found: ' + sTmp);
518520end;
519521
520522procedure TForm1.SaveMemo;
521523begin
522524if SaveDialog1.Execute then
523525 begin
524526 try
525527 memo1.Lines.SaveToFile(SaveDialog1.FileName);
526528 except on EStreamError do
527529 showmessage('Could not save file: ' + SaveDialog1.FileName);
528530 end;
529531 end
530532end;
531533
532534procedure TForm1.FormDropFiles(Sender: TObject;
533535 const FileNames: array of string);
534536begin
535537 memo1.Lines.LoadFromFile(FileNames[0]);
536538end;
537539
538540end.
539541```
540542
541543- When you have added the new lines, go to the Object Inspector, choose Form1, select the Events tab, go to the OnCreate event and double-click the empty field. The TForm1.FormCreate procedure should be automatically filled in for you. Now compile the application for the last time!
542544
543545- As you have run MyEditor before, the previous `Info.plist` file will have been cached in the Launch Service database and so the changes we made to it will not be noticed. To fix this, first drag the existing MyEditor.app bundle to the Trash Bin, and then copy the MyEditor.app bundle to the Applications directory again. Open an Applications \> Utilities \> Terminal and execute the following commands:
544546
545-` cd <your project directory>`\
546-` rm MyEditor.app/Contents/MacOS/MyEditor            // remove the link to the executable from the bundle`\
547-` cp MyEditor MyEditor.app/Contents/MacOS/MyEditor   // copy the executable to the bundle `\
548-` cp -R MyEditor.app /Applications/                  // copy the application bundle to /Applications`\
549-` rm MyEditor.app/Contents/MacOS/MyEditor            // remove the executable from the bundle`\
550-` cd MyEditor.app/Contents/MacOS/MyEditor            `\
551-` ln -s ../../../MyEditor .                          // restore the link to the executable`
547+```text
548+ cd <your project directory>
549+ rm MyEditor.app/Contents/MacOS/MyEditor // remove the link to the executable from the bundle
550+ cp MyEditor MyEditor.app/Contents/MacOS/MyEditor // copy the executable to the bundle
551+ cp -R MyEditor.app /Applications/ // copy the application bundle to /Applications
552+ rm MyEditor.app/Contents/MacOS/MyEditor // remove the executable from the bundle
553+ cd MyEditor.app/Contents/MacOS/MyEditor
554+ ln -s ../../../MyEditor . // restore the link to the executable
555+```
552556
553557- Now if you open Safari and type `xyy:///Users/<username>/<path to your project directory>/unit1.pas` into the URL box at the top... the following dialog should appear:
554558
555559![](/wiki-images/8/88/Myeditor_dialog2.png)
556560
557561- Click Allow and... the file should load.
558562
559563## Last words
560564
561565As with many things Apple, the CFBundleDocumentTypes entries:
562566
563567- CFBundleTypeExtensions
564568- CFBundleTypeMIMETypes
565569- CFBUndleTypeOSTypes
566570- NSExportableAs
567571
568572were deemed legacy `Info.plist` keys in macOS 10.5 (Leopard) and were deprecated in favour of Uniform Type Identifiers (UTIs) introduced in macOS 10.5 for document-based applications.
569573
570574Instead, you should use the LSItemContentTypes and (new for macOS 10.5) NSExportableTypes keys, and declare the corresponding UTIs as appropriate in the application `Info.plist`. For the declaration of UTIs in `Info.plist` refer to the [[macOS File and Custom URL Scheme Associations|External Links]] below.
571575
572576It should be noted that the legacy keys are still working in macOS 10.15.4 (Catalina).
573577
574578## See also
575579
576580- [[Application Bundle]]
577581- [[macOS property list files]]
578582
579583## External links
580584
581585- [Apple: Launch Services](https://developer.apple.com/documentation/coreservices/launch_services)
582586- [Apple:Developing a document-based application](https://developer.apple.com/documentation/appkit/documents_data_and_pasteboard/developing_a_document-based_app)
583587- [Apple: Uniform Type Identifers](https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/understanding_utis/understand_utis_intro/understand_utis_intro.html)
584588- [Apple: System-declared UTIs](https://developer.apple.com/library/archive/documentation/Miscellaneous/Reference/UTIRef/Articles/System-DeclaredUniformTypeIdentifiers.html)
585589- [Info.plist Keys and Values](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Introduction/Introduction.html)
586590- [Apple: Defining a custom URL scheme](https://developer.apple.com/documentation/uikit/inter-process_communication/allowing_apps_and_websites_to_link_to_your_content/defining_a_custom_url_scheme_for_your_app)
587591
588592---
589593*From the Free Pascal wiki, page "macOS File and Custom URL Scheme Associations", as it stood on 2021-12-08 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).*

Back to history