Crashlytics что это
Перейти к содержимому

Crashlytics что это

  • автор:

Crashlytics

Crashlytics — бесплатный инструмент отслеживания и анализа багов в мобильных приложениях на операционных системах iOS и Android. Сервис рассчитан на неограниченное количество программ, пользователей и ошибок. Отчёты о сбоях можно получать в режиме реального времени. Для работы необходимо завести аккаунт в Fabric.

Платформа предназначена для разработчиков приложений, так как позволяет отслеживать баги и жалобы пользователей на падение программы и анализировать, что именно привело к сбою. Отсутствие платы за использование делают инструмент доступным как для крупных, так и для небольших компаний.

Crashlytics собирает и отображает данные о багах для каждого в отдельности проекта с указанием номера строки с ошибкой. Полученный массив можно фильтровать по версиям приложений, типам устройств, операционным системам, наличию джейлбрейку на телефоне. Платформа высчитывает значения и строит графики с показателями среднего количества багов в день, приблизительного процента смартфонов с авариями, общего количества пользователей, столкнувшихся с проблемой. Все отчёты можно выгружать в файл формата .TXT. В режиме реального времени доступна статистика о числе устройств с запущенной программой и корректности работы. В перечне сбоев можно помечать о решении проблемы. Все проекты расшариваются между участниками с различным уровнем доступа.

Ключевые особенности

  • Анализ багов в мобильных приложениях iOS и Android
  • Бесплатное использование
  • Сбор данных в режиме реального времени
  • Фильтрация по типу устройств, ОС, версии программы, джейлбрейку
  • Ведение одного проекта с различных аккаунтов

Вступление

Достаточно известный ранее сервис Crashlytics с осени 2014 года является частью Fabric — набора специализированных SDK (или, как сказано на официальном сайте, “modular, cross-platform mobile development suite”), каждый из которых возможно интегрировать по отдельности, либо совместно. В своем обзоре я остановлюсь только на Crashlytics Kit — сервисе и SDK, отвечающими за дистрибуцию мобильных приложений.

Система оценки: сервисы оцениваются по 10-балльной шкале по каждому из разделов (Регистрация и интеграция, Основной функционал, Дополнительный функционал, Continuous Integration). Суммарная оценка позволит определить победителя.

Fabric

Регистрация и интеграция

Регистрация в сервисе построена на заявительном принципе — каждый желающий создать новый аккаунт может оставить заявку, которая, исходя из нашего опыта, будет рассмотрена в кратчайшие сроки (не так давно заявка нашего сотрудника была одобрена в течение часа). Лишним будет говорить, что интеграция SDK Fabric является быстрой и простой. Ни один другой сервис дистрибуции не предоставляет настолько удобный пошаговый мастер интеграции. Через этот процесс лучше пройти самостоятельно, редкий случай, когда рутинная, как правило, работа, доставляет удовольствие и выполняется с интересом.

Основной функционал

Примечание (обновлено 15 июня 2015): говоря о дистрибуции приложений для iOS необходимо помнить, что на данный момент все сервисы, кроме TestFlight от Apple, по-прежнему должны учитывать ограничение на количество устройств доступных при использовании AdHoc provision profiles. Следовательно, максимум используемых устройств равен 100 на каждое семейство устройств (это условие было изменено 8 июня 2015 года, после объявления на WWDC об объединении всех developers programs в одну), в которые входят в том числе и устройства, используемые непосредственно разработчиками. Самым же большим ограничением является то, что список зарегистрированных устройств можно “обнулять” только раз в год, после продления подписки на iOS Developer Program (возможно в последующем и это условие будет изменено).

В части основного функционала Fabric концептуально отличается от всех других рассмотренных сервисов. Так, например, добавление нового проекта (“приложения” в терминологии Fabric) осуществляется не на сайте сервиса, а в десктопном клиенте:

Добавление новых пользователей/тестировщиков возможно как при помощи приложения-клиента, так и на вебсайте сервиса. В первом случае возможно добавить тестировщика не включая его ни в какую группу:

Во втором же случае необходимо выбрать существующую группу или создать новую, куда и будут добавляться все новые члены команды:

Примечание: Сервис предоставляет возможность для импорта списка тестировщиков из старой версии TestFlight: dev.twitter.com/crashlytics/beta-distribution/testflight-migration. Но этот функционал будет полезным, если вы заранее позаботились об экспорте списка, так как с марта 2015 года старая версия TestFlight уже недоступна.

Импорт списка тестировщиков возможен из CSV-файла, его формат должен быть следующим:

First name,Last name,E-mail 

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

Установить предыдущие версии приложения очень просто, под кнопкой для установки последней версии находится список всех доступных конкретному пользователю версий:

Дополнительный функционал

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

Посмотрим, что же предлагает Fabric.

Первое — это символизация отчётов о падении приложения. И это очевидно даже из оригинального названия сервиса: Crashlytics.

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

  • Defensive Reporting: processes that crash often end up sustaining considerable damage before the kernel takes action to terminate them. This can result in secondary crashes, where the crash handling code itself is unable to operate correctly and fails. We’ve invested in making our file handling code extremely defensive, so parsing cache files can’t crash unexpectedly.
  • Stack Unwinding: one of the most abstruse aspects of crash detection is stack unwinding, the seemingly omniscient ability to determine historic code execution that directly lead to the crash. Our SDK determines the calling instruction that works in the case of objc_msgSend and many other methods that conform to Apple’s iOS ABI.
  • Mach Exceptions: we capture crashes using the lowest level system available on iOS and OS X. The Mach Exception API makes it possible for us to capture every crash, consistently, and without some of the indeterminate behavior of other mechanisms. This also gives us data that much more closely matches what a developer would see in Xcode.
  • Uncaught exception reporting: when your app throws an uncaught exception, the Crashlytics springs to life. Crashlytics quickly records the stack trace and state of the device at the time the exception was thrown and sends the crash information to our servers for processing. You get complete visibility for every crash, effortlessly.
  • Caught exception reporting: Crashlytics isn’t just for uncaught exceptions! Adding a single line of code in your catch block will report caught exceptions to Crashlytics for processing, and you are still free to handle the exception however is best for your users. You get the full stack trace and all the same device information we collect for fatal crashes, so you can identify and fix bugs even if your app doesn’t crash!
  • Fully automated deobfuscation: we automate deobfuscation of ProGuarded stack traces for apps built using our ant tools, maven tools or IDE plugins. We did the legwork for you. Built into your existing workflow, our SDK will have negligible impact on your app.

После отправки отчёта с устройства на сервер Fabric (это происходит после перезапуска “упавшего” приложения), сервис рассылает уведомления по электронной почте, а также выводит оповещение на компьютерах с установленным клиентом:

В качестве недостатка можно отметить то, что во втором случае отсуствует возможность запуска Xcode с нужным проектом, классом и выделенной строкой кода (как это сделано в клиенте HockeyApp).

Также возможно настроить интеграцию с трекерами и другими сервисами, после чего уведомления будут передаваться и туда. Большим плюсом является возможность подключения сразу нескольких сервисов. А недостатком — скудность справочной информации, относящейся к данному функционалу.

Примечание: в тестовом проекте была настроена интеграция с Bitbucket и Hipchat. В результате сообщения о новых падениях приходили только в Hipchat, новые тикеты в Bitbucket не создавались.

Fabric предоставляет возможность повысить полезность связанной с отчётами о падении информации при помощи трёх дополнительных инструментов:

Custom keys: фреймворк предоставляет специальные методы, позволяющие сохранить значения переменных, критически важных для последующего анализа.

+ (void)setObjectValue:(id)value forKey:(NSString *)key; + (void)setIntValue:(int)value forKey:(NSString *)key; + (void)setBoolValue:(BOOL)value forKey:(NSString *)key; + (void)setFloatValue:(float)value forKey:(NSString *)key; 

Примечание: максимальное количество переменных — 64. Подробнее можно узнать тут.

Custom logging: использование макроса “CLS_LOG” позволяет записывать служебные сообщения в лог устройства, однако в отличие от стандартного NSLog при использовании этого макроса лог будет прикреплён к отчёту о падении (подробнее).

