---
# System prepended metadata

title: Launcher/Patcher
tags: [processes]

---

# Launcher/Patcher
###### tags: `processes`
The UniVirtual Launcher/Patcher is a program that the user runs before starting the Viewer application, which verifies the integrity of their installation, downloads any new or missing files, and updates any outdated files. The design goal is to handle updates seamlessly to the user and enable a very slim initial download from a website for the user.

The base code comes from the PATCH Updating System Unity asset (https://assetstore.unity.com/packages/tools/utilities/patch-updating-system-pro-46639), with modifications added to support UniVirtual specific assets.

Once installed, on first run, the latest version of the viewer will be downloaded and installed, followed by any currently published asset files (DLLs, asset bundles). On subsequent launches, only changed files will be downloaded, streamlining the update process.

The Launcher/Patcher can also self-update, as new features are added.

## Deploy

### Windows

:::info
GitHub: https://github.com/cndgdev/dev-univirtual_launcher/
Branch: `develop`
:::

1. Build from `dev-univirtual_launcher` Visual Studio project
2. Open the Pathcer Unity Project
3. Add the new app in the folder...
4. Make a new patch from GUI instructions
5. Upload those to AWS `Amazon S3 > Buckets > univirtual > patch/ > WIN/ > Updater/`
8. Edit `builds_index.json` to direct to the current version.


### macOS

1. Build patcher Unity project on macOS
2. Run shell script on macOS terminal to sign the app (see below)
3. **TODO:: Jason should upload the patch project**
4. Add the new app in the folder...
5. Make a new patch from GUI instructions
6. This will produce a folder and a json file
7. Upload those to AWS `Amazon S3 > Buckets > univirtual > patch/ > OSX/ > Updater/`
8. Edit `builds_index.json` to direct to the current version.

```shell=
#!/bin/sh
BINARY="UniVirtual.Launcher.app"
ZIP="UniVirtual.Launcher.unsigned.zip"
ENTITLEMENTS="univirtual.entitlements"
SIGNCERT="Developer ID Application: Chant Newall Development Group LLC (ZJYBZ7K2S7)"
BUNDLE="info.cndg.univirtual.launcher"
USER="USERNAME"
PASSWORD="PASSWORD"
VENDOR="ZJYBZ7K2S7"


find "./$BINARY" -name "*.meta" -type f -exec rm {} \;

libfile=`find ./$BINARY -path "./$BINARY/Contents/Resources" -prune -false -o -name '*.dylib'`
while read -r libname; do
        echo "Sign:" $libname
        codesign --deep --force --verify -vvvv --timestamp --options runtime --entitlements  $ENTITLEMENTS --sign "$SIGNCERT" "$libname"
done <<< "$libfile"

bundlefile=`find ./$BINARY -path "./$BINARY/Contents/Resources" -prune -false -o -name '*.bundle'`
while read -r bundlename; do
        echo "Sign:" $bundlename
        codesign --deep --force --verify -vvvv --timestamp --options runtime --entitlements  $ENTITLEMENTS --sign "$SIGNCERT" "$bundlename"
done <<< "$bundlefile"

frameworkfile=`find ./$BINARY -path "./$BINARY/Contents/Resources" -prune -false -o -name '*.framework'`
while read -r frameworkname; do
        echo "Sign:" $frameworkname
        codesign --deep --force --verify -vvvv --timestamp --options runtime --entitlements  $ENTITLEMENTS --sign "$SIGNCERT" "$frameworkname"
done <<< "$frameworkfile"

binaryfile=`find ./$BINARY/Contents/MacOS -type f`
while read -r binaryname; do
        echo "Sign:" $binaryname
        codesign --deep --force --verify -vvvv --timestamp --options runtime --entitlements  $ENTITLEMENTS --sign "$SIGNCERT" "$binaryname"
done <<< "$binaryfile"


ditto -c -k --sequesterRsrc --keepParent "$BINARY" "$ZIP"

#xcrun altool --notarize-app --username $USER --password $PASSWORD --asc-provider $VENDOR --primary-bundle-id $BUNDLE --file $ZIP

# functions
requeststatus() { # $1: requestUUID
    requestUUID=${1?:"need a request UUID"}
    req_status=$(xcrun altool --notarization-info "$requestUUID" \
                              --username "$USER" \
                              --password "$PASSWORD" 2>&1 \
                 | awk -F ': ' '/Status:/ { print $2; }' )
    echo "$req_status"
}

# upload file
echo "## uploading $ZIP for notarization"
requestUUID=$(xcrun altool --notarize-app \
                           --primary-bundle-id "$BUNDLE" \
                           --username "$USER" \
                           --password "$PASSWORD" \
                           --asc-provider "$VENDOR" \
                           --file "$ZIP" 2>&1 \
              | awk '/RequestUUID/ { print $NF; }')
                           
echo "Notarization RequestUUID: $requestUUID"

if [[ $requestUUID == "" ]]; then 
    echo "could not upload for notarization"
    exit 1
fi
    
# wait for status to be not "in progress" any more
request_status="in progress"
while [[ "$request_status" == "in progress" ]]; do
    echo "waiting... "
    sleep 10
    request_status=$(requeststatus "$requestUUID")
    echo "$request_status"
done

# print status information
xcrun altool --notarization-info "$requestUUID" \
             --username "$USER" \
             --password "$PASSWORD"
echo 

if [[ $request_status != "success" ]]; then
    echo "## could not notarize $BINARY"
    exit 1
fi

# staple result
echo "## Stapling $BINARY"
xcrun stapler staple "$BINARY"

echo '## Done!'

exit 0

```