콘텐츠로 건너뛰기
  • 카테고리
  • 최근
  • 태그
  • 인기
  • 사용자
  • 그룹
  • 검색
  • Get Qt Extensions
  • Unsolved
축소
브랜드 로고
  1. 홈
  2. Qt Development
  3. General and Desktop
  4. Implement a Custom Protocol on Mac
Forum Updated to NodeBB v4.3 + New Features

Implement a Custom Protocol on Mac

예약됨 고정됨 잠김 이동됨 Unsolved General and Desktop
mac osqtwidgets
14 게시물 3 작성자 2.4k 조회수 2 Watching
  • 오래된 순
  • 최신 순
  • 가장 많은 투표
답글
  • 토픽으로 답글
로그인 후 답글 작성
이 토픽은 삭제되었습니다. 토픽 관리 권한이 있는 사용자만 볼 수 있습니다.
  • SGaistS SGaist

    Hi,

    You are looking for QDesktopServices::setUrlHandler.

    C 오프라인
    C 오프라인
    ChrisW67
    에 작성함 마지막 수정자: ChrisW67
    #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 답글 마지막 답글
    0
    • C ChrisW67

      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 오프라인
      S 오프라인
      stefanwoe
      에 작성함 마지막 수정자:
      #4

      @ChrisW67 Yes, thats what i need.

      1 답글 마지막 답글
      0
      • SGaistS 오프라인
        SGaistS 오프라인
        SGaist
        Lifetime Qt Champion
        에 작성함 마지막 수정자:
        #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 답글 마지막 답글
        0
        • SGaistS SGaist

          @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 오프라인
          S 오프라인
          stefanwoe
          에 작성함 마지막 수정자:
          #6

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

          SGaistS 1 답글 마지막 답글
          0
          • S stefanwoe

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

            SGaistS 오프라인
            SGaistS 오프라인
            SGaist
            Lifetime Qt Champion
            에 작성함 마지막 수정자:
            #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 답글 마지막 답글
            0
            • SGaistS SGaist

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

              S 오프라인
              S 오프라인
              stefanwoe
              에 작성함 마지막 수정자:
              #8

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

              SGaistS 1 답글 마지막 답글
              0
              • SGaistS SGaist

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

                S 오프라인
                S 오프라인
                stefanwoe
                에 작성함 마지막 수정자:
                #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 답글 마지막 답글
                0
                • S stefanwoe

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

                  SGaistS 오프라인
                  SGaistS 오프라인
                  SGaist
                  Lifetime Qt Champion
                  에 작성함 마지막 수정자:
                  #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 답글 마지막 답글
                  0
                  • SGaistS SGaist

                    @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 오프라인
                    S 오프라인
                    stefanwoe
                    에 작성함 마지막 수정자:
                    #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 답글 마지막 답글
                    0
                    • S 오프라인
                      S 오프라인
                      stefanwoe
                      에 작성함 마지막 수정자: stefanwoe
                      #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 답글 마지막 답글
                      5
                      • SGaistS 오프라인
                        SGaistS 오프라인
                        SGaist
                        Lifetime Qt Champion
                        에 작성함 마지막 수정자:
                        #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 답글 마지막 답글
                        0
                        • S 오프라인
                          S 오프라인
                          stefanwoe
                          에 작성함 마지막 수정자: stefanwoe
                          #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 답글 마지막 답글
                          0

                          • 로그인

                          • 검색하려면 로그인하거나 등록하세요.
                          • 첫 게시물
                            마지막 게시물
                          0
                          • 카테고리
                          • 최근
                          • 태그
                          • 인기
                          • 사용자
                          • 그룹
                          • 검색
                          • Get Qt Extensions
                          • Unsolved