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. Understanding Qt and Mac PKG Setups
QtWS25 Last Chance

Understanding Qt and Mac PKG Setups

Scheduled Pinned Locked Moved Solved General and Desktop
macdeployqtmacosxpkgsetup
5 Posts 2 Posters 5.0k 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.
  • M Offline
    M Offline
    maximo
    wrote on 25 Nov 2015, 01:42 last edited by
    #1

    Can you point me to some tutorials for the following thing?

    I've made my first Qt5.5 app for the Mac. However, because it's including the embedded webkit, it's going to be a little large on the install. I need to learn how to make a PKG setup that is a small initial download. Then, when one runs the PKG setup, it downloads the "payload" part of the setup (the bulky part such as the webkit part).

    I can't use a DMG because I need to use a post-install Bash script to set some things up in root mode, which I understand a PKG setup can allow you to do, but a DMG cannot. (I am under NDA at the moment and cannot explain what my application is -- but it needs powerful permissions. All I can say is that it's in the software utility market.)

    M 1 Reply Last reply 26 Nov 2015, 10:05
    0
    • S Offline
      S Offline
      SGaist
      Lifetime Qt Champion
      wrote on 25 Nov 2015, 22:17 last edited by
      #2

      Hi,

      You have more information about it in Xcode's documentation here

      Hope it helps

      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
      1
      • M maximo
        25 Nov 2015, 01:42

        Can you point me to some tutorials for the following thing?

        I've made my first Qt5.5 app for the Mac. However, because it's including the embedded webkit, it's going to be a little large on the install. I need to learn how to make a PKG setup that is a small initial download. Then, when one runs the PKG setup, it downloads the "payload" part of the setup (the bulky part such as the webkit part).

        I can't use a DMG because I need to use a post-install Bash script to set some things up in root mode, which I understand a PKG setup can allow you to do, but a DMG cannot. (I am under NDA at the moment and cannot explain what my application is -- but it needs powerful permissions. All I can say is that it's in the software utility market.)

        M Offline
        M Offline
        maximo
        wrote on 26 Nov 2015, 10:05 last edited by maximo
        #3

        I figured out how to make this work. There's no easy doc on this -- there are out of date docs all over the place, with bits of info in one not in the other. I piecemealed it all together and did enough testing to prove that I have a system that works.

        The following instructions won't likely work in the Apple Store. So, this is for distributing your application outside of that. For that, you'll probably be more straight-forward and create a payload-oriented pkg file, or a dmg file, rather than a payload-less pkg file.

        Basically, you use macdeployqt to create your .dmg of your .app, which also fills in all the necessary components your app might need. Then, you run the .dmg and drag the .app out to a folder. Zip that folder and copy it up to your web server. Then, you create what's called a "no payload" setup as a .pkg file, which has a preinstall and postinstall script that can either be Bash or Perl scripts, but because Macs also come with PHP, they could also be PHP scripts. (I’m not certain, but if Python or Ruby is shipped by default too, then I guess you could use Python or Ruby too.) You also have the option of specifying whether it requires root:wheel privilege to install this, and can specify the application title (a friendly title), as well as a welcome message, optional readme, and optional license file. So, when people download this .pkg file, it's very tiny. (You can fatten it with extra bogus stuff if you want to make it seem like it's a quality app and not a mistake.) When they run the .pkg file, you can use the preinstall and postinstall scripts to download a payload from your web server, unzip it, and put it in the Applications folder, as well as perhaps install stuff in other parts of the volume as well, and do other powerful things.

        Here are the steps:

        1. In QtCreator, build your application and run it once so that you know it’s working. Let’s assume your app is called “MyApp.app”.

        2. Go to command line and cd to inside your build directory that QtCreator made.

        3. Run this command:

        ~/Qt/5.5/clang_64/bin/macdeployqt “MyApp.app" -dmg -always-overwrite

        Note that your Qt path may be different than that. You an use which macdeployqt to determine the path.

        1. This creates a “MyApp.dmg”. Launch it and drag out the MyApp.app to a folder. Now zip this file as MyApp.app.zip and copy it up to your web server.

        2. Open the TextEdit application, ensure you are in RichText mode, and create a file welcome.rtf, readme.rtf, and license.rtf. Now, there’s a couple exceptions here. If you add an image into your welcome.rtf file, TextEdit switches it to welcome.rtfd when you go to save it -- that’s actually perfectly fine. You also don’t need a readme.rtf (or readme.rtfd), but it’s an option. Most people will likely want a license.rtf, however -- it’d be silly not to include one.

        3. Move these RTF/RTFD files into a Resources folder. You can also stick a large binary file (like a large image or .dat file) in there just to fatten this very thin install so that it looks substantial. For instance, if you’re making a graphics program, people are more likely to install something that is 5MB than something that is only 1MB.

        4. In the Resources folder, also create two very important files with no file extension: preinstall and postinstall. For now, make it easy on yourself while testing this and simply make each one do something like:

        #!/bin/bash
        
        touch /tmp/preinstall-script-was-run.txt
        # or touch /tmp/postinstall-script-was-run.txt
        

        ...however, these files will eventually be the powerful scripts to download your application from a web server, unzip it, and install it in the Applications folder. These scripts also are automatically passed 4 variables in this order:

        $0 = script path
        $1 = package path
        $2 = target path
        $3 = target volume

        1. Use the chmod command to give these script files the proper launch permission:
        chmod a+x Resources/preinstall
        chmod a+x Resources/postinstall
        
        1. Use the chown command if you want to make it such that these scripts can run under root permission like so:

        chown -R root:wheel Resources

        1. Now create a payload-less pkg file like so:

        pkgbuild --identifier com.MyCompany.MyApp --nopayload --scripts ./Resources MyApp.pkg

        ...change MyCompany and MyApp accordingly, of course.

        1. Now we need to analyze it to create what's called a Distribution.xml file out of it:

        productbuild --synthesize --package MyApp.pkg Distribution.xml

        1. Now we need to edit this Distribution.xml file because it's missing some things we need.

        Under the first OPTIONS tag, add these lines, changing the file names exactly as you named them, and the application title as it is. Do not specify folder paths -- that won't matter:

        	<title>My App</title>
        	<welcome file="welcome.rtfd"/>
        	<readme file="readme.rtf"/>
        	<license file="license.rtf"/>
        

        If you don't include a readme, then remove that line.

        Now, skip to the bottom of that file and look for the element PKG-REF with an attribute VERSION. Change the version number to the version of your application. Then, add these other two attributes to that element:

        auth="Root" installKBytes="xxx"

        ...where xxx is the actual number of kilobytes of your zipped payload when fully uncompressed off the web server.

        Thus it might look like so:

        <pkg-ref id="com.MyCompany.MyApp" version="1.0" auth="Root" installKBytes="68393" onConclusion="none">MyApp.pkg</pkg-ref>

        1. This optional step here is to edit your preinstall and postinstall scripts to do magical things like download a file off the server, unzip it, stick it in Applications, and other stuff. However, for now, you can skip that because we're just testing. Remember in step # 7 we just implemented a touch statement so that we can test things for now to prove that this works by examining our /tmp folder after installation. Note that the Apple Installer will automatically show a progress bar that will sit there until it successfully completes the preinstall and postinstall scripts -- you won't have to code that.

        2. Now that we have a working Distribution.xml file, and a working Resources folder, we can make our final package:

        productbuild --distribution Distribution.xml --resources ./Resources --package-path ./MyApp.pkg MyApp.1.01.pkg

        What this does is stuff your Distribution.xml, Resources, and MyApp.pkg file inside MyApp.1.01.pkg (where 1.01 might be your version number in this example). It also tells the package file your RTF/RTFD files.

        And there you have it! The MyApp.1.01.pkg file is already compressed, so you don't need to zip it. Just copy it up to your web server and run it. When you open your /tmp folder later, you'll see that you have those two touch files that we created as a test.

        Now that you know that this works, you can edit your preinstall and postinstall scripts to do the magical things you need with your server payload, and then follow it by doing this:

        rm MyApp.pkg
        rm MyApp.1.0.1.pkg
        chmod a+x Resources/preinstall
        chmod a+x Resources/postinstall
        chown -R root:wheel Resources
        pkgbuild --identifier com.MyCompany.MyApp --nopayload --scripts ./Resources MyApp.pkg
        productbuild --distribution Distribution.xml --resources ./Resources --package-path ./MyApp.pkg MyApp.1.01.pkg
        

        The remaining step out of this is the code-signing step on the MyApp.1.01.pkg file like so:

        • Go through the hoops on the Apple Developer site to get your developer certificate:

        https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/DistributingApplicationsOutside/DistributingApplicationsOutside.html#//apple_ref/doc/uid/TP40012582-CH12-SW2

        (Note that you'll need to change those instructions if you want to make this work in the Apple Store.)

        • Then run this:

        productsign --sign "Developer ID Installer: My Company" MyApp.1.0.1.pkg MyApp.1.0.1.signed.pkg

        You can then copy the signed pkg to another directory and rename it back to MyApp.1.0.1.pkg.

        M 1 Reply Last reply 30 Nov 2015, 00:06
        0
        • S Offline
          S Offline
          SGaist
          Lifetime Qt Champion
          wrote on 26 Nov 2015, 21:54 last edited by
          #4

          Thanks for the detailed post !

          I'd recommend that you make it a wiki article, that will make it easier to find.

          Note that using that kind of installer rules out the Apple Store.

          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
          1
          • M maximo
            26 Nov 2015, 10:05

            I figured out how to make this work. There's no easy doc on this -- there are out of date docs all over the place, with bits of info in one not in the other. I piecemealed it all together and did enough testing to prove that I have a system that works.

            The following instructions won't likely work in the Apple Store. So, this is for distributing your application outside of that. For that, you'll probably be more straight-forward and create a payload-oriented pkg file, or a dmg file, rather than a payload-less pkg file.

            Basically, you use macdeployqt to create your .dmg of your .app, which also fills in all the necessary components your app might need. Then, you run the .dmg and drag the .app out to a folder. Zip that folder and copy it up to your web server. Then, you create what's called a "no payload" setup as a .pkg file, which has a preinstall and postinstall script that can either be Bash or Perl scripts, but because Macs also come with PHP, they could also be PHP scripts. (I’m not certain, but if Python or Ruby is shipped by default too, then I guess you could use Python or Ruby too.) You also have the option of specifying whether it requires root:wheel privilege to install this, and can specify the application title (a friendly title), as well as a welcome message, optional readme, and optional license file. So, when people download this .pkg file, it's very tiny. (You can fatten it with extra bogus stuff if you want to make it seem like it's a quality app and not a mistake.) When they run the .pkg file, you can use the preinstall and postinstall scripts to download a payload from your web server, unzip it, and put it in the Applications folder, as well as perhaps install stuff in other parts of the volume as well, and do other powerful things.

            Here are the steps:

            1. In QtCreator, build your application and run it once so that you know it’s working. Let’s assume your app is called “MyApp.app”.

            2. Go to command line and cd to inside your build directory that QtCreator made.

            3. Run this command:

            ~/Qt/5.5/clang_64/bin/macdeployqt “MyApp.app" -dmg -always-overwrite

            Note that your Qt path may be different than that. You an use which macdeployqt to determine the path.

            1. This creates a “MyApp.dmg”. Launch it and drag out the MyApp.app to a folder. Now zip this file as MyApp.app.zip and copy it up to your web server.

            2. Open the TextEdit application, ensure you are in RichText mode, and create a file welcome.rtf, readme.rtf, and license.rtf. Now, there’s a couple exceptions here. If you add an image into your welcome.rtf file, TextEdit switches it to welcome.rtfd when you go to save it -- that’s actually perfectly fine. You also don’t need a readme.rtf (or readme.rtfd), but it’s an option. Most people will likely want a license.rtf, however -- it’d be silly not to include one.

            3. Move these RTF/RTFD files into a Resources folder. You can also stick a large binary file (like a large image or .dat file) in there just to fatten this very thin install so that it looks substantial. For instance, if you’re making a graphics program, people are more likely to install something that is 5MB than something that is only 1MB.

            4. In the Resources folder, also create two very important files with no file extension: preinstall and postinstall. For now, make it easy on yourself while testing this and simply make each one do something like:

            #!/bin/bash
            
            touch /tmp/preinstall-script-was-run.txt
            # or touch /tmp/postinstall-script-was-run.txt
            

            ...however, these files will eventually be the powerful scripts to download your application from a web server, unzip it, and install it in the Applications folder. These scripts also are automatically passed 4 variables in this order:

            $0 = script path
            $1 = package path
            $2 = target path
            $3 = target volume

            1. Use the chmod command to give these script files the proper launch permission:
            chmod a+x Resources/preinstall
            chmod a+x Resources/postinstall
            
            1. Use the chown command if you want to make it such that these scripts can run under root permission like so:

            chown -R root:wheel Resources

            1. Now create a payload-less pkg file like so:

            pkgbuild --identifier com.MyCompany.MyApp --nopayload --scripts ./Resources MyApp.pkg

            ...change MyCompany and MyApp accordingly, of course.

            1. Now we need to analyze it to create what's called a Distribution.xml file out of it:

            productbuild --synthesize --package MyApp.pkg Distribution.xml

            1. Now we need to edit this Distribution.xml file because it's missing some things we need.

            Under the first OPTIONS tag, add these lines, changing the file names exactly as you named them, and the application title as it is. Do not specify folder paths -- that won't matter:

            	<title>My App</title>
            	<welcome file="welcome.rtfd"/>
            	<readme file="readme.rtf"/>
            	<license file="license.rtf"/>
            

            If you don't include a readme, then remove that line.

            Now, skip to the bottom of that file and look for the element PKG-REF with an attribute VERSION. Change the version number to the version of your application. Then, add these other two attributes to that element:

            auth="Root" installKBytes="xxx"

            ...where xxx is the actual number of kilobytes of your zipped payload when fully uncompressed off the web server.

            Thus it might look like so:

            <pkg-ref id="com.MyCompany.MyApp" version="1.0" auth="Root" installKBytes="68393" onConclusion="none">MyApp.pkg</pkg-ref>

            1. This optional step here is to edit your preinstall and postinstall scripts to do magical things like download a file off the server, unzip it, stick it in Applications, and other stuff. However, for now, you can skip that because we're just testing. Remember in step # 7 we just implemented a touch statement so that we can test things for now to prove that this works by examining our /tmp folder after installation. Note that the Apple Installer will automatically show a progress bar that will sit there until it successfully completes the preinstall and postinstall scripts -- you won't have to code that.

            2. Now that we have a working Distribution.xml file, and a working Resources folder, we can make our final package:

            productbuild --distribution Distribution.xml --resources ./Resources --package-path ./MyApp.pkg MyApp.1.01.pkg

            What this does is stuff your Distribution.xml, Resources, and MyApp.pkg file inside MyApp.1.01.pkg (where 1.01 might be your version number in this example). It also tells the package file your RTF/RTFD files.

            And there you have it! The MyApp.1.01.pkg file is already compressed, so you don't need to zip it. Just copy it up to your web server and run it. When you open your /tmp folder later, you'll see that you have those two touch files that we created as a test.

            Now that you know that this works, you can edit your preinstall and postinstall scripts to do the magical things you need with your server payload, and then follow it by doing this:

            rm MyApp.pkg
            rm MyApp.1.0.1.pkg
            chmod a+x Resources/preinstall
            chmod a+x Resources/postinstall
            chown -R root:wheel Resources
            pkgbuild --identifier com.MyCompany.MyApp --nopayload --scripts ./Resources MyApp.pkg
            productbuild --distribution Distribution.xml --resources ./Resources --package-path ./MyApp.pkg MyApp.1.01.pkg
            

            The remaining step out of this is the code-signing step on the MyApp.1.01.pkg file like so:

            • Go through the hoops on the Apple Developer site to get your developer certificate:

            https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/DistributingApplicationsOutside/DistributingApplicationsOutside.html#//apple_ref/doc/uid/TP40012582-CH12-SW2

            (Note that you'll need to change those instructions if you want to make this work in the Apple Store.)

            • Then run this:

            productsign --sign "Developer ID Installer: My Company" MyApp.1.0.1.pkg MyApp.1.0.1.signed.pkg

            You can then copy the signed pkg to another directory and rename it back to MyApp.1.0.1.pkg.

            M Offline
            M Offline
            maximo
            wrote on 30 Nov 2015, 00:06 last edited by
            #5

            Some added notes from the trenches:

            • Above, I describe a small stub setup that downloads a larger payload. However, if your payload is large from the server, you're going to be looking at the screen stuck at the "Running package scripts..." notice and a jammed progress bar while it continues to download over Curl your larger payload. One solution to that in your preinstall Bash script is to do this:

            osascript -e 'tell application "System Events" to set visible of process "Installer" to false'

            That super neat trick hides the installer so that you can show something else. That way, the customer doesn't think your installer just jammed.

            Then, build yourself a simplistic ObjectiveC application that looks just like that Installer but shows a more active progress bar (use a timer) and then displays a few messages like "Downloading..." and "Finishing download..." and stuff like that. Of course, you can do it in Qt, but even the most minimum Mac-based Qt widget app (not statically compiled) is 8.9MB zipped, whereas in ObjectiveC you can make an app that does the same thing in a mere 32K (unzipped). (Oh, and for you QML die-hards out there, a widget-based app has you topped on file size. I was seeing 12.1MB zipped for something comparable in QML.)

            Once that Curl has finished, it can then kill the ObjectiveC process and reverse the osascript to get the installer to show you the Finish page.

            • If deploying a large commercial application, and especially if you need to hook up special high-permission items and require script control, then you may not want to use either the .pkg or .dmg formats at all. This is because, psychologically, customers are not likely to want to download a huge honking 200MB+ DMG or PKG file. Instead, they would be more likely to download a smaller file, run it, and then when it says Installing, it does the rest of the download steps. (I know it's the same wait time, but psychology is important in product marketing.) Take a look at Norton's Antivirus for the Mac. (There's a free trial on their website.) They basically made an ObjectiveC / Cocoa application and then zipped it. However, it's a stub setup that's very small. When you run it, it then shows the typical EULA and then starts downloading components from the web, and putting things into the appropriate places.
            1 Reply Last reply
            0

            3/5

            26 Nov 2015, 10:05

            • Login

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