В developer подписках Apple есть возможность разрабатывать приложения для внутрекорпоротивного использования. При этом приложения не проходят проверку со стороны Apple и не обязаны «светится» в AppStore. Всё выше сказанное относится и к Ad Hoc приложениям, они принципиально ничем не отличаются, разве что временем жизни после создания.
Для распространения приложения хотелось решить задачи:
- пользователь самостоятельно мог установить приложение на свое устройство
- только авторизированный пользователь мог устанавливать приложение
- простая публикация приложения на сервере
Опишу, как реализовывали и какие были трудности.
1.
С первым пунктом всё понятно, есть информация на эту тему. Т.е. создаем правильную ссылку на plist файл, а в нем должна быть волшебная ссылка на ipa архив приложения.
2.
Второй пункт казался не такой и сложной проблемой: создаем страницу аутентификации и авторизируем пользователя. Далее выдаем ему ссылку на установку/обновление приложения. PROFIT.
На деле оказалось всё не так просто. Сессия между Safari (я не говорю уже о других браузерах) и AppStore не шарится. Немного подумав можно и этот вопрос решить – сделать сессионные ключи и передавать их в параметрах ссылки. Просто делаем аналог куки, которые передаются GET'ом и имеют ограничения по времени жизни/количество раз использования. Далее меня ждал еще один маленький нюанс. По задумке ссылка на plist выглядела примерно так: httр://example.com/getapp?key=F00DBEE&type=plist, для получения самого приложения параметр type=ipa. Оказалось, что при обработке ссылок устройство учитывает только первый параметр, остальные попросту отбрасывает – обидно. Но где наше не пропадало – все интересующие данные можно и в один параметр сложить.
Стоит обратить внимание еще на одну мелочь – перед тем как получить приложение AppStore делает запрос на сервер методом HEAD, а только потом скачивает сам фал GET'ом. В связи с этой хитрой хитростью у меня сессия «протухала» тогда когда не надо. Да само приложение выплевывалось два раза, т.к. привык для контента использовать HEAD === GET.
3.
Уменьшение количества данных для публикации = уменьшение ошибок третьей стороны. В идеальном случае, что бы в обновлении фигурировал один файл приложения — ipa, но пользователю, зачастую, хочется знать, какие изменения были в приложение. Так что остановились на варианте ipa + описание изменений.
Для установки приложения нужен plist, в котором описаны предустановочные свойства. Этот XML файл выглядит абсолютно одинаково (с разницей в значениях параметров) для разных приложений.
<?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>items</key>
<array>
<dict>
<key>assets</key>
<array>
<!-- обязательный. Ссылка на приложение -->
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>__URL__</string>
</dict>
<!-- не обязательный, иконка, которая показывается
в момент скачивания приложения.
При отсутствии будет серый квадрат -->
<dict>
<key>kind</key>
<string>display-image</string>
<key>needs-shine</key>
<false/>
<key>url</key>
<string>__SMALL_IMAGE__</string>
</dict>
</array>
<key>metadata</key>
<dict>
<!-- обязательный. внутренний
идентификатор приложения -->
<key>bundle-identifier</key>
<string>__IDENTIFIER__</string>
<!-- обязательный. Версия сборки приложения -->
<key>bundle-version</key>
<string>__VERSION__</string>
<key>kind</key>
<string>software</string>
<!-- обязательный. Наименование приложения -->
<key>title</key>
<string>__TITLE__</string>
</dict>
</dict>
</array>
</dict>
</plist>
Данные параметры можно получить из другого plist, находящегося в недрах ipa-файла (который является zip архивом) приложения — Info.plist. Недостаток только в том, что он бинарный. В MacOS есть хорошая консольная утилита plutil для конвертации форматов plist'ов, но не у всех на серверах стоят MacOS.
Решить эту проблему можно путем написания своего конвертера, либо собрать нативное приложение, либо воспользоваться Perl скриптом, Windows можно поставить приложения от Apple и найти консольную утилиту по адресу «C:Program Files (x86)Common FilesAppleApple Application Support». Вариант со своей реализацией заманчив, но дорог. Я воспользовался Perl'ом. После конвертации бинарного plist получаем примерно такой XML:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
<string>14D73</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>MyApp</string>
<key>CFBundleExecutable</key>
<string>MyApp</string>
<key>CFBundleIcons</key>
<dict>
<key>CFBundlePrimaryIcon</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>i57.png</string>
<string>i114.png</string>
</array>
</dict></dict>
<key>CFBundleIdentifier</key>
<string>com.company.MyApp.ios</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>MyApp</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneOS</string>
</array>
<key>CFBundleVersion</key>
<string>1.0.3</string>
<!--
еще много ключей и их значений, который в данной статье не интересны
-->
</dict>
</plist>
Из описания нам интересны: CFBundleVersion, CFBundleIdentifier, CFBundleDisplayName. Это наименование, версия, идентификатор приложения соответственно. Можно бонусом еще и иконку вытянуть. Для получения значений используем такой XPath /plist/dict/key[contains(text(),'__KEY__
')]/following-sibling::string[1]/text() где __KEY__
необходимые ключи.
Таким образом можно распространять не только Enterprise, но и AdHoc без особых проблем.
Обновление приложения.
Следить за обновлением приложения должно само приложение, т.к. оно не является частью AppStore. Да и вообще за приложением b2b нужно следить очень внимательно, оно еще может не перенестись с одного устройства на другое при дампе через iTunes. Для непосредственного обновления приложения из самого приложения необходимо открывать в Safari волшебную ссылку на манифест (plist) файл, которая начинается так itms-services://?action=download-manifest&url=.
В качестве заключения.
В данной реализации, быть может, только один костыль — использование стороннего приложения для чтения info.plist, остальные «телодвижения» можно совершить без особых проблем на всех (большинстве) платформ/технологий и т.д.
Автор: wlw