SoFunction
Updated on 2025-03-04

Detailed explanation of how to use iCloud Drive to synchronize Xcode configuration

Preface

Many years ago, an old programmer told the author that code snippets are the wealth of programmers. He has a USB flash drive containing his wealth. Whenever he needs to switch computers to write code, he will deploy carefully configured fonts, themes, code snippets, etc. to the new computer and then start high-speed encoding. Every time I watch him write code, it is a pleasure, but this is another story.

need

Many years later, the author finally made up enough money to buy his own Mac, and he would write codes to commemorate his lost youth when he was free. But sometimes I always feel awkward, for example, there is a small gap between the font and the unit, or a code snippet cannot be pressed - in the end I found that this code snippet was not configured on this computer. After too many things happen, you will feel bored. Why do you have to repeat the same operation twice or three times? Or take out the USB flash drive that has been eaten for a few years and fucks it and syncs it manually on computers everywhere? Is there no way to change the application multiple times at once? The author slapped his forehead and thought of today's protagonist - iCloud Drive

1. Why use iCloud Drive?

Because this is Apple's network disk, embedded in the system, we don't need to worry about uploading and downloading as long as we turn on it. Just like OneDrive on Windows, we just need to put the file in, and it will automatically start uploading and synchronizing it on every Apple device. Using this, we can easily synchronize Xcode configuration files on different devices without manual synchronization or uploading and downloading.

2. Other alternatives

Large homosexual dating sites like GitHub

At present, I think it should be better and more convenient to use git, but it is a bit complicated to implement. Friends with ability can do it themselves

OneDrive/Nut Cloud and other network disks

I think it's better to have one with one.

Ideas

As we all know, Xcode code snippets are stored in the ~/Library/Developer/Xcode/UserData/CodeSnippets path, and there are also configuration information such as themes in nearby locations. Based on my experience, we only need to back up the three subdirectories of CodeSnippets, FontAndColorThemes and KeyBindings in the same directory. Whenever we modify code snippets, themes or shortcut keys, put the corresponding files in iCloud Drive and use the latest overwrite to the corresponding directory when on other computers.

script

Although this is the way of thinking, the author definitely dares not fool people by using such things that can be analyzed by a three-year-old child. So in order to simplify this cumbersome and mechanical operation, the author wrote a script like this:

#!/usr/bin/env bash

set -euo pipefail

################# variable define ##########
now=`date "+%Y%m%d%H%M%S"`

red=`tput setaf 1`
green=`tput setaf 2`
yellow=`tput setaf 3`
reset=`tput sgr0`

xcode_dir="${HOME}/Library/Developer/Xcode/UserData"
cloud_backup_dir="${HOME}/Library/Mobile Documents/com~apple~CloudDocs/XcodeBackup"
local_backup_dir="${HOME}/resource/Archive/XcodeBackup"

code_snippets="CodeSnippets"
font_and_color_themes="FontAndColorThemes"
key_bindings="KeyBindings"

########### MAIN ##################
# check directory exist
if [ ! -d "${cloud_backup_dir}" ]; then
 echo "${red}iCloud DriveThe backup path does not exist!${reset}"
 mkdir -p "${cloud_backup_dir}"
 echo "${green}Automatically createiCloud DriveBackup path:${reset}${cloud_backup_dir}"
 else
 echo "${green}iCloud DriveBackup path:${reset}${cloud_backup_dir}"
fi

if [ ! -d "${local_backup_dir}" ]; then
 echo "${red}本地The backup path does not exist!${reset}"
 mkdir -p "${local_backup_dir}"
 echo "${green}Automatically create本地Backup path:${reset}${local_backup_dir}"
 else
 echo "${green}本地Backup path:${reset}${cloud_backup_dir}"
fi

# zip files
cd "${xcode_dir}"
zip -r "${cloud_backup_dir}/XcodeBackup+${now}.zip" "${code_snippets}" "${font_and_color_themes}" "${key_bindings}" &
zip -r "${local_backup_dir}/XcodeBackup+${now}.zip" "${code_snippets}" "${font_and_color_themes}" "${key_bindings}" &

wait

# delete unnecessary backup files
num=`ls -l "${cloud_backup_dir}" |grep "^-"|wc -l`
if [ ${num} -gt 5 ]; then
 num=`expr ${num} - 5`
 cd "${cloud_backup_dir}"
 ls -tr "${cloud_backup_dir}" | head -${num} | xargs rm
fi

num=`ls -l "${local_backup_dir}" |grep "^-"|wc -l`
if [ ${num} -gt 5 ]; then
 num=`expr ${num} - 5`
 cd "${local_backup_dir}"
 ls -tr "${local_backup_dir}" | head -${num} | xargs rm
fi

This tedious operation is simplified, and you can achieve automatic backup by just running it while you are powered on. The function is also very simple:

  • First, two paths to backup Xcode configuration files were created, one in the cloud and the other in the local area (you can configure the local path by yourself, and generally you won't use it).
  • Then archive Xcode in one copy of each of these two places. The author chooses zip package instead of 7zip with a higher compression ratio, etc. because he wants to be more general and easy for everyone to use out of the box, and there is no need to install other software.
  • Finally, the old packages generated after multiple runs are deleted, and only the latest 5 are retained to save valuable space (after all, I am poor and I am willing to use the free 5g version)

With this script, everyone just needs to insist on running when the computer is turned on. The author likes to update cocoapods, brew, brew cask and other things every day when the computer is turned on, so I wrote a script and just backup it. The script idea is roughly as follows, because it has nothing to do with the topic, I won't explain it in detail.

#!/usr/bin/env bash

open Shadow of Magic Stockings for Yourself

wait

pod repo update --verbose &
renewHomebrew cask &
Back up various coin wallets &

BackupXcodewaitIDEConfiguration File &

wait

killall Shadow of Magic Stockings for Yourself

However, this is actually not very convenient. After all, it is very annoying to open terminal and enter commands. Do you have to manually calculate whether the configuration of this computer is the latest? Then consider whether the configuration in the cloud disk needs to be decompressed to the specified location to cover it? And it is very likely that the configuration of this computer has been uploaded to the cloud disk as the latest version before doing this.

All computers use the same version of configuration

The author thought about it again. If you can compare the last modification date of these files with the backup files, and whoever uses the new version will use, then isn't that implemented? As long as we make sure that we run the script once every time we modify it and run it once every time we turn it on, we can achieve the effect we want. As for how to determine the last modification time of a file, the author believes that only a data structure that is valued based on the key generated by the file name and the last modification time of a corresponding file (although you can also compare the backup files, but because I am very knowledgeable and do not know how to operate, I can only judge it through key-value pairs)

However, in practice, it once again demonstrates my lack of talent and knowledge. I don’t know how to create an efficient and durable key-value pair in bash. If any big shot knows, please be sure to tell the author.

Finally, the author thinks of the SQLite 3 that comes with Mac. Although such a small function database has a little anti-aircraft gun to kill mosquitoes, it is enough to run. The script is as follows;

#!/usr/bin/env bash

set -euo pipefail

################# variable define ##########
now=`date "+%Y%m%d%H%M%S"`

red=`tput setaf 1`
green=`tput setaf 2`
yellow=`tput setaf 3`
reset=`tput sgr0`

xcode_dir="${HOME}/Library/Developer/Xcode/UserData"
cloud_backup_dir="${HOME}/Library/Mobile Documents/com~apple~CloudDocs/XcodeBackup"
local_backup_dir="${HOME}/resource/Archive/XcodeBackup"

xcode_backup_database="${HOME}/Library/Mobile Documents/com~apple~CloudDocs/.BackupDatabase"

code_snippets="CodeSnippets"
font_and_color_themes="FontAndColorThemes"
key_bindings="KeyBindings"

temp="DoNotModify"
database="${xcode_backup_database}/${temp}"

########### MAIN ##################
# check directory exist
if [ ! -d "${cloud_backup_dir}" ]; then
 echo "${red}iCloud DriveThe backup path does not exist!${reset}"
 mkdir -p "${cloud_backup_dir}"
 echo "${green}Automatically createiCloud DriveBackup path:${reset}${cloud_backup_dir}"
else
 echo "${green}iCloud DriveBackup path:${reset}${cloud_backup_dir}"
fi

if [ ! -d "${local_backup_dir}" ]; then
 echo "${red}localThe backup path does not exist!${reset}"
 mkdir -p "${local_backup_dir}"
 echo "${green}Automatically createlocalBackup path:${reset}${local_backup_dir}"
else
 echo "${green}localBackup path:${reset}${cloud_backup_dir}"
fi

if [ ! -d "${xcode_backup_database}" ]; then
 echo "${red}The synchronous database path does not exist!${reset}"
 mkdir -p "${xcode_backup_database}"
 echo "${green}Automatically createDatabase path:${reset}${local_backup_dir}"
else
 echo "${green}Database path:${reset}${cloud_backup_dir}"
fi

sqlite3 "${database}" 'create table if not exists backupXcode(id integer primary key not NULL,key integer unique not NULL,value integer not NULL);'

#Get the last modification timecd "${xcode_dir}"
find "./${code_snippets}" "./${font_and_color_themes}" "./${key_bindings}" -type f >> ${temp}

while read path; do
 key=`md5 -q -s "${path}"`
 value=`stat -f "%m" "${path}"`
 isModify=`sqlite3 "${database}" "select value from backupXcode where key == '${key}';"`
 if [ -z ${isModify} ]; then
  echo "${yellow}localXcodeThe configuration has not been synchronized yet${reset}!"
  num=`ls -l "${cloud_backup_dir}" |grep "^-"|wc -l`
  if [ ${num} -ge 1 ]; then
   echo "${green}Find the latest oneXcodeConfiguration,Start automatic replacement${reset}!"
   
   cd "${xcode_dir}"
   ## backup before
   zip -r "" "${code_snippets}" "${font_and_color_themes}" "${key_bindings}" &
   wait
   
   cd "${cloud_backup_dir}"
   newBackup=`ls -t | head -1`
   
   unzip -u "${newBackup}" -d "${xcode_dir}" &
   wait
   
   cd "${xcode_dir}"
   rm ${temp}
   find "./${code_snippets}" "./${font_and_color_themes}" "./${key_bindings}" -type f >> ${temp}
   echo Update the database...
   while read path; do
    key=`md5 -q -s "${path}"`
    value=`stat -f "%m" "${path}"`
    sqlite3 "${database}" "insert or replace into backupXcode values(NULL,'${key}',${value});" &
   done < ${temp}
  fi
  break
 fi
 if [ ${isModify} != ${value} ]; then
  if [ ${isModify} -lt ${value} ]; then
   echo "${yellow}localXcodeConfiguration超前${reset}!"
  else
   echo "${yellow}localXcodeConfiguration已经过期${reset}!"
   
   num=`ls -l "${cloud_backup_dir}" |grep "^-"|wc -l`
   if [ ${num} -ge 1 ]; then
    echo "${green}Find the latest oneXcodeConfiguration,Start automatic replacement${reset}!"
    
    cd "${xcode_dir}"
    ## backup before
    zip -r "" "${code_snippets}" "${font_and_color_themes}" "${key_bindings}" &
    wait
    
    cd "${cloud_backup_dir}"
    newBackup=`ls -t | head -1`
    
    unzip -o "${newBackup}" -d "${xcode_dir}" &
    wait
   fi
  fi
  cd "${xcode_dir}"
  rm ${temp}
  find "./${code_snippets}" "./${font_and_color_themes}" "./${key_bindings}" -type f >> ${temp}
  echo Update the database...
  while read path; do
   key=`md5 -q -s "${path}"`
   value=`stat -f "%m" "${path}"`
   sqlite3 "${database}" "insert or replace into backupXcode values(NULL,'${key}',${value});"
  done < ${temp}
  break
 fi
done < ${temp}

wait
rm ${temp}

# zip files
cd "${xcode_dir}"
zip -r "${cloud_backup_dir}/XcodeBackup+${now}.zip" "${code_snippets}" "${font_and_color_themes}" "${key_bindings}" &
zip -r "${local_backup_dir}/XcodeBackup+${now}.zip" "${code_snippets}" "${font_and_color_themes}" "${key_bindings}" &

wait

# delete unnecessary backup files
num=`ls -l "${cloud_backup_dir}" |grep "^-"|wc -l`
if [ ${num} -gt 5 ]; then
 num=`expr ${num} - 5`
 cd "${cloud_backup_dir}"
 ls -tr "${cloud_backup_dir}" | head -${num} | xargs rm
fi

num=`ls -l "${local_backup_dir}" |grep "^-"|wc -l`
if [ ${num} -gt 5 ]; then
 num=`expr ${num} - 5`
 cd "${local_backup_dir}"
 ls -tr "${local_backup_dir}" | head -${num} | xargs rm
fi

postscript

The author briefly tested it and it can basically be used. With this idea, it should also be used in configuration files such as Alfred and vimrc. However, it is still not very convenient. However, I am a little bit uninformed and at this level, I hope it will be helpful to you. I wonder if you have any good suggestions? The author believes that the script can be automatically run when Xcode is closed, but the good Hook point (:"∠)_ has not been found yet. If you have any good suggestions, please welcome.PR

Okay, the above is the entire content of this article. I hope that the content of this article has a certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.