#!/bin/bash ################################################################################################### # Script Name: Manage-AndroidSDKCMDLineTools.sh # By: Zack Thompson / Created: 2/19/2021 # Version: 1.2.0 / Updated: 3/31/2021 / By: ZT # # Description: This script allows you to perform the initial configuration of the Android Studio # Environment using a custom SDK location which enables easier remote management of the SDK. # Also supports updating and installing SDK components. # # Note: The initial configuration logic assumes that Android Studio (GUI) has not been launched. # If it has, existing settings will not be overwritten, but other configurations will be performed. # ################################################################################################### echo "***** Manage AndroidSDKCMDLineTools process: START *****" ################################################## # Script Parameters # Action options are: # setup: perform initial setup before or after installing the CLI Tools # update: perform actions to update currently installed components action=$( echo "${4}" | /usr/bin/awk '{print tolower($0)}' ) shared_location="${5}" # default: "/Users/Shared/Android" sdk_components_to_install="${6}" gui_enable_auto_update_checks=$( echo "${7}" | /usr/bin/awk '{print tolower($0)}' ) # options are: "true" (default) or "false" gui_update_channel=$( echo "${8}" | /usr/bin/awk '{print tolower($0)}' ) # "release" (aka stable; default) launch_agent_label="${9}" default_launch_agent_label="com.github.mlbz521.AndroidStudioEnvironmentVariables" launch_agent_location="/Library/LaunchAgents/${launch_agent_label}.plist" ################################################## # Define Variables # Get OS Version Details os_version=$( /usr/bin/sw_vers -productVersion ) os_major_version=$( echo "${os_version}" | /usr/bin/awk -F '.' '{print $1}' ) os_minor_patch_version=$( echo "${os_version}" | /usr/bin/awk -F '.' '{print $2"."$3}' ) # Get the Console User console_user=$( /usr/sbin/scutil <<< "show State:/Users/ConsoleUser" | /usr/bin/awk '/Name :/ && ! /loginwindow/ { print $3 }' ) # Get the Console Users' UniqueID console_uid=$( /usr/bin/id -u "${console_user}" ) exit_code=0 ################################################## # Functions configure_updates() { # Configures the updates.xml file to configure the updates settings # Removed if statement since we're using bash and can't easily update XML # if [[ ! -x "${shared_location}/config/options/updates.xml" ]]; then echo "Configuring: ${shared_location}/config/options/updates.xml" /bin/cat > "${shared_location}/config/options/updates.xml" << EOF EOF /usr/sbin/chown root:wheel "${shared_location}/config/options/updates.xml" /bin/chmod 777 "${shared_location}/config/options/updates.xml" # fi } # Install the passed SDK Components install_components() { echo "Installing SDK components..." echo " -> ${1}" # shellcheck disable=SC2086 install_exit_status=$( "${shared_location}/sdk/cmdline-tools/latest/bin/sdkmanager" --install $1 ) install_exit_check=$? if [[ $install_exit_check != 0 ]]; then echo "ERROR: Encountered error while installing components:" echo "${install_exit_status}" exit_code=1 fi } ################################################## # Bits staged... # Check if an action was supplied if [[ -z "${action}" ]]; then echo "ERROR: An \`action\` wasn't provided" echo "***** Manage AndroidSDKCMDLineTools process: FAILED *****" exit 1 fi # Set default values if not supplied if [[ -z "${shared_location}" ]]; then shared_location="/Users/Shared/Android" fi # Perform initial setup before or after installing the CLI Tools if [[ "${action}" == "setup" ]]; then # Set defaults if not passed if [[ -z "${gui_enable_auto_update_checks}" ]]; then gui_enable_auto_update_checks="true" fi if [[ -z "${gui_update_channel}" ]]; then gui_update_channel="release" fi if [[ -z "${launch_agent_label}" ]]; then launch_agent_label="${default_launch_agent_label}" launch_agent_location="/Library/LaunchAgents/${launch_agent_label}.plist" fi if [[ ! -d "${shared_location}" ]]; then # shellcheck disable=SC2174 /bin/mkdir -p -m 775 "${shared_location}" fi /usr/sbin/chown root:staff "${shared_location}" # Configure the idea.properties file if [[ ! -x "${shared_location}/idea.properties" ]]; then echo "Creating: ${shared_location}/idea.properties" /bin/cat > "${shared_location}/idea.properties" << EOF # Custom Android Studio properties idea.config.path=$shared_location/config idea.system.path=$shared_location/system idea.plugins.path=$shared_location/config/plugins idea.log.path=$shared_location/system/log EOF /usr/sbin/chown root:wheel "${shared_location}/idea.properties" /bin/chmod 755 "${shared_location}/idea.properties" fi if [[ ! -d "${shared_location}/config/options" ]]; then # shellcheck disable=SC2174 /bin/mkdir -p -m 775 "${shared_location}/config/options" /usr/sbin/chown root:staff "${shared_location}/config/options" /bin/chmod 775 "${shared_location}/config" fi # Create the androidStudioFirstRun.xml file to prevent the import and setup wizard if [[ ! -x "${shared_location}/config/options/androidStudioFirstRun.xml" ]]; then echo "Creating: ${shared_location}/config/options/androidStudioFirstRun.xml" /bin/cat > "${shared_location}/config/options/androidStudioFirstRun.xml" << EOF 1 EOF /usr/sbin/chown root:wheel "${shared_location}/config/options/androidStudioFirstRun.xml" /bin/chmod 777 "${shared_location}/config/options/androidStudioFirstRun.xml" fi if [[ ! -x "${shared_location}/config/options/updates.xml" ]]; then # Function configure_updates "${gui_enable_auto_update_checks}" "${gui_update_channel}" fi # Agree to Licenses yes | "${shared_location}/sdk/cmdline-tools/latest/bin/sdkmanager" --licenses > /dev/null 2>&1 # Create a LaunchAgent to set the Environment Variables for GUI Apps echo "Creating: ${launch_agent_location}" /bin/cat > "${launch_agent_location}" << EOF Label $launch_agent_label ProgramArguments sh -c launchctl setenv ANDROID_SDK_ROOT $shared_location/sdk; launchctl setenv STUDIO_PROPERTIES $shared_location/idea.properties; launchctl setenv STUDIO_JDK /Applications/Android\ Studio.app/Contents/jre/jdk/Contents/Home; launchctl setenv ANDROID_PREFS_ROOT $shared_location/.android; launchctl setenv GRADLE_USER_HOME $shared_location/.gradle RunAtLoad EOF /usr/sbin/chown root:wheel "${launch_agent_location}" /bin/chmod 644 "${launch_agent_location}" if [[ -z "${console_uid}" || "${console_user}" == "loginwindow" ]]; then echo "Notice: A console user is not currently logged in, will not attempt to bootstrap the LaunchAgent" else if [[ -e "${launch_agent_location}" ]]; then # Check if the LaunchDaemon is running before loading it again. # Determine proper launchctl syntax based on OS Version. # macOS 11+ or macOS 10.11+ if [[ $( /usr/bin/bc <<< "${os_major_version} >= 11" ) -eq 1 || ( "${os_major_version}" == 10 && $( /usr/bin/bc <<< "${os_minor_patch_version} >= 11" ) -eq 1 ) ]]; then launchctl_exit_code=$( /bin/launchctl print gui/"${console_uid}"/"${launch_agent_label}" > /dev/null 2>&1; echo $? ) if [[ $launchctl_exit_code == 0 ]]; then echo "Stopping agent: ${launch_agent_location}" /bin/launchctl bootout gui/"${console_uid}"/"${launch_agent_label}" fi echo "Starting agent: ${launch_agent_location}" /bin/launchctl bootstrap gui/"${console_uid}" "${launch_agent_location}" /bin/launchctl enable gui/"${console_uid}"/"${launch_agent_label}" # macOS 10.x - macOS 10.10 elif [[ "${os_major_version}" == 10 && $( /usr/bin/bc <<< "${os_minor_patch_version} <= 10" ) -eq 1 ]]; then launchctl_exit_code=$( /bin/launchctl asuser "${console_uid}" /bin/launchctl list "${launch_agent_label}" > /dev/null 2>&1; echo $? ) if [[ $launchctl_exit_code == 0 ]]; then echo "Stopping agent: ${launch_agent_location}" /bin/launchctl asuser "${console_uid}" /bin/launchctl unload "${launch_agent_location}" fi echo "Starting agent: ${launch_agent_location}" /bin/launchctl asuser "${console_uid}" /bin/launchctl load "${launch_agent_location}" /bin/launchctl asuser "${console_uid}" /bin/launchctl start "${launch_agent_location}" fi fi fi # If supplied, install the passed components if [[ -n "${sdk_components_to_install}" ]]; then # Function install_components "${sdk_components_to_install}" fi # Perform update actions elif [[ "${action}" == "update" ]]; then # If supplied, configure the update settings if [[ -n "${gui_enable_auto_update_checks}" && -n "${gui_update_channel}" ]]; then # Function configure_updates "${gui_enable_auto_update_checks}" "${gui_update_channel}" fi # If supplied, install the passed components if [[ -n "${sdk_components_to_install}" ]]; then # Function install_components "${sdk_components_to_install}" fi # Update installed components echo "Updating SDK components..." update_exit_status=$( "${shared_location}/sdk/cmdline-tools/latest/bin/sdkmanager" --update ) update_exit_check=$? if [[ $update_exit_check != 0 ]]; then echo "ERROR: Encountered error while updating components:" echo "${update_exit_status}" exit_code=1 fi else echo "ERROR: An unknown \`action\` was provided: ${action}" echo "***** Manage AndroidSDKCMDLineTools process: FAILED *****" exit 2 fi if [[ $exit_code != 0 ]]; then echo "***** Manage AndroidSDKCMDLineTools process: FAILED *****" exit 3 fi echo "***** Manage AndroidSDKCMDLineTools process: COMPLETE *****" exit 0