Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Implement a Custom Protocol on Mac
QtWS25 Last Chance

Implement a Custom Protocol on Mac

Scheduled Pinned Locked Moved Unsolved General and Desktop
mac osqtwidgets
14 Posts 3 Posters 2.2k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S SGaist
    29 Feb 2024, 22:31

    Hi,

    You are looking for QDesktopServices::setUrlHandler.

    C Offline
    C Offline
    ChrisW67
    wrote on 1 Mar 2024, 08:20 last edited by ChrisW67 3 Jan 2024, 08:22
    #3

    I think @stefanwoe is asking a related but different question.

    How do you make an arbitrary browser on Mac open your application and pass the URL as argument when you give the browser a URL like myapp://some/arguments? On Windows this is done with registry magic (and offerings to the deity of your choice).

    This is not the same thing as making a custom scheme for use from within a Qt program, which is what QDesktopServices does in a non-persistent fashion.

    S 1 Reply Last reply 1 Mar 2024, 08:31
    0
    • C ChrisW67
      1 Mar 2024, 08:20

      I think @stefanwoe is asking a related but different question.

      How do you make an arbitrary browser on Mac open your application and pass the URL as argument when you give the browser a URL like myapp://some/arguments? On Windows this is done with registry magic (and offerings to the deity of your choice).

      This is not the same thing as making a custom scheme for use from within a Qt program, which is what QDesktopServices does in a non-persistent fashion.

      S Offline
      S Offline
      stefanwoe
      wrote on 1 Mar 2024, 08:31 last edited by
      #4

      @ChrisW67 Yes, thats what i need.

      1 Reply Last reply
      0
      • S Offline
        S Offline
        SGaist
        Lifetime Qt Champion
        wrote on 1 Mar 2024, 09:05 last edited by
        #5

        @ChrisW67 that's also what I understood.

        Even if iOS is mentioned in the documentation, AFAIR, the same applies for macOS with the changes you have to do to the info.plist file through the CFBundleURLSchemes entry.

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        S 1 Reply Last reply 1 Mar 2024, 11:09
        0
        • S SGaist
          1 Mar 2024, 09:05

          @ChrisW67 that's also what I understood.

          Even if iOS is mentioned in the documentation, AFAIR, the same applies for macOS with the changes you have to do to the info.plist file through the CFBundleURLSchemes entry.

          S Offline
          S Offline
          stefanwoe
          wrote on 1 Mar 2024, 11:09 last edited by
          #6

          @SGaist Thats what i tried, but so far no success.

          S 1 Reply Last reply 1 Mar 2024, 19:28
          0
          • S stefanwoe
            1 Mar 2024, 11:09

            @SGaist Thats what i tried, but so far no success.

            S Offline
            S Offline
            SGaist
            Lifetime Qt Champion
            wrote on 1 Mar 2024, 19:28 last edited by
            #7

            @stefanwoe can you share a minimal compilable sample application so we can investigate ?

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            S 2 Replies Last reply 2 Mar 2024, 10:08
            0
            • S SGaist
              1 Mar 2024, 19:28

              @stefanwoe can you share a minimal compilable sample application so we can investigate ?

              S Offline
              S Offline
              stefanwoe
              wrote on 2 Mar 2024, 10:08 last edited by
              #8

              @SGaist if i had this i would not have asked this question.

              S 1 Reply Last reply 4 Mar 2024, 20:54
              0
              • S SGaist
                1 Mar 2024, 19:28

                @stefanwoe can you share a minimal compilable sample application so we can investigate ?

                S Offline
                S Offline
                stefanwoe
                wrote on 3 Mar 2024, 21:42 last edited by
                #9

                @SGaist But you may have a look at the link i posted:
                www.xmldatabases.org/WK/blog/1154_Handling_URL_schemes_in_Cocoa.item (very old...)

                1 Reply Last reply
                0
                • S stefanwoe
                  2 Mar 2024, 10:08

                  @SGaist if i had this i would not have asked this question.

                  S Offline
                  S Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on 4 Mar 2024, 20:54 last edited by
                  #10

                  @stefanwoe said in Implement a Custom Protocol on Mac:

                  @SGaist if i had this i would not have asked this question.

                  The goal is not that you provide a working solution. Having a minimal project will allow us to check your issue and help you debug it.

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  S 1 Reply Last reply 5 Mar 2024, 06:10
                  0
                  • S SGaist
                    4 Mar 2024, 20:54

                    @stefanwoe said in Implement a Custom Protocol on Mac:

                    @SGaist if i had this i would not have asked this question.

                    The goal is not that you provide a working solution. Having a minimal project will allow us to check your issue and help you debug it.

                    S Offline
                    S Offline
                    stefanwoe
                    wrote on 5 Mar 2024, 06:10 last edited by
                    #11

                    @SGaist This can be done with any sample application. i.e. the MDI Example https://doc.qt.io/qt-6.2/qtwidgets-mainwindows-mdi-example.html.
                    If we us a URL in a browser such us

                    mayprotocol://mydata

                    A handler within this application shall be called.
                    AND: if the application is not running it shall be started. That works fine on windows (no programming in the required - its just called with a command line parameter) see the link in my question), but i dont get it to work on the mac.

                    1 Reply Last reply
                    0
                    • S Offline
                      S Offline
                      stefanwoe
                      wrote on 10 May 2024, 10:24 last edited by stefanwoe 5 Nov 2024, 06:13
                      #12

                      After spending several days in total with this I now had success and the custom protocol works as expected.

                      Basically its correct, that only a CFBundleURLTypes entry in Info.plist is needed but there are some caveats that were so hard to find out:

                      1. Updating Info.plist in the QCreator project will not immediately update the Info.plist file in the created application boundle. This remains unchanged until a full rebuild is made.
                      2. But even if we modify the file inside the Application boundle (MyApp.app/Contents/Info.plist) a modification in this file will not always be noticed by the macOS after you once start the application. I have not found the details of this. I created a sample project in XCode and there all changes were registered immediately. Also if you download a dmg file this is registered immediately.
                      3. The Key to get all this to work during development is the lsregister utility described here:
                        https://eclecticlight.co/2019/03/25/lsregister-a-valuable-undocumented-command-for-launchservices/

                      Command to remove all custom protocols:

                      /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -kill -r -domain u -domain s -domain l -v
                      

                      If you do that, as soon as you start your application, the custom protocol defined in MyApp.app/Contents/Info.plist will be registered

                      To find if a protocol is registered:

                      /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -dump | grep myprotocol
                      

                      Where myprotocol is the name of the protocol searched. You may pipe the dump to less or a file to see which application is registered for the protocol. The dump returns a huge amount of data.

                      Also you can tell lsregister to add the protocol(s) from a boundle:

                      /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -R -f pathname
                      

                      The linked article states "You shouldn’t ever have to do this" - but this seems invalid to me.

                      Or tell lsregister to forget about a application:

                      /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -R -f -u pathname
                      code_text
                      

                      where pathname is the path and name of the app.

                      So the whole process is:

                      1. Add CFBundleURLTypes to your Info.plist
                      <key>CFBundleURLTypes</key>
                      <array>
                         <dict>
                           <key>CFBundleTypeRole</key>
                           <string>Viewer</string>
                           <key>CFBundleURLName</key>
                           <string>com.mydomain</string>
                           <key>CFBundleURLSchemes</key>
                           <array>
                               <string>myProtocol</string>
                           </array>
                         </dict>
                      </array>
                      

                      And then take care about the registering as described above.

                      If the protocol IS registered on the Mac, then you'll get a nice clean QEvent::FileOpen in the event callback of your application class derived from QApplication:

                      class CMyApplication : public QApplication
                      {
                      public:
                          CMyApplication(int &argc, char **argv)
                              : QApplication(argc, argv)
                          {
                          }
                      
                          bool event(QEvent *event) override
                          {
                              if (event->type() == QEvent::FileOpen) {
                                  QFileOpenEvent *openEvent = static_cast<QFileOpenEvent *>(event);
                                  QString urlString = openEvent->url().toString();
                                      // Processs urlString ...
                              }
                              return QApplication::event(event);
                          }
                      };
                      

                      Now you can open a browser and type in the address bar:

                      myProtocol://?param1=value1&param2=value2
                      

                      And the browser will ask you if you want to start the registered application:
                      ed8eafe0-833e-44ec-ac4e-355b214f018a-image.png

                      If you accept this, openEvent->url().toString() will return the complete string you typed into your browser. If your Application is not running it will be started by the macOS.

                      1 Reply Last reply
                      5
                      • S Offline
                        S Offline
                        SGaist
                        Lifetime Qt Champion
                        wrote on 10 May 2024, 19:07 last edited by
                        #13

                        Thanks for the thorough feedback !

                        Interested in AI ? www.idiap.ch
                        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                        1 Reply Last reply
                        0
                        • S Offline
                          S Offline
                          stefanwoe
                          wrote on 8 Apr 2025, 20:17 last edited by stefanwoe 4 Aug 2025, 20:43
                          #14

                          The Implementation to handle a custom Protocol in the Application does no more work in Qt 6.8.2 as described above (only the C++ programming part, the other stuff - Info.plist etc. remains unchanged)
                          The correct way to implement such a handler is to use

                          void QDesktopServices::setUrlHandler()

                          See https://doc.qt.io/qt-6/qdesktopservices.html#setUrlHandler
                          This paragraph also describes how to set Info.plist etc...
                          This most likely also would have worked in 6.5.3 - why did I never find it?

                          For Windows all of this works quite differently. Registering works through well known registry entries:

                          [HKEY_CLASSES_ROOT\myprotocol]
                          "URL Protocol"=""
                          [HKEY_CLASSES_ROOT\myprotocol\shell]
                          [HKEY_CLASSES_ROOT\myprotocol\shell\open]
                          [HKEY_CLASSES_ROOT\myprotocol\shell\open\command] 
                          @="\"path to application.exe" \"%1\"
                          

                          This will just start a new instance of the application with the custom protocols URL as first parameter %1. Its the applications responsibility to handle that correctly (i.e. call a existing instance via a QLocalSocket etc.

                          1 Reply Last reply
                          0

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt Extensions
                          • Unsolved