Наверное, каждый разработчик, когда начинает осваивать новую технологию, хочет опробовать все самостоятельно, реализовать все с самого низкого уровня, чтобы потом наслаждаться результатом своей работы. Однако с накоплением опыта многие задачи становятся достаточно скучными и хочется избавить себя от этой нужной, но неинтересной рутины. В этой статье я хочу поделиться тем, какие способы и средства помогут упростить жизнь разработчику и сэкономить нервы.
Настройка проекта, среды разработки, подключение библиотек, сниппеты
Это один из первых и самых легких, но все-таки существенных действий, однако про это уже написано много статей, таких как эта, эта, эта и вряд ли есть разработчик, который этого не знает, поэтому на этом останавливаться не будем. Также, для Xcode написано довольно много полезных плагинов, обзорную статью по которым можно почитать тут.
Свой репозиторий CocoaPods
Помимо подключения своих любимых или нужных для этого проекта библиотек через CocoaPods, можно добавить свой репозиторий с самыми частыми «функциями-помощниками». Например, кому не надоедает писать код следующего вида:
[self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
или
NSData *data = [responseString dataUsingEncoding:NSUTF8StringEncoding];
return [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
Чтобы избавить себя от этого, я использую на GitHub репозиторий с полезными категориями, которые сильно сократят написание кода. Воспользовавшись им, это все можно переписать следующим образом:
[self removeAllSubviews];
return responseString.JSON;
Локализация приложения
Практически всегда требуется сделать не менее двух-трех локализаций проекта. В Xcode есть для этого свои средства, и нужно отдать должное разработчикам Apple за то, что они их улучшают, но все-таки это не самый удобный способ, особенно если приложение уже в AppStore и нужно выпустить обновление — проблем хватает как с Base Internationalization, так и с Localizable.Strings. Те, кто с этим уже сталкивался, знает, что Xcode не умеет дописывать или обновлять значения в локализованных *.strings файлах для Storyboard, а также утилита genstrings ожидает на вход только новые добавленные строки, разве что мы не захотим перегенерировать все вхождения заново.
Начнем с Localizable.Strings. Я выделяю отдельный h-файл для NSLocalizedString, например StringConstants.h, в котором через #define определены локализованные строки. С помощью такого подхода можно убить сразу двух зайцев:
- Собрать общие фразы и слова, такие, как «Отмена», «Выйти», «Неверный логин или пароль» и др., которые с большой вероятностью будут присутствовать в любом проекте, так что его можно будет таскать с собой с уже готовыми строками
- Переиспользовать уже существующие строки внутри проекта, не набирая каждый раз длинный и неудобный макрос NSLocalizedString
Так, показ стандартного UIAlertView с сообщением об ошибке будет выглядеть следующим образом:
[[[UIAlertView alloc] initWithTitle:kErrorString
message:kInvalidLoginOrPasswordString
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil] show];
Что касается генерации локализованных файлов, то для этого я использую второй h-файл, NewStringConstants.h, в который добавляю те вхождения, которые необходимо локализовать, после чего удаляю их. Непосредственно в Localizable.Strings новые вхождения добавляет скрипт в Build Phases:
cd ${PROJECT_DIR}/MyProject
genstrings -a -o Base.lproj NewStringConstants.h
genstrings -a -o ru.lproj NewStringConstants.h
genstrings -a -o pt-PT.lproj NewStringConstants.h
genstrings -a -o es.lproj NewStringConstants.h
Все, что остается сделать после этого — написать локальные значения строк в Localizable.Strings-файлах.
Со Storyboard задача решается также через скрипт, который детально рассматривается в этой статье. Здесь хочу кратко упомянуть, что суть работы скрипта заключается в том, что он извлекает строки из Storyboard с помощью утилиты ibtool, и при вызове проверяется, не произошло ли каких изменений. При наличии последних делается экспорт локализованных строк, после чего локализованные файлы мержатся. Опять-таки остается подправить локализованные файлы. Также хочу упомянуть про инструмент AppleGlot, про который говорится в приведенной выше статье, однако он использует другой подход в итеративном обновлении локализации. Выбор конкретного инструмента остается за разработчиком в зависимости от его предпочтений.
Тестирование приложения
Здесь речь пойдет о ручном тестировании приложения в условиях ограниченного количества устройств. Как бы много кода не было покрыто юнит-тестами, нельзя исключать ручное тестирование. В основном этим занимается сам разработчик во время создания приложения, но когда оно готово, необходимо передать приложение обычному пользователю, у которого не «замылен» глаз и который будет использовать приложение как непосвященный во все тонкости работы среднестатистический пользователь. Хорошо, если в наличии имеется весь набор устройств со всеми поддерживаемыми операционными системами, однако в основном это не так. Даже если есть вся линейка устройств, то, как правило, разнообразием операционных систем они не отличаются, что в основном, конечно, и не нужно, но проверить не помешает. На помощь придет симулятор iOS, который можно настроить путем выбора нужного элемента из выпадающего меню. Однако, без дополнительных действий тестировщику придется передавать исходные коды, что не всегда приемлемо. Далее я опишу, как можно передать собранное приложение для тестирования на iOS симуляторе и какое нужно установить для этого дополнительное ПО.
Установка sim_launcher и ios-sim
gem install sim_launcher
brew install ios-sim
sim_launcher позволяет запускать iOS приложения в симуляторе через HTTP GET запросы. Это удобно тем, что всю организационную работу для тестирования можно организовать в браузере, не заставляя пользователя запоминать команды терминала. ios-sim представляет из себя некую обертку над командами терминала, упрощая работу с симулятором. Похоже, что sim_launcher не обновляется уже некоторое время, поэтому с последней версией ios-sim он не совместим. Необходимо исправить следующие функции в файле simulator.rb, находящийся в папке установки sim_launcher:
def start_simulator(sdk_version, device_family)
sdk_version ||= SdkDetector.new(self).latest_sdk_version
run_synchronous_command( :start, '--devicetypeid', sdk_version, '--exit' )
end
def launch_ios_app(app_path, sdk_version, device_family, app_args = nil)
if problem = SimLauncher.check_app_path( app_path )
bangs = '!'*80
raise "n#{bangs}nENCOUNTERED A PROBLEM WITH THE SPECIFIED APP PATH:nn#{problem}n#{bangs}"
end
sdk_version ||= SdkDetector.new(self).latest_sdk_version
args = ["--args"] + app_args.flatten if app_args
run_synchronous_command( :launch, app_path, '--devicetypeid', sdk_version, '--exit', *args )
end
Запуск билда на симуляторе
sim_launcher
Эта команда поднимает веб сервис на 8881 порту. Указав вместо <path-to-app> полный путь к .app-файлу, необходимо перейти в браузере по адресу http://localhost:8881/launch_iphone_app?sdk=com.apple.CoreSimulator.SimDeviceType.iPhone-6,%208.1&app_path=<path-to-app>. Если откроется симулятор iPhone 6 c iOS 8.1, значит все работает исправно. В случае, если в окне браузера появились какие-то ошибки, то, скорее всего, что-то не так с исходниками sim_launcher, либо .app файл не поддерживает работу в симуляторе. Сделать сборку для симулятора можно с помощью следующей команды:
xcodebuild -workspace MyProject.xcworkspace -scheme MyProject -arch i386 -sdk iphonesimulator
Последние штрихи
Запуск симулятора из браузера удобен, однако вручную набирать адрес не очень здорово. Можно сверстать небольшую html-страницу, которая бы предоставляла некоторый удобный UI тестировщику. Самая простая реализация выглядит следующим образом:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Testing utility</title>
</head>
<body>
<form action="http://localhost:8881/launch_iphone_app" method="get" target="_blank">
<p><select name="sdk" size="15">
<option disabled>Select a device</option>
<option value="com.apple.CoreSimulator.SimDeviceType.iPhone-4s, 7.1">iPhone 4s iOS 7.1</option>
<option value="com.apple.CoreSimulator.SimDeviceType.iPhone-5, 7.1">iPhone 5 iOS 7.1</option>
<option value="com.apple.CoreSimulator.SimDeviceType.iPhone-5s, 7.1">iPhone 5s iOS 7.1</option>
<option value="com.apple.CoreSimulator.SimDeviceType.iPad-2, 7.1">iPad 2 iOS 7.1</option>
<option value="com.apple.CoreSimulator.SimDeviceType.iPad-Retina, 7.1">iPad Retina iOS 7.1</option>
<option value="com.apple.CoreSimulator.SimDeviceType.iPad-Air, 7.1">iPad Air iOS 7.1</option>
<option value="com.apple.CoreSimulator.SimDeviceType.iPhone-4s, 8.1">iPhone 4s iOS 8.1</option>
<option value="com.apple.CoreSimulator.SimDeviceType.iPhone-5, 8.1">iPhone 5 iOS 8.1</option>
<option value="com.apple.CoreSimulator.SimDeviceType.iPhone-6-Plus, 8.1">iPhone 6 Plus iOS 8.1</option>
<option value="com.apple.CoreSimulator.SimDeviceType.iPhone-6, 8.1">iPhone 6 iOS 8.1</option>
<option value="com.apple.CoreSimulator.SimDeviceType.iPad-Retina, 8.1">iPhad Retina iOS 8.1</option>
<option value="com.apple.CoreSimulator.SimDeviceType.iPad-Air, 8.1">iPad Air iOS 8.1</option>
</select></p>
<p><input name="app_path"/></p>
<p><input type="submit" value="Run"/></p>
</form>
</body>
</html>
Список симуляторов, которые на данный момент доступны для запуска через ios-sim, можно получить с помощью команды
ios-sim showdevicetypes
Нарезка дизайна
Думаю, что немало iOS-разработчиков параллельно еще являются если не опытными, то довольно продвинутыми пользователями Adobe Photoshop, так как порой приходится что то дорабатывать или экспортировать из макетов. Для нарезки элементов интерфейса можно подключить скрипт, который будет это делать в пару кликов.
Публикация приложения
Для хорошего оформления страницы приложения в AppStore, его необходимо снабдить соответствующими скриншотами. Помимо необходимости делать их для каждого поддерживаемого устройства, необходимо также позаботиться о всех локализациях. Без автоматизации этот процесс также несет в себе боль много рутиной работы. На сайте fastlane.tools приведена схема автоматизации многих процессов, связанных как с тестированием, непрерывной интеграцией, а также публикацией приложения. Все исходные коды выложены в открытом доступе, а также есть инструкция к ним. Здесь же хочу лишь прокомментировать часть по работе со скриншотами. Воспользовавшись UI Automation подготавливается скрипт, который симулятор будет выполнять в автоматическом режиме, в нужных местах которого необходимо добавить команду создания скриншота. Поддерживаются отдельные скрипты для телефонов и планшетов. Все скриншоты сортируются по локализациям и складываются в отдельные папки, а также генерируется обзорная html-страница. С помощью другого скрипта все скриншоты можно загрузить в iTunesConnect также без участия пользователя. Таким образом, остается только настроить параметры.
На этом я бы хотел завершить эту статью. Надеюсь, она будет полезна не только тем, кто только начал осваивать или интересуется прелестями iOS-разработки, но и опытным разработчикам, которые, возможно, не знали, что много скучной работы можно поручить компьютеру, оставив себе самую интересную разработку. В комментариях предлагаю обсудить, если есть, другие инструменты и способы для ускорения или упрощения каких-то задач.
Автор: azat92