Примечание: в отчёте сохраняется весь лог целиком с момента запуска приложения. Есть возможность поиска по логу с использованием регулярных выражений.

User information: также есть возможность идентифицировать пользователя приложения (идентификатор, имя и адрес почты — подробнее). При использовании необходимо учитывать политику Apple в отношении персональных данных.

Answers — сервис аналитики, который стал частью Fabric летом 2014 года, является хорошим дополнением для сервиса сбора отчётов о падении. Он позволяет получать оперативную информацию об использовании приложения (отображаются как “мгновенные” показатели, так и суммарные/статистические данные):

Сервис старается дарить позитив, рассылая например такие письма:

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

Continuous Integration

Примечание: Описанные далее нюансы использования сервисов как части непрерывной интеграции (continuous integration) в данном обзоре подразумевают, что она будет делаться на основе решения, предлагаемого компание Apple. То есть при помощи Mac OS X Server и Xcode bots — подробно на организации такой интеграции я не буду останавливаться, возможно это станет темой для отдельной статьи. Желающие могут ознакомиться с темой самостоятельно, например, обратившись к официальному руководству от Apple.

Для использования API загрузки дистрибутива приложения необходимо получить API_KEY и BUILD_SECRE. Узнать их можно на странице “Settings -> Organizations -> страница с детальной информацией для конкретной организации -> скрытые поля под названием организации”:

Загрузка осуществляется при помощи специальной утилиты, которая включена в фреймворк, пример использования:

/path/to/Crashlytics.framework/submit  -ipaPath /path/to/my.ipa -emails TestEmail@crashlytics.com,AmazingTester@twitter.com -notesPath ~/Notes/ReleaseNotes.txt -groupAliases GroupAlias,GroupAlias2 

Примечание: emails, notesPath и groupAliases — необязательные параметры.

Полный список параметров:

 -emails list of individual addresses (comma-separated) -groupAliases list of group aliases from web dashboard (comma-separated) -notesPath absolute path to .txt file -notifications enables/disables email notification to testers (YES|NO) 

Справочная страница на официальном сайте: http://support.crashlytics.com

Итого суммарная оценка по всем разделам: 34 балла.

Заключение

В своём обзоре я постарался рассмотреть плюсы и минусы четырёх сервисов дистрибуции мобильных приложений для iOS, а также оценить их. Признаюсь, изначально мне казалось, что победитель очевиден, но в итоге, после более тщательного изучения, всё не так однозначно.

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

  1. Fabric — 34 балла.
  2. HockeyApp — 33 балла.
  3. Ubertesters — 32 балла.
  4. Testflight — 15 баллов.

На первом месте Fabric, самыми большими достоинствами этого сервиса является бесплатность, высокая эффективность в сборе и обработке отчётов о падениях. Из недостатков можно отметить некоторую ориентированность на разработчиков* и отсутствие встроенной системы сбора отзывов.

*Здесь я подразумеваю узкую специализацию сервиса: если какой-либо член команды не является разработчиком, то в приложении ему недоступен никакой другой дополнительный функционал (кроме того что требуется от приложения по спецификации). И если приложение работает без падений, для предоставления отзыва потребуется использование какого-то другого сервиса.

Второе и третьте место у HockeyApp и Ubertesters — разница в оценках всего 1 балл.

Плюсами HockeyApp является поддержка символизации отчётов о падении и более тесная, в сравнении с другими сервисами, интеграция с Xcode (открытие проекта/класса на строке вызвавшей падение приложения). Из недостатков можно отметить отсутствие нормального бесплатного тарифного плана и ограниченность имеющейся системы сбора отзывов.

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

TestFlight, разместившийся на последнем месте, выглядит аутсайдером, но я думаю, что это временное положение и с дальнейшим развитием как сервиса, так и всей эко-системы разработки от Apple, он вполне может потеснить текущих лидеров, последние новости с WWDC 2015 вселяют определенный оптимизм.

Надеюсь, что серия обзоров получилась полезной и смогла кому-то с выбором подходящего сервиса для распространения своего приложения. Буду рад ответить на дополнительные вопросы.

  • Блог компании Arcadia
  • Разработка под iOS
  • Разработка мобильных приложений
  • Тестирование мобильных приложений

Firebase Crashlytics и Firebase Performance для QA

Firebase Crashlytics предоставляет функциональность логирования крашей в мобильных приложениях. Он позволяет отслеживать и анализировать краши приложения, что помогает выявить и исправить проблемы, связанные с устойчивостью и стабильностью приложения. Тестировщики могут использовать Firebase Crashlytics для автоматического сбора отчетов о крашах, включая трассировку стека, информацию о девайсе и другие полезные данные. Это позволяет быстро определить причину крашей и принять меры для их устранения.

Firebase Performance

Firebase Performance предоставляет инструменты для измерения и оптимизации производительности мобильных приложений. Он позволяет тестировщикам и разработчикам отслеживать время загрузки приложения, задержки при выполнении операций, использование ресурсов и другие параметры производительности. Это позволяет определить узкие места и проблемы, которые могут влиять на пользовательский опыт. Тестировщики могут использовать Firebase Performance для выявления проблем производительности и предложения рекомендаций по их устранению.

Оба инструмента, Firebase Crashlytics и Firebase Performance, предлагают детальные отчеты и аналитику, которые помогают тестировщикам и разработчикам лучше понимать проблемы приложения и принимать эффективные меры для их исправления или оптимизации производительности. Их интеграция в мобильное приложение помогает создать более надежное и эффективное приложение.

Crash-crash, baby. Автоматический мониторинг фатальных ошибок мобильных приложений

Всем привет! Меня зовут Дмитрий, я релиз-инженер в команде CI/CD Speed Авито. Вот уже несколько лет мы с коллегами отвечаем за всё, что связано с релизами наших мобильных приложений и не только. В прошлый раз я рассказывал о нашей системе релизов мобильных приложений на основе контракта. Сегодня речь пойдет о том, как мы автоматизировали сбор информации из Firebase о новых фатальных ошибках в мобильных приложениях.

Проблематика

В процессе написания программ неизбежно возникают ошибки. Некоторые из них могут быть фатальными и приводить к крашу приложения. Для сбора, анализа и исправления таких ошибок используются специальные системы мониторинга.

Раньше, как и многие на рынке мобильных приложений, мы использовали Fabric, для которого vadimsmal и YourDestiny написали очень удобный клиент Fabricio. На базе этого клиента у нас была создана система мониторинга, которая заводила Jira-задачи на новые фатальные ошибки, искала ответственных по Git-Blame и сообщала об ошибках в cпециальный слак-канал.

Но компания Google решила прекратить развитие проекта Fabric, объявила дату закрытия и предложила всем желающим мигрировать на их платформу Firebase, что мы благополучно и сделали.

Система автоматического мониторинга крашей перестала работать, и нам пришлось возвращаться к постоянному ручному мониторингу. При первичном изучении документации выяснилось, что у Firebase нет публичного API для получения необходимой информации, и придётся искать обходные пути.

Получаем данные

Google Cloud Functions

Первая проблема для организации автоматического мониторинга, которую нужно было решить — как оперативно получать информацию о новых сбоях в работе приложения.

Исследование документации Firebase привело нас к Google Cloud Functions или же облачным функциям. Это serverless FaaS от Google, который позволяет запускать ваш код в облачной инфраструктуре Google. У Firebase-Crashlytics есть встроенная интеграция с облачными функциями (на момент написания статьи данная функциональность помечена как deprecated). Вы можете написать call-back на один из трёх crashlytics-ивентов и дальше обрабатывать его как вашей душе угодно. Особенно нас интересуют два ивента — “onNew”(новое событие crashlytics) и “onVelocityAlert” (резкий рост события crashlytics).

В голове сразу же родилась схема. Настраиваем интеграцию Firebase-Google Cloud Functions, шлём оттуда все новые краши сразу в свой сервис, и там уже обрабатываем. Берём пример из документации, вносим несколько доработок и получаем следующий код на JS который загружаем в Google Cloud:

const functions = require('firebase-functions'); const rp = require('request-promise'); function sendEvent(event) < return rp(< method: 'POST', uri: functions.config().crashlytics.crash_collector_url, body: event, json: true, >); > exports.NewIssueEvent = functions.crashlytics.issue().onNew(async (issue) => < await processEvent(issue, 'NewIssueEvent') >); exports.RegressedEvent = functions.crashlytics.issue().onRegressed(async (issue) => ); exports.VelocityAlertEvent = functions.crashlytics.issue().onVelocityAlert(async (issue) => ); const processEvent = async (event, type) => < if (isActualEvent(event)) < await sendEvent(event); console.log(`Posted $$ successfully to crash collector`); > else < console.log(`It's old event or not Avito. Do nothing`); >> const isActualEvent = (event) => < const = event; const = appInfo; const version = latestAppVersion && parseFloat(latestAppVersion.split(' ')[0]); console.log(`Event appName: $ version: $`); return appName === 'Avito' && version > 60.0 > 

Тут мы добавили небольшое изящное архитектурное решение, чтобы не получать события, не относящиеся к Авито, или же события совсем старых версий приложения.

Но в текущей реализации нам не хватает данных. В Firebase-Crashlytics есть fatal события (собственно фатальные ошибки-краши) и non-fatal (остальные события которые по той или иной причине логируются в crashlytics). Все летящие к нам ивенты на событие “onNew” не имеют признака фатальности, к тому же нам хотелось как-то фильтровать события по количеству затронутых пользователей и частоте возникновения, но этой информации в событиях нет.

BigQuery

Google позволяет экспортировать данные из Firebase в BigQuery. BigQuery — облачное хранилище, предоставляющее удобную платформу для хранения и обработки данных. На момент исследования в середине 2019 года был доступен только один тип синхронизации c Firebase — Batch Table.

Нужно отметить ключевые особенности данного типа синхронизации:

  1. Синхронизация происходит раз в сутки, при этом нет гарантии, когда она будет завершена.
  2. Нельзя настроить тип экспортируемых событий — экспортируется и fatal и non-fatal.
  3. Чем дольше живёт таблица, тем больше в ней данных (ваш кэп) и тем дороже стоят услуги хранения.

Дорабатываем изначальную схему:

После получения ивента в нашем сервисе идём в BigQuery и получаем недостающую информацию: признак фатальности, число задетых пользователей и так далее. При этом запросы к BigQuery отправляем не на каждый новый ивент, а периодически. Для нас оптимальная частота запросов — раз в день после 17:00, так как за это время выгрузка данных из Firebase-Crashlytics в BigQuery успевала завершиться, и можно было получить информацию по всем необработанным ивентам простым запросом:

SELECT issue_id, is_fatal, COUNT(*) as crashes_counter, COUNT(DISTINCT installation_uuid) AS affected_users FROM `android.firebase_crashlytics.` WHERE issue_id in ( ) GROUP BY issue_id, is_fatal LIMIT 1000

Внимательный читатель может заметить, что тут образовывается временной лаг между фактическим появлением краша и получением нами информации о нём. Чтобы не пропускать редкие, но действительно важные краши, которые резко растут и задевают сразу много пользователей, у нас по-прежнему оставалось событие “onVelocityAlert” в Google Cloud Function. По документации это событие вызывается исключительно на фатальные ошибки в работе приложения, если ошибка привела к сбою N сеансов пользователей за последний час. По факту же “onVelocityAlert” не работало, мы зарепортили это в Google, нас внесли во внутренний трекер, и на этом всё.

Слак

Нас вполне устраивал временной лаг при получении «обычных» фатальных ошибок, но совсем не хотелось пропустить пожар. В поисках возможности получения VelocityAlert мы пришли к интеграции Firebase-Crashlytics и слака. В консоли Firebase вы можете достаточно просто и быстро настроить отправку событий в определённый слак-канал, в том числе событий VelocityAlert. Это было почти то, что мы искали. Интеграция позволяла оперативно получать информацию о том, что всё плохо, но при этом нельзя было фильтровать события по версии. В итоге канал больше напоминал свалку.

Тогда мы решили использовать канал с сырыми VelocityAlert как источник данных для сервиса. Слушать этот канал, подтягивать из него новые сообщения с VelocityAlert и уже на уровне сервиса фильтровать.

Новая схема выглядела так:

Обрабатываем данные

С источником данных вроде определились. Теперь нужно эти данные обрабатывать.

Напомню, что наша старая система на Fabric делала с данными о крашах:

  1. Искала ответственного по Git-Blame.
  2. Создавала задачу на исправление.
  3. Оповещала о новом событии в специальный слак-канал.

Первое от чего мы решили отказаться — это автоматическое создание задачи и поиск ответственного по Git-Blame. По опыту, автоматически созданные задачи отправлялись на кладбище Jira, и к ним редко кто возвращался, а поиск по Git-Blame иногда давал сбой, что ещё больше повышало шансы забыть задачу. А вот оповещения в слак мы решили развивать, этот канал коммуникации показал себя наиболее эффективным.

Обработку решили реализовать на базе сервиса мобильных релизов Nupokati. Он собирает информацию по новым крашам, раз в день по крону запрашивает дополнительные данные из BigQuery, фильтрует краши по фатальности и частоте возникновения — нас не интересуют единичные сбои — и отправляет daily report в слак по актуальной версии приложения.

Пример daily report

Сразу в треде к этому репорту находятся ответственные, и создаются соответствующие задачи. Опять же по опыту, задачи, которые заведены ответственным разработчиком самостоятельно, гораздо чаще закрываются с исправлением краша.

Помимо daily report мы отлавливаем VelocityAlert для актуальной версии и тут же репортим о пожаре в слак-канал и ответственному за конкретный релиз инженеру. В треде определяется, насколько взрыв фатален, и что с ним делать.

Google Cloud Functions всё

Около года мы успешно эксплуатировали новую систему автоматического сбора и алертинга фатальных ошибок в мобильных приложениях. Уже практически забыли, как заходить в Firebase и смотреть краши. Как вдруг было объявлено, что интеграция Firebase-crashlytics и Google Cloud Functions deprecated и её работа будет приостановлена 1 октября 2020 года. Нужно было оперативно дорабатывать решение и отказываться от облачных функций. При этом хотелось обойтись минимальными изменениями в работающей системе.

Так мы просто убрали Cloud Functions и доработали запрос на получения данных из BigQuery. Вся остальная система осталась прежней: daily report, velocityAlerts, фильтры по количеству задетых пользователей и слак-каналы. Новый запрос получает сразу все уникальные краши по нужной версии и отправляет их в поток обработки.

SELECT issue_id, issue_title, is_fatal, COUNT(issue_id) as crashes_counter, ARRAY_AGG (distinct application.display_version) AS versions, COUNT(DISTINCT installation_uuid) AS affected_users FROM `android.firebase_crashlytics.` WHERE is_fatal=true GROUP BY issue_title, issue_id, is_fatal HAVING ARRAY_LENGTH(versions)=1 AND "" in UNNEST(versions) ORDER BY crashes_counter DESC

Итоги

Система автоматической сборки крашей позволила нам снизить ручной труд и человеческий фактор. Больше не нужно заходить в консоль Firebase и следить за крашами. Мы смогли построить процесс по исправлению фатальных ошибок на базе предоставляемых ей данных и улучшить качество наших мобильных приложений. При этом в текущей реализации с получением данных из BigQuery напрямую мы можем легко расширять и дорабатывать её, если понадобится.

Несколько советов тем, кто захочет повторить наш путь:

  • Использование BigQuery платное, но есть песочница, в которой можно поэкспериментировать.
  • Оптимизируйте запросы к BigQuery. Процессинг данных не бесплатный, он в прямом смысле имеет денежное выражение согласно тарифам.
  • Для оптимизации затрат на хранение данных в BigQuery уменьшайте время жизни таблиц, это есть в настройках. Для нас оптимальным отказался период жизни таблицы в пять дней.
  • Уже после создания нашей системы появился BigQuery streaming. На нём можно собрать аналогичную систему или даже лучше.
  • Внимательней читайте документацию к Google Cloud Platform. Это очень мощная платформа с множеством инструментов и возможностей.
  • алерты
  • мониторинг
  • краш-репорт
  • google cloud functions
  • мобильные приложения
  • Блог компании AvitoTech
  • Разработка мобильных приложений

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *