Мы в Fyusion Inc разрабатываем SDK для сторонних клиентов. В этой статье я специально расскажу о разработке iOS SDK. Разработка SDK сопряжена со своими проблемами:

  • Процесс выпуска
  • Документация
  • Минимальное использование сторонних фреймворков
  • Журналы отслеживания/аналитика
  • Минималистичные общедоступные API
  • Непрерывная интеграция
  • Тестовые приложения

Процесс выпуска

Мы начали разработку нашего SDK в 2018 году. На ранних этапах и из-за первоначальных сжатых сроков мы решили поставлять наши SDK в виде обычного zip-файла. ZIP-файл будет содержать фреймворк, сгенерированный с помощью системы сборки XCode, и любую документацию по API для фреймворка. Мы используем Jazzy для автоматической генерации документации по API.

Первым очевидным шагом к изменению здесь было написание скрипта для автоматизации процесса создания фреймворка. Мы сделали что-то очень простое следующим образом:

Вышеупомянутое помогло нам создать структуру для любой цели, которую мы указываем в аргументах скрипта. Это только помогло нам создать универсальный фреймворк, но процесс создания zip по-прежнему был ручным. Создание почтового индекса также не так сложно в ruby, это можно легко сделать следующим образом:

Это помогло нам создать фреймворк, заархивированный в папку с версиями. Что теперь? Следующей задачей было сделать распространение фреймворка автоматическим. Исходя из мира iOS, первое, что приходит мне на ум, — это Cocoapods. Основная проблема с Cocoapods заключалась в том, что мы не хотели обнародовать нашу структуру. Вариантом для этого было бы поддерживать частный репозиторий GitHub и предоставлять каждому клиенту доступ к этому репозиторию. Но это не похоже на очень хороший и масштабируемый вариант. Поэтому мы решили загрузить наши фреймворки прямо на s3 в виде zip-файла, защищенного секретными ключами нашего приложения. По сути, это также создает удаленную ссылку podspec, на которую могут указывать наши клиенты. Ссылка podspec сама по себе указывает на загруженное местоположение s3 zip. После этого установка наших фреймворков для наших клиентов выполняется так же просто:

После того, как это было сделано, единственной оставшейся частью полной автоматизации было присоединение вышеуказанной части к CI. Недавно мы перешли на использование GitHub Actions и решили написать выпуск YML-файла, который автоматически инициирует упаковку фреймворка в zip-архив с использованием вышеуказанного механизма, а затем загружает его в папку s3, делая его доступным для всех наших клиентов.

Документация

При разработке SDK мы должны убедиться, что он хорошо задокументирован, а все функции хорошо объяснены пользователям нашего SDK. В основном состоит из 2 частей:

  • Документация по API. Этот тип документации обычно сопровождается общедоступными API в SDK. Мы загружаем документацию API удаленно, а также на наш веб-сайт для разработчиков и используем Jazzy для автоматического создания документации API в формате HTML.
  • Документация для разработчиков. Здесь объясняется, что мы предлагаем в нашем SDK, а также примеры кода базовой интеграции нашего SDK. Это также сопровождается другими вещами, такими как предварительные условия использования нашего SDK, любые случайные часто задаваемые вопросы, которые могут помочь разработчикам в интеграции SDK, журналы изменений с информацией о каждой выпущенной версии, примеры приложений и т. д.

Минимальное использование сторонних фреймворков

Поскольку наш SDK интегрируется нашими пользователями/клиентами в свои приложения, целесообразно использовать минимальные сторонние фреймворки. Это помогает избежать конфликтов или ошибок компиляции, если разработчик/конечный пользователь нашего SDK использует одну и ту же стороннюю платформу. Например: предположим, что мы решили использовать Crashlytics в качестве инструмента отслеживания сбоев для нашего SDK, это может вызвать проблемы при инициализации Crashlytics, используемого конечным пользователем SDK, поскольку здесь инициализация представляет собой одноэлементный шаблон. Поэтому мы не можем полагаться на сторонние фреймворки для выполнения основных задач.

Для сетевых операций мы обычно разрабатываем собственный конвейер с использованием API-интерфейсов NSURLSession, предоставляемых самой Apple. Может быть очень заманчиво использовать известный сетевой сторонний фреймворк, такой как AFNetworking или Alamofire, но это неразумно делать по причинам, описанным выше.

Журналы отслеживания/аналитика

По мере роста нашего SDK и нашей клиентской базы мы поняли, что очень важно отслеживать журналы того, как пользователь использует основные функции вашего SDK. В настоящее время мы используем CocoaLumberJack для записи журналов (которые обычно включают ошибки, предупреждения и любую отладочную информацию, которая нам может понадобиться), а затем загружаем их в s3 и визуализируем с помощью Kibana и ElasticSearch. С тех пор, как мы начали отправлять эти журналы в s3, это очень помогло отследить ошибки, о которых сообщают наши клиенты.

Все разработчики в нашей команде имеют доступ к этим журналам, и как только QA сообщает о какой-либо ошибке, мы сначала пытаемся просмотреть эти журналы и выяснить, что происходило на этом конкретном устройстве, когда возникла ошибка. Это действительно помогает нам узнать состояние используемого устройства и то, как функции SDK выполнялись в это конкретное время, что, в свою очередь, помогает нам отлаживать ошибку/сбой гораздо быстрее и эффективнее.

Минималистичные общедоступные API

При написании SDK очень важно иметь как можно более минималистичный API для наших конечных пользователей. Наличие сложных API может запутать стороннего разработчика, и в конечном итоге они могут неправильно интегрировать SDK. Итак, главный вопрос, который следует задать себе при разработке общедоступного API: можно ли сделать его более простым? Все, что вы можете придумать, может быть конфиденциальным и не должно быть раскрыто конечному пользователю, не должно быть раскрыто. Рассмотрим пример класса Authentication SDK.

Приведенный выше класс — это всего лишь гипотетический класс, который кто-то может представить стороннему разработчику. Теперь вопросы, которые приходят мне в голову:

  • Нам действительно нужно запрашивать идентификатор и секрет приложения при инициализации? Есть ли способ не запрашивать эти аргументы? Ответ: Да, вы можете создать отдельный файл info.plist для каждого клиента на своем портале для разработчиков и просто попросить пользователей импортировать его в свой проект. Таким образом, вы не запрашиваете у пользователя идентификатор и секрет приложения при инициализации, что делает наш API более простым и менее подверженным ошибкам пользователя.
  • Действительно ли нам нужно предоставлять свойства разработчику, интегрирующему SDK? Им действительно нужны какие разрешения у них есть, или есть ли у них сеть, или какой токен доступа SDK использует внутри? Если ответ НЕТ, то эти свойства могут быть перемещены в приватное расширение класса и не будут отображаться в общедоступном заголовке.

После долгих размышлений приведенный выше класс может стать таким простым, как показано ниже:

Непрерывная интеграция

Непрерывная интеграция действительно важна для поддержания стабильности вашего SDK. На начальных этапах у нас было очень мало заданий, работающих на Jenkins. Но когда мы начали расти, мы начали понимать, что с некоторыми слияниями наша компиляция SDK была нарушена. Лучший способ обнаружить это на раннем этапе — создать задания, имитирующие компиляцию пакетов SDK, отправляемых клиентам. Итак, теперь у нас есть задание, которое компилирует все цели SDK, которые у нас есть для любого PR, отправленного любым разработчиком. У нас также есть рабочие места, которые занимаются модульными тестами для наших основных функций SDK.

Мы также недавно перешли на GitHub Actions от Jenkins. Наша главная причина перейти на Github Actions заключалась в том, чтобы перенести весь наш конвейер CI в облако, которое встроено вместе с Github Actions. Вы также можете выбрать собственные беговые машины в качестве вторичной или основной цели. GitHub Actions также очень гибок в том смысле, что вы можете контролировать каждый шаг вашего конвейера CI по сравнению с Jenkins.

Тестовые приложения

Очень важно иметь тестовое приложение, которое в основном демонстрирует все функции вашего SDK. Наличие такого приложения также помогает автоматизировать тестовые случаи пользовательского интерфейса для функций вашего SDK. Мы всегда добавляем любые новые функции, добавленные в SDK, в тестовое приложение. Это также помогает в ручном тестировании QA и помогает нам выявлять любые ошибки до того, как они попадут в производство.

Мы также используем наше тестовое приложение в заданиях CI, чтобы отдел контроля качества мог протестировать все функции нашего SDK, на которые повлияло изменение, которое мы планируем вскоре объединить. Тестовое приложение также демонстрирует полезную информацию об отладке, которая помогает нашей команде контроля качества создавать JIRA с гораздо более полезной информацией, чтобы разработчики могли быстро и эффективно отлаживать проблему.

Сводка

Вышеупомянутые проблемы/вопросы, которые я упомянул, являются лишь частью ежедневных проблем, с которыми мы сталкиваемся, и не претендуют на то, чтобы быть исчерпывающим списком. Но в основном я осветил все основные проблемы, с которыми мы сталкиваемся при ежедневной разработке функций SDK. Надеюсь, это поможет людям, пытающимся создать фреймворк/SDK для сторонних пользователей.