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 Offline
    S Offline
    stefanwoe
    wrote on 29 Feb 2024, 14:32 last edited by stefanwoe
    #1

    We want to be able to call our application from a browser link (as i.e. MS teams does when you open a link to a teams meeting).

    The principal is quite simple and exists since quite a while. Under Windows this consists just of a few registry entries (https://stackoverflow.com/questions/80650/how-do-i-register-a-custom-url-protocol-in-windows).

    But anything i tried on the Mac does not work at all.
    See i.e. https://stackoverflow.com/questions/15721047/mac-custom-protocol-fails-on-some-machines or https://web.archive.org/web/20091215155410/http://www.xmldatabases.org/WK/blog/1154_Handling_URL_schemes_in_Cocoa.item (very old...)

    I learned that we need:
    a) to add CFBundleURLTypes to pInfo.list
    b) Add a handler that shall be called by MacOs.

    But i dont get it to work at all. Of course some native coding has to be done in Objective-C.

    Does anyone have a working sample for that within a qt Application?

    1 Reply Last reply
    0
    • S Offline
      S Offline
      SGaist
      Lifetime Qt Champion
      wrote on 29 Feb 2024, 22:31 last edited by
      #2

      Hi,

      You are looking for QDesktopServices::setUrlHandler.

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

      C 1 Reply Last reply 1 Mar 2024, 08:20
      1
      • 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