Automating iPhone & iPad Deployment

The iPhone Configuration Utility is used to “image” iPhone, iPad and iPod Touch. The reason I quoted image was because you aren’t laying bits down as you would in a traditional imaging scenario. Instead, you are sending a profile and possibly some applications to the device. This is done through a configuration profile, which is a property list, prefixed with a .mobileconfig extension.

The iPhone Configuration Utility stores its data in the ~/Library/MobileDevice directory. Here, you will find two directories:

  • Devices – Contains the Device data for each device that has been docked to the iPhone Configuration Utility.
  • Configuration Profiles – Contains the profiles that you will assign to devices in the form of .mobileconfig plists.

Both of these can be managed from the command line and therefore generated en masse. First, let’s look at creating Devices. If you go into the Devices directory you will see a .deviceinfo file for each device that you have interacted with through iPhone Configuration Utility, prefixed by the UDID of the device. Here, you can view one as a standard property list, which appears in a very simplistic fashion as follows:

<?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>UniqueChipID</key>
<integer>0</integer>
<key>applicationDictionaries</key>
<array/>
<key>configurationProfiles</key>
<array/>
<key>deviceActivationState</key>
<string>WildcardActivated</string>
<key>deviceBuildVersion</key>
<string>7E18</string>
<key>deviceCapacityKey</key>
<integer>15333203968</integer>
<key>deviceIdentifier</key>
<string>12a0b688649cfe0ce5df2ab8b4f9eaaee0d000fc</string>
<key>deviceLastConnected</key>
<date>2010-05-27T00:17:17Z</date>
<key>deviceName</key>
<string>Charles Edge’s iPhone</string>
<key>devicePhoneNumber</key>
<string>1 (310) 555-1212</string>
<key>deviceProductVersion</key>
<string>3.1.3</string>
<key>deviceSerialNumber</key>
<string>12345678901</string>
<key>deviceType</key>
<string>iPhone</string>
<key>provisioningProfiles</key>
<array/>
</dict>
</plist>
To find a UDID, you can plug a device into iTunes, select the device from the Devices list and then click on the Summary tab. Here, you can click on the bold Software Version to see the Build version, the bold Phone Number to see the IMEI (first click) or ICCID (second click) and the bolded Serial Number to see the Identifier (or UDID).
The serial number can also be obtained from a bar code on the box that came with the device, although the UDID cannot at this time. The serial though can then be brought into a database that has both, to correlate them (assuming you are programmatically going to wrangle this data at a later time) and assign profiles based on, for example, Open Directory or Active Directory group membership of the primary user.
You can copy a template file without unique identifiers and then use defaults to put the unique data into the file. Or you can use a series of defaults commands with plistbuddy to create a file from scratch. The data can then be viewed in somewhat of a 2d fashion up to this point. The problem is then come in the arrays, which in conjunction with the fact that they reference data from the mobileconfig files we’ll look at in a moment, mean that you are using localized plists to form a relational context to data.
You can then look at a .mobileconfig file, which appears in a very simplistic form as follows:
<?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>PayloadContent</key>
<array>
<dict>
<key>FullScreen</key>
<false/>
<key>IsRemovable</key>
<true/>
<key>Label</key>
<string></string>
<key>PayloadDescription</key>
<string>Configures Web Clip</string>
<key>PayloadDisplayName</key>
<string>Web Clip</string>
<key>PayloadIdentifier</key>
<string></string>
<key>PayloadOrganization</key>
<string></string>
<key>PayloadType</key>
<string>com.apple.webClip.managed</string>
<key>PayloadUUID</key>
<string>80222944-B43C-4A43-AB93-2998CDCBE808</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>Precomposed</key>
<false/>
<key>URL</key>
<string></string>
</dict>
</array>
<key>PayloadDescription</key>
<string>Profile description.</string>
<key>PayloadDisplayName</key>
<string>Profile Name</string>
<key>PayloadOrganization</key>
<string></string>
<key>PayloadRemovalDisallowed</key>
<false/>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadUUID</key>
<string>5B0879F3-9BA9-41E7-AC8F-F4703D4400DB</string>
<key>PayloadVersion</key>
<integer>1</integer>
</dict>
</plist>
You can then create a single ,mobileconfig, make it a template and make it exactly like you want things to match up as your lowest common denominator, or template, user. Those .mobileconfig files then get applied to each device, which you could do in batches. You can also dynamically copy them to a web server and send an SMS/email to the user to click on them to apply them, or dock the device.
You can also add applications using a pre-existing array and copying it down, although if there are licensing concerns surrounding doing so it would be wise to investigate the ramifications of doing so first. Keys and such are defined in the iPhone Enterprise Deployment Guide, along with sample AppleScript for creation of files.
You can also copy the database by copying the property list files between machines. When iPhone Configuration Utility is opened it will automatically read in the new property lists and display the information. Overall, it is going to be as much work as it is to dynamically generate provisioning on the fly using the ruby sample code provided by Apple. It is still going to be the fastest path to market (and support) to go the 3rd party route, using a tool where they’ve built all of this out. The options in the iPhone Configuration Utility, along with the .mobileconfig files becomes the baseline that most 3rd party packages use, but overall they’ve done the work to build out the wrappers and if you want to roll your own you’ll essentially end up building something similar to what is currently on the market, without support (which for some environments is required).
Good luck!