Issues With Building a MacOS Package That Contains Other Packages and Scripts

I’m sorry this might be long, but it seems that this process is extremely precise and so I want to provide as much detail as possible to help you understand how I got here. I’m really stuck and desperately need some guidance on this. I’ll give you a high-level overview of what I’m trying to achieve, and then show you what I have so far.

So my goal is to take an existing .Net project that’s essentially just security software running a service as a daemon, and effectively to get it running on Mac. This involves building an installer for Mac, because the service that will be running in the background as a daemon needs to check a specific file path for a JSON file that’s created during the installer. The JSON file is created via a Swift app that I wrote. The app simply displays a dialog that asks for the user’s email address, first name and last name, and it also generates a unique device ID. When the user submits this form dialog, the swift app generates a JSON file and stores it at a specific file path that the .Net service knows where to find it when it launches. So to interject the installer with a Swift dialog, I created a preinstall script that basically just launches the .app file I created by archiving my Swift app in Xcode. When I run this script independently, it works as it should and as long as the .app file is where it should be, which is in root of my project directory. When I test the script independently, it launches the app and the dialog is presented, creates the JSON file and exits as it should. I’ve also resolved all signing and notarization issues and have confirmed that each sub-package can be executed without GateKeeper warnings on a fresh Mac. My issue is that when I build my final package using productbuild, the scripts are never executed and the logs found at /var/log/install.log give no indication that the scripts are running or even referenced in any way. Here is my file structure:

enter image description here

The files highlighted in blue are what I started with. Everything EXCEPT NetarxInstallationDialog.app and Poseidon.svc.zip were generated when publishing our .NET project. Poseidon.svc is the service I ultimately need to run as a daemon. NetarxInstallationDialog.app is my Swift project that was archived, signed and notarized already. I’ve confirmed that this was done correctly, as it runs just fine on a fresh Mac. So from this starting point (assume just the files in blue existed at the time):

First I zipped Poseidon.svc so I could notarize it. I ran:

zip -r Poseidon.svc.zip Poseidon.svc

Which produced Poseidon.svc.zip. Then I ran:

xcrun notarytool submit Poseidon.svc.zip --keychain-profile “Netarx” --wait

This succeeded with no issues.

Then I built a package for Poseidon.svc:

pkgbuild --root ./ --identifier "com.netarx.poseidon" --version "1.0.0" --install-location "/Library/Application Support/Netarx" --sign "Developer ID Installer: xxx xxxx (xxxxxxxxxx)" Poseidon.pkg

This produced the file Poseidon.pkg, then to sign the package I ran:

productsign --sign "Developer ID Installer: xxx xxxx (xxxxxxxxxx)" --timestamp Poseidon.pkg Poseidon-signed.pkg 

This produced the file Poseidon-signed.pkg, and I deleted the original Poseidon.pkg as it was no longer needed.

Then I notarized Poseidon-signed.pkg:

xcrun notarytool submit Poseidon-Signed.pkg --keychain-profile "Poseidon" --wait

This succeeded without error. Then I stapled the notarization ticket to Poseidon-signed.pkg:

xcrun stapler staple Poseidon-Signed.pkg

This succeeded without error and I’ve verified this package runs an installer with no GateKeeper warnings on a fresh Mac.

Then I built a package for my NetarxInstallationDialog.app (The swift app) so that it could be used in productbuild for the final installer:

pkgbuild --root NetarxInstallationDialog.app 
        --install-location "/Library/Application Support/Netarx/NetarxInstallationDialog.app" 
        --identifier "com.netarx.installationdialog" 
        --version "1.0.0" 
         --sign "Developer ID Installer: xxx xxxx (xxxxxxxxxx)" 
            NetarxInstallationDialog.pkg

This produced the file NetarxInstallationDialog.pkg. Since I signed this package directly within the pkgbuild command, I simply checked the signature using pkgutil and confirmed it was good. Then I notarized NetarxInstallationDialog.pkg:

xcrun notarytool submit NetarxInstallationDialog.pkg --keychain-profile "Poseidon" --wait

This also succeeded without error, so I then stapled the notarization ticket to NetarxInstallationDialog.pkg:

xcrun stapler staple NetarxInstallationDialog.pkg

This succeeded without error as well, and I was able to verify that this pkg also runs on a fresh Mac with no GateKeeper warning.

Since I need my swift app to launch at the beginning of the installation, before Poseidon.svc can be installed and run, I added a preinstall script:

#!/bin/sh

# Define log file
USER_NAME="$(whoami)"
LOG_FILE="/Users/${USER_NAME}/Desktop/preinstall_script.log"
echo "Starting preinstall script" > "${LOG_FILE}"

# Path to the application
APP_PATH="/Library/Application Support/Netarx/NetarxInstallationDialog.app"

# Define the JSON path
JSON_PATH="/Users/${USER_NAME}/Library/Application Support/Netarx/Validator/UserConfiguration.json"
echo "Expected JSON path: ${JSON_PATH}" >> "${LOG_FILE}"

# Check if the application exists and run it
if [ -d "$APP_PATH" ]; then
    echo "Application found, attempting to open..." >> "${LOG_FILE}"
    open "$APP_PATH"

    while [ ! -f "${JSON_PATH}" ]; do
        echo "Waiting for user input..." >> "${LOG_FILE}"
        sleep 2
    done
    echo "Configuration file found. Continuing installation..." >> "${LOG_FILE}"
else
    echo "Application not found at $APP_PATH" >> "${LOG_FILE}"
    exit 1
fi

echo "Preinstall script completed successfully" >> "${LOG_FILE}"
exit 0

This script basically is just meant to execute NetarxInstallationDialog.app and wait for the user to submit input, and then the Swift app generates a JSON file and stores it in /Users/${USER_NAME}/Library/Application Support/Netarx/Validator/UserConfiguration.json. After the file is found, the script exits with code 0.

As I said, I’ve tested this script by running it from terminal and I see NetarxInstallationDialog.app launch, and the script exit with code 0 once I submit input within the swift app. That all seems to work as expected.

I’ve also included a postinstall script, which aims to install Poseidon.svc as a launch daemon:

#!/bin/sh

# Define the source path of the .plist file
PLIST_SRC="./resources/com.netarx.poseidon.plist"

# Define the destination path
PLIST_DEST="/Library/LaunchDaemons/com.netarx.poseidon.plist"

# Debug: Check if the .plist file exists
if [ -f "$PLIST_SRC" ]; then
    echo ".plist file found, proceeding with copy and permissions settings..."
    # Copy the .plist file to the correct directory
    sudo cp "$PLIST_SRC" "$PLIST_DEST"
    
    # Set the owner and permissions
    sudo chown root:wheel "$PLIST_DEST"
    sudo chmod 644 "$PLIST_DEST"
    
    # Load the daemon
    sudo launchctl load -w "$PLIST_DEST"
else
    echo ".plist file not found at $PLIST_SRC"
fi

Here’s the plist my postinstall script references:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.netarx.poseidon</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Library/Application Support/Netarx/Poseidon.svc</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
</dict>
</plist>

Then I added a Distribution.xml file to my root directory:

<?xml version="1.0" encoding="UTF-8"?>
<installer-script minSpecVersion="1">
    <title>Your Application Installer</title>
    <options customize="allow" allow-external-scripts="no"/>
    <choices-outline>
        <line choice="default">
            <line choice="InstallNetarxDialog"/>
            <line choice="InstallPoseidon"/>
        </line>
    </choices-outline>
    <choice id="default"/>
    <choice id="InstallNetarxDialog">
        <pkg-ref id="netarx"/>
    </choice>
    <choice id="InstallPoseidon">
        <pkg-ref id="poseidon"/>
    </choice>
    <pkg-ref id="netarx" version="1.0.0" auth="Root">NetarxInstallationDialog.pkg</pkg-ref>
    <pkg-ref id="poseidon" version="1.0.0" auth="Root">Poseidon-signed.pkg</pkg-ref>
    <scripts>
        <preinstall file="resources/scripts/preinstall.sh"/>
        <postinstall file="resources/scripts/postinstall.sh"/>
    </scripts>
</installer-script>

After adding Distribution.xml to my project root directory, adding the plist to a /resources directory, and adding scripts to a /scripts directory within /resources, I ran productbuild to bundle it all together and create the final installer which I aim to distribute:

productbuild --distribution ./Distribution.xml 
             --resources resources 
             --package-path . 
             --sign "Developer ID Installer: xxx xxxx (xxxxxxxxxx)" 
             /Users/xxxxxxx/Desktop/NewPoseidon/FinalInstaller.pkg

This produces the file FinalInstaller.pkg (not pictured, but it’s in the root directory of my project with the other packages). I also signed and notarized FinalInstaller.pkg without issue and verified that it runs on another Mac without GateKeeper warnings.

The issue is that when I run this FinalInstaller.pkg, none of the scripts appear to be running. I’m not seeing my Swift app launch and not seeing Poseidon.svc installed where it should be to run as a daemon.

With all of this said, do you see anywhere I went wrong with any of this? I’ve never built an installer for Mac and I wouldn’t be surprised at all if I’m going about this incorrectly. Any help would be greatly appreciated!

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật