Русский
Русский
English
Статистика
Реклама

Разработка под ios

IOS интервью в Vivid

11.06.2021 18:10:18 | Автор: admin

Возможно, вы знаете про Vivid, где-то слышали или же видите впервые. Мы делаем один из самых быстрорастущих и многообещающих финансовых сервисов в Европе. Чтобы не быть голословным, вот некоторые из наших показателей:

Скачивания и активные пользователи в Германии с 03.21 по 06.21Скачивания и активные пользователи в Германии с 03.21 по 06.21Количество функций в приложениях в 4 квартале 2020 годаКоличество функций в приложениях в 4 квартале 2020 года

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

Дисклеймер

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

Немного вводных

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

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

Наши особенности

Кроме основных обязанностей интервьюеров мы старались делать следующее:

  • Располагать к себе кандидата и создавать friendly атмосферу

  • Задавать вопросы по ситуации, а не по заготовленному сценарию

Для первого пункта мы использовали смолтолки перед собеседованием (это не вопросы про опыт или резюме, а то, что помогает лучше узнать кандидата), иногда шутили для разрядки, подстраивались под особенности кандидата.

Случай на собеседовании

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

Для собеседования мы не готовили список вопросов мы готовили темы на которые хотим поговорить. Такими темами были: Swift (куда же без знания языка), UI (так как у нас его очень много, он на 95% кастомный и иногда нетривиальный) и архитектура (для ведущего разработчика это очень важно). По каждой теме мы старались спрашивать только то, что в основном используется в повседневной разработке и то, что связано с нашим приложением. Конечно, иногда мы углублялись в какой-то вопрос, чтобы понять насколько хорошо кандидат знает тему, но тут есть тонкость если вдруг человек не отвечает или отвечает неправильно, мы не делаем на этом сильный акцент, так как это опциональные вопросы и ответы на них не обязан знать каждый.
Также для нас была очень важна практика, так как это то, что раскрывает способности разработчика лучше всяких вопросов. У нас были заготовлены различные задачи, которые мы выбирали в зависимости от ситуации. Среди них не было вопросов по алгоритмам, потому что мы не считаем их показательными они показывают умение находить решения (или вспоминать их), а не умение писать код. Наши задачи показывали то, как кандидат обычно пишет свой код, какие конструкции использует, насколько оптимальны его решения и как он размышляет.

Самая сложная задача

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

Формат собеседования

Экспериментировать и меняться это то, что свойственно нашей компании. Собеседования не исключение. Мы попробовали разные форматы: одно собеседование на 1.5 часа с вопросами "по ситуации", теоретическое собеседование на 1 час и практическое на 1.5 часа, теоретическое собеседование на 1 час и тестовое задание. В конце-концов мы пришли к следующему:

  • Скрининг перед собеседованием из 6 вопросов.

  • Одно собеседование на 1.5-2 часа. Из них 10-20 минут на общение с кандидатом не на технические темы, 30-40 минут на кодинг и остальное время на теорию.

  • Интервью всегда проводят 2 человека это дает более объективную оценку кандидата после собеседования.

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

Скрининг

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

В скрининге содержатся такие вопросы, ответ на которые не приходится искать долго. В то же время это не избитые вопросы, что нравится кандидатам (судя по опросам).

Циферки:

  • Средняя длительность скрининга 4 минуты

  • Процент кандидатов, прошедших скрининг 75%

Техническая часть

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

Поняв наши проблемы, мы переработали техническую часть. Теперь у собеседования есть "сценарий", представляющий собой древовидную схему в Miro.

Пример одной из веток собеседованияПример одной из веток собеседования

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

Есть одна особенная ветка Swift. Для движения по ней мы проводим лайвкодинг, в рамках которого кандидат решает поставленную задачу, у которой добавляются или меняются требования (прям как в реальной жизни). Задача затраивает практически весь синтаксис языка при ее небольшом объеме. По ходу решения мы задаем вопросы. Например: "Почему использовал class, а не struct?", "Можно ли задачу решить по-другому?" и так далее.

Таким образом, мы получили "фреймворк" для собеседования. Он позволил нам:

  • быстро понимать во время собеседования что спрашивать

  • вести собеседование более структурировано

  • быстро обучать новых интервьюеров

Как оцениваем кандидатов

Нельзя не затронуть столь субъективную тему как оценка уровня кандидата. Мы разделяем уровни разработчика как и многие другие: Junior, Middle, Senior. К каждому уровню еще можем добавлять + или - чтобы оценка была немного более точной.

Для определения уровня используем следующие маркеры:

  • Предыдущий опыт. Чем больше в нем сложных и разнообразных задач, тем выше уровень.

  • Решение задачи. Чем быстрее и правильнее решена задача, чем чище код и чем лучше обоснованы решения, тем выше уровень.

  • Ответы на теоретические вопросы. Тут нам важно понять, подкреплено ли знание теории практикой. Если кандидат отвечает на вопрос это хорошо, но если еще и приводит примеры из опыта или объясняет своими словами, то еще лучше. Короче говоря, для нас понимание важнее знания.

  • Умеренный перфекционизм. Это когда кандидат достаточно хорошо продумывает решение, но не тратит кучу времени на незначительные мелочи.

После выхода на работу

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

Напоследок

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

На этом все. Всем удачи на собеседованиях!

Подробнее..

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

24.05.2021 12:21:25 | Автор: admin

Если вы регулярно читаете Хабр, то вам попадались статьи в духе: бросайте всё и начинайте изучать Swift, Kotlin или Flutter прямо сейчас. Давайте разбираться, правда ли стоит переобуваться в мобильного разработчика. Мы попросили спикеров, программный комитет и разработчиков взглянуть на сферу мобильной разработки с разных ракурсов и приоткрыть завесу тайны грядущей конференции Мир. Труд. Мобайл. В конце приятный бонус для читателей Хабра и подробности программы.

Мобильная разработка актуальна. Это факт

В отчёте State of Mobile 2021 говорится, что рынок мобильных приложении и игр вырос на 30% за 2020 год пользователи потратили на них рекордные $111 млрд. Пандемия и изоляция внесли свой вклад.

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

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

В сторах можно найти приложение на любой случай жизни. Что говорить, когда даже у автомата по розливу воды у дома в спальном районе (за 3 /литр) есть мобильное приложение для онлайн-оплаты. Кажется, мобильщики выбрали как девиз любая идея достойна мобильного приложения! Почему? Отчасти потому что новые технологии упростили и шаблонизировали разработку.

Отчёт State of Mobile 2021 Отчёт State of Mobile 2021

Про изменения в подходах к разработке мы спросили Фёдора Цымбала из Orion Innovations. Он выступит с докладом: Android Automotive. Не путать с Android Auto.

Новые технологии бывают разные. В основном упрощается решение типовых задач. Нужно помнить, что некоторые фреймворки намеренно усложняют жизнь разработчику. Заставляют думать об аспектах, которые раньше можно было игнорировать. Например, работа с Permissions, как мне кажется, усложняется в каждой новой версии Android. Но это связано с желанием Google защитить персональные данные пользователя. Так что не всегда усложнение это плохо.

В плане UI-фреймворков сейчас очень популярен Flutter. Но Jetpack Compose вполне может его потеснить. Стоит выбрать что-то одно из этих двух опций.

Заметен уход с мобилок на другие устройства: часы, телевизоры, автомобили. Android на этих устройствах сейчас активно развивается. По моему мнению, это тоже очень интересная тема. Про Android Automotive я и буду рассказывать: Google Automotive Services, Driver Distraction Guidelines, Garage Mode и об интеграции Android с подсистемами автомобиля, такими как камера заднего вида, климат контроль или поворотники.

Павел Стрельченко из hh.ru занимается Android-разработкой с 2015 года, поэтому успел застать разработку под Android 4, первую версию Android Studio, жизнь без Jetpack, Architecture Components и Kotlin. Павел выступит с темой: Укрощая фиче-флаги. Разберем проблемы постоянных merge-конфликтов, сбора флагов в один-единственный список.

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

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

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

Тем, кто только начинает свой путь в увлекательный мир Android, я всегда рекомендую одно и тоже посмотреть лекции Android Academy. Мои коллеги по Android-у проделали потрясающую работу, собрав в один бесплатный курс всё необходимое для успешного старта в профессии.

Все спикеры

Evelio Tarazona Cceres
Instagram / Facebook

Server Driven Cross-Platform UI/Features/Apps. At Instagram we leverage Server Driven UI approach to build once/iterate quickly and ship features to billions of users on Android/iOS and the web.

Федор Цымбал
Orion Innovations

Android Automotive. Не путать с Android Auto. Google Automotive Services, Driver Distraction Guidelines, Garage Mode и об интеграции Android с подсистемами автомобиля, такими как камера заднего вида, климат контроль или поворотники.

Ольга Сартакова
Redmadrobot

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

Евгений Ртищев
Sberbank

Оптимизируем процессы разработки и параметры приложения.

Андрей Малеваник
Нетологиия

Красота или функциональность. Должен ли интерфейс быть красивым?

Павел Стрельченко
hh.ru

Укрощая фиче-флаги. Разберем проблемы постоянных merge-конфликтов, сбора флагов в один-единственный список.

Екатерина Петрова
JetBrains

State of Kotlin Multiplatform Mobile. О том, что поменялось в экосистеме KMM с момента большого релиза, о трендах и планах развития.

Александр Аверин
adVentures, Mail.ru

История перезапуска музыкального приложения BOOM глазами дизайнера.

Александр Гращенков
RoadAR

Почему тормозит iPhone. От базового уровня перевода задач в бэкграунд, до ускорения отрисовки с помощью Metal.

Михаил Никипелов
Distillery

Пиктограммы 80-го уровня. Про подбор идей и отсекание лишнего: как при работе с библиотеками, так и при отрисовке своих иконок.

Дмитрий Мельников
EventSheep (ех-Yandex, ех-Mail.ru)

Как мобильному разработчику сделать стартап без команды. MVP или прототип целого проекта с сервером и фронтендом.

Андрей Чевозеров
Банк ВТБ

SwiftUI в production. Как и зачем?

Антон Назаров
Crisalix

RxSwift vc Combine. О личном опыте миграции с RxSwift на Combine, какие подводные камни есть, как облегчить процесс.

Александр Денисов
EPAM

Так ли страшен Null, как его малюют? О том, что такое Null Safety, чем она может помочь в разработке, какие сложности могут ждать при миграции и чем реализация в Dart похожа, а чем отлична от Kotlin и Swift реализации.

Антон Шилов
Badoo

Воркшоп по анимациям на Jetpack Compose. Разберем основные API и инструменты для работы с анимациями от простого к сложному.

Мария Кирдун
EPAM

Искусство коммуникаций, или как творчеству выжить в IT. Игры на коммуникацию на реальных примерах,

Евгений Сатуров
Surf

Типы модульных тестов на Flutter. О том, как писать код на Flutter, чтобы его можно было протестировать.

Павел Горшков
экс-Redmadrobot, экс-Яндекс

Что придет на смену мобильным приложениям? Мобильная эра, специфика мобильных устройств, эволюция цифровых сервисов.

Сергей Акентьев
Кошелёк

CI на Apple M1. Жутко больно и запредельно быстро. Как работать с кластером MacMini на M1 и почему мы оказались в Дата-центре? Проблемы архитектуры arm64, билды под Apple Rosetta 2, как бороться с софтом Apple и стоит ли оно того?

Алексей Бородкин
Магнит

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

Александр Соболь
МегаФон

Многопроцессная разработка Android приложений взгляд на микросервисную архитектуру.

Приложение остаётся способом реализовать большую идею малыми силами

Мобильное приложение по-прежнему отличный вариант для старта своего продукта с небольшой затратой ресурсов. Самый сладкий и большой кусок пирога мобильные игры. Пользователи потратили на них в 2020 году $143 млрд. Доля мобильных игр в магазинах приложений в 2021 году вырастет до 20%.

Про технологии, рынок, зарплаты и перспективы вроде понятно. Вопрос сколько стоит реализовать свою идею.

Приложения комбинируют механики. Афиша DVIZZ реализована в виде свайпов мероприятийПриложения комбинируют механики. Афиша DVIZZ реализована в виде свайпов мероприятий

Резиденты Иннополиса работают над приложением DVIZZ, которое объединяет афишу городских событий и создание встреч, чтобы познакомиться с новыми людьми и хорошо провести время. Придумать новую идею становится сложнее, уже практически всё реализовано. Поэтому новые приложения активно комбинируют функции. Стремление в сторону супераппов с замкнутой экосистемой как тренд не только для IT-гигантов.

Основатель DVIZZ Михаил Иванов рассказывает, что потратил 500 000 на разработку и 3 млн на зарплаты за полгода после запуска.

Сейчас на операционные расходы уходит около 10 000 в месяц. Но это ещё не всё, потому что самое сложное продвижение. На анализ, стратегию, маркетинг, таргетинг потратили 300 000 . Уже удалось снизить стоимость установки до приятных цифр, но начальный этап действительно самый сложный.

Приложением я решаю личную проблему, а таких как я много. Нет площадок для ивентов, где каждый может рассказать про свои планы на выходные и позвать знакомых, например, как в инсте. Можно сказать, что DVIZZ Инстаграм для ивентов. В ленте можно выбрать мероприятие и купить билет, присоединиться ко встрече пользователей или создать свою.

У нас есть три стратегии монетизации: реклама больших ивентов в афише, платные мероприятия или мастер-классы больше 10 человек и доступ в бизнес-кабинет владельцев площадок для аренды, например, теннисного корта или лектория прямо из приложения. Уже понемногу зарабатываем, планируем запускать в Москве. Окупиться планируем через год.

Что будет на Мир. Труд. Мобайл

Два формата: бесплатный онлайн и офлайн на цифровой даче в Иннополисе. Всего будет 5 больших хабов:

  • Android;

  • iOS;

  • Кроссплатформа;

  • Дизайн;

  • Софтскилы.

Офлайн

Специальная программа для 200 офлайн-участников: закрытые лекции и воркшопы, дачный нетворкинг (песни под гитару у диджитал-костра), тестирование беспилотного такси, афтепати. Спикеры будут читать доклады на грядках, веранде, солнцепёке и даже на чердаке.

Ждём в гости!Ждём в гости!

Онлайн

По недавнему опыту IT Nights мы убедились, что очень важно экспериментировать с подачей и не бояться свежих решений в довольно консервативном жанре конференций. Поэтому в этот раз поднимаем планку и скрещиваем офлайн и онлайн. В офлайне будет немного больше приколов (уж извините), но онлайн точно не останется серой мышью в виде прямого эфира. Уже доступна удобная платформа: прямой эфир, опросы и голосования, беседка-клабхаус со спикерами на холиварные темы после доклада и дачный шопинг на виртуальном базаре.

Зарегистрироваться на онлайн сейчас стоит хотя бы потому, что после конференции доступ к докладам будет платным.

Увидимся на Мир. Труд. Мобайл.

27 мая

Скидка на офлайн 25% для читателей Хабра по промокоду habr

Мобайл редьки слаще!

Подробнее..

Анонс эфира live-coding на SwiftUI

11.06.2021 12:20:14 | Автор: admin

Приглашаем на эфир live-coding на SwiftUI. Реализуем фичу для опенсорсного проекта StackOv, который написан полностью на SwiftUI. Обсудим, почему использовать некоторые системные View при работе со SwiftUI не всегда удачная идея. Посмотрим, как можно сделать по-другому. Эфир состоится 24 июня, четверг, в 18:30 мск.

РЕГИСТРАЦИЯ

В формате live-coding напишем облако тегов для опенсорсного проекта StackOv. Это мобильный клиент для Stackoverflow, сделанный полностью на SwiftUI.

Реализовать фичу облака тегов в SwiftUI можно двумя способами:

очевидным и не совсем правильным,

неочевидным, но почти правильным (почему почти узнаете во время эфира).

В чём суть: в SwiftUI для динамического подсчета размеров используется GeometryReader, он реагирует на любое движение, поэтому нагружает систему. Расскажем и покажем, как можно по-минимуму его использовать, чтобы избавиться от этих проблем.

Кейс переиспользуемый, поэтому будет интересен всем, кто работает со SwiftUI, и не только для того, чтобы реализовать конкретную фичу с облаком тегов.

Ведущие:

Гриша Бернгардт, iOS Lead Surf

Влад Климов,iOS разработчик Surf

Как попасть на эфир

24 июня, четверг. Начнём в 18:30 мск, планируем закончить примерно в 20:00. Трансляция на YouTube-канале Surf.

Зарегистрируйтесь. Таймпад за день и за час до начала встречи отправит на указанную почту ссылку на трансляцию.

До встречи!

РЕГИСТРАЦИЯ

Подробнее..

Самое важное с keynote-презентации WWDC21

07.06.2021 22:20:16 | Автор: admin

Сегодня стартует ежегодная конференция для разработчиков Apple WWDC, и по традиции она начинается в анонсов обновлений операционных систем для продуктов компании.

Выжимка самого важного из того, что объявили во время keynote-презентации в этом материале.

iOS 15

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

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

Также в FaceTime будет встроен портретный режим, размывающих фон за вами.

Одно из нововведений Facetime link. Это ссылки, позволяющие вести расписание ваших звонков, и делиться ими не только с владельцами iPhone, но и с пользователями Android через веб-браузер.

SharePlay позволяет слушать музыку, смотреть фильмы или просто расшарить экран вместе с другими людьми в звонке, при этом любой человек может остановить или возобновить воспроизведение медиафайла. При этом участники звонка смогут и переписываются одновременно с просмотром фильма или подслушиванием музыки. Функция будет поддерживаться множеством приложений, таких как HBOMax, Twich, TikTok, Disney+ и другими.

Сообщения получили новый дизайн для отображения фотографий в виде коллажей или стопки фото.

Новая функция Shared with you дает возможность закрепить то, что вам присылают в iMessage, и что вы хотели бы посмотреть это позже.

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

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

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

Live Text позволяет распознать тексты, например, прямо с камеры телефона или скриншота/фотографии, сохраненной в памяти вашего девайса. Чтение доступно пока на семи языках, не включающих русский. Таким образом можно распознать не только текст на фотографии, но и место, растение, породу животного и не только. При помощи этого алгоритма теперь можно можно найти нужный чек среди ваших фотографий или фото из определенной локации. А если на фото произойдет распознавание ваших контактов или знаменитостей, система выдаст вам информацию о них.

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

В Wallet появилась возможность добавить транспортные карты различных городов, а также ключи от всего, что можно открыть электронным ключом: от вашего дома до автомобиля и номера в отеле. Кроме того, теперь в Walllet можно добавить ваше ID с персональными данными, отсканировал водительские права. Такое ID будет действовать, например, в аэропортах.

В приложении Погоды, помимо редизайна, появилось полноэкранное отображение прогноза погоды на карте в местах поблизости от вас.

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

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

AirPods и Apple Music

AirPods Pro теперь смогут фокусироваться и усиливать голос говорящего рядом человека и тем самым работать как слуховой аппарат.

Siri сможет зачитывать важные уведомления через наушники.

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

Добавлено пространственное звучание на всех девайсах и на tvOS.

iPadOS 15

Переработаны виджеты: теперь их можно размещать где угодно, а не только в центре уведомлений.

Добавили Библиотеку приложений, где можно скрывать страницы, которые вам больше не нужны, и возвращать их обратно, когда необходимо.

Многозадачность тоже улучшили: теперь активное приложение можно сдвинуть в сторону, чтобы открыть другое на экране Домой. Кроме того, теперь их можно опускать вниз, как в Windows или Mac, чтобы затем между ними быстро переключаться.

В Заметках появились упоминания и тэги.

Появилась функция Быстрых заметок для записи важной информации. Они будут собираться в отдельном хабе, и их можно создавать как на iPadOS, так и MacOS.

Также для iPad появится и приложение Перевода с функцией автоперевода любого текста, в том числе рукописного или с фотографий.

С помощью Swift Playgrounds теперь на iPad можно писать собственные приложения для iPhone и iPad.

Конфиденциальность, Siri и iCloud

Появилась защита конфиденциальности в Почте, которая может скрывать ваш IP-адрес или местоположение, а также время открытия письма. Также ваш IP не смогут отслеживать и трекеры в Safari.

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

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

Два улучшения iCloud: восстановление доступа к вашему аккаунту при помощи устройств доверенных людей, которым будет приходить код доступа к вашему девайсу.

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

Еще одна функция скрытие электронного адреса, а также встроенная поддержка HomeKit Secure Video.

Здоровье

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

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

watchOS 8

Обновленное приложение медитаций, возможность отслеживать изменения дыхания во сне и новый циферблат с 3D-портретами из фотографий, снятых на iPhone в обновленной системе watchOS 8. А также обновленное приложение для просмотра снимков, более похожее на таковое в смартфонах, и улучшенный набор текста с возможностью удаления слов и редактирования.

Умный дом

Теперь Apple TV сможет открывать ссылки на сериалы и фильмы, которые присылают пользователю в сообщениях.

HomePod mini можно будет использовать как динамики для телевизора.

В Apple TV+ появятся профили пользователей с возможностью отслеживать прогресс по просмотру сериалов.

Обновление получит и приложение Дом для Apple Watch. Теперь с его помощью можно будет следить за глазком и еще быстрее управлять функциями дома. А камеры смогут присылать пользователю уведомления о полученной посылке.

macOS Monterey

MacOS, как и iOS, тоже получит поддержку SharePlay для совместного просмотра фильмов, а также обновленные Сообщения, Фокусировку и Заметки.

Новая функциональность Universal Control, позволяющая управлять iPad и Mac с помощью одних и тех же клавиатуры и мыши. Так, если iPad поставить рядом с MacBook, курсор сможет автоматически перейти на экран планшета. Это относится как к управлению мышью, так и тачпадом. Таким образом можно переносить файлы с устройства на устройство или, например, использовать iMac в качестве динамиков для iPhone.

Теперь пользователи смогут создавать быстрые сценарии для ежедневных задач и при помощи Shortcuts на Mac. Пока еще будет действовать и Automator, так что переход будет производиться постепенно, в течение нескольких лет.

Новый дизайн для Safari как на Mac, так и на iPad и iPhone. На Mac теперь строка браузера расположена прямо внутри вкладки. На iPhone они теперь находятся снизу и исчезают при чтении. Вкладки же, в свою очередь, можно собирать в группы и таким образом пересылать по почте.

Технологии для разработчиков

Представлены новые API для изоляции голоса, Focus и SharePlay, а также функции для сканирования 3D-объектов для последующего переноса в AR.

Язык Swift упростит создание параллельных процессов, сократив количество необходимого кода.

Теперь в App Store можно будет создавать разные страницы для приложений с возможностью подсветить разные особенности для разных типов пользователей. Так, можно будет подсветить события внутри приложений и игр и выносить их в форме виджетов на экран с приложениями.

Функциональность Xcode Cloud, позволяющая скомпилировать приложение прямо в облаке для дальнейшей работы над них сразу нескольких разработчиков и тем самым позволяющая сэкономить ресурсы железа. Когда приложение пройдет через все проверки, его автоматически разошлют тестировщикам. Эта функция станет доступна в 2022 году.

TestFlight появится на Mac, и его закрытый тест начнется сразу на WWDC.


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

Подробнее..

Xcode Cloud, SharePlay, Focus самое важное с Keynote WWDC21

08.06.2021 00:14:55 | Автор: admin

Сегодня стартует ежегодная конференция разработчиков Apple WWDC, и по традиции она начинается в анонсов обновлений операционных систем для продуктов компании.

Выжимка самого важного из того, что объявили во время keynote-презентации в этом материале.

iOS 15

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

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

Также в FaceTime будет встроен портретный режим, размывающих фон за вами.

Одно из нововведений Facetime link. Это ссылки, позволяющие вести расписание ваших звонков, и делиться ими не только с владельцами iPhone, но и с пользователями Android через веб-браузер.

SharePlay позволяет слушать музыку, смотреть фильмы или просто расшарить экран вместе с другими людьми в звонке, при этом любой человек может остановить или возобновить воспроизведение медиафайла. При этом участники звонка смогут и переписываются одновременно с просмотром фильма или подслушиванием музыки. Функция будет поддерживаться множеством приложений, таких как HBOMax, Twich, TikTok, Disney+ и другими.

Сообщения получили новый дизайн для отображения фотографий в виде коллажей или стопки фото.

Новая функция Shared with you дает возможность закрепить то, что вам присылают в iMessage, и что вы хотели бы посмотреть это позже.

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

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

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

Live Text позволяет распознать тексты, например, прямо с камеры телефона или скриншота/фотографии, сохраненной в памяти вашего девайса. Чтение доступно пока на семи языках, не включающих русский. Таким образом можно распознать не только текст на фотографии, но и место, растение, породу животного и не только. При помощи этого алгоритма теперь можно можно найти нужный чек среди ваших фотографий или фото из определенной локации. А если на фото произойдет распознавание ваших контактов или знаменитостей, система выдаст вам информацию о них.

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

В Wallet появилась возможность добавить транспортные карты различных городов, а также ключи от всего, что можно открыть электронным ключом: от вашего дома до автомобиля и номера в отеле, то есть, появилась поддержка CarKey и умных замков с UWB. Кроме того, теперь в Walllet можно добавить ваше ID с персональными данными, отсканировал водительские права. Такое ID будет действовать, например, в аэропортах.

В приложении Погоды, помимо редизайна, появилось полноэкранное отображение прогноза погоды на карте в местах поблизости от вас.

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

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

AirPods и Apple Music

AirPods Pro теперь смогут фокусироваться и усиливать голос говорящего рядом человека и тем самым работать как слуховой аппарат.

Siri сможет зачитывать важные уведомления через наушники.

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

Добавлено пространственное звучание на всех девайсах и на tvOS.

iPadOS 15

Переработаны виджеты: теперь их можно размещать и на экране Домой, а не только в центре уведомлений.

Добавили Библиотеку приложений, где можно скрывать страницы, которые вам больше не нужны, и возвращать их обратно, когда необходимо.

Многозадачность тоже улучшили: теперь активное приложение можно сдвинуть в сторону, чтобы открыть другое на экране Домой. Кроме того, теперь их можно опускать вниз, как в Windows или Mac, чтобы затем между ними быстро переключаться. Улучшен SplitView для работы с несколькими приложениями одновременно.

В Заметках появились упоминания и тэги.

Появилась функция Быстрых заметок для записи важной информации. Они будут собираться в отдельном хабе, и их можно создавать как на iPadOS, так и MacOS.

Также для iPad появится и приложение Перевода с функцией автоперевода любого текста, в том числе рукописного или с фотографий.

С помощью Swift Playgrounds теперь на iPad можно писать собственные приложения для iPhone и iPad.

Конфиденциальность, Siri и iCloud

Появилась защита конфиденциальности в Почте, которая может скрывать ваш IP-адрес или местоположение, а также время открытия письма. Также ваш IP не смогут отслеживать и трекеры в Safari.

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

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

Два улучшения iCloud: восстановление доступа к вашему аккаунту при помощи устройств доверенных людей, которым будет приходить код доступа к вашему девайсу.

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

Еще одна функция скрытие электронного адреса, а также встроенная поддержка HomeKit Secure Video.

Здоровье

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

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

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

watchOS 8

Обновленное приложение медитаций, возможность отслеживать изменения дыхания во сне и новый циферблат с 3D-портретами из фотографий, снятых на iPhone в обновленной системе watchOS 8. А также обновленное приложение для просмотра снимков, более похожее на таковое в смартфонах, и улучшенный набор текста с возможностью удаления слов и редактирования.

Появится нового стандарта умных устройств Matter, позволяющих сделать все устройства независимыми друг от друга.

Умный дом

Теперь Apple TV сможет открывать ссылки на сериалы и фильмы, которые присылают пользователю в сообщениях.

HomePod mini можно будет использовать как динамики для телевизора.

В Apple TV+ появятся профили пользователей с возможностью отслеживать прогресс по просмотру сериалов.

Обновление получит и приложение Дом для Apple Watch. Теперь с его помощью можно будет следить за глазком и еще быстрее управлять функциями дома. А камеры смогут присылать пользователю уведомления о полученной посылке.

macOS Monterey

MacOS, как и iOS, тоже получит поддержку SharePlay для совместного просмотра фильмов, а также обновленные Сообщения, Фокусировку и Заметки.

Новая функциональность Universal Control, позволяющая управлять iPad и Mac с помощью одних и тех же клавиатуры и мыши. Так, если iPad поставить рядом с MacBook, курсор сможет автоматически перейти на экран планшета. Это относится как к управлению мышью, так и тачпадом. Таким образом можно переносить файлы с устройства на устройство или, например, использовать iMac в качестве динамиков для iPhone.

Теперь пользователи смогут создавать быстрые сценарии для ежедневных задач и при помощи Shortcuts на Mac. Пока еще будет действовать и Automator, так что переход будет производиться постепенно, в течение нескольких лет.

Новый дизайн для Safari как на Mac, так и на iPad и iPhone. На Mac теперь строка браузера расположена прямо внутри вкладки. На iPhone они теперь находятся снизу и исчезают при чтении. Вкладки же, в свою очередь, можно собирать в группы и таким образом пересылать по почте.

Новинки для разработчиков

Представлены новые API для изоляции голоса, Focus и SharePlay, а также функции для сканирования 3D-объектов для последующего переноса в AR.

Язык Swift упростит создание параллельных процессов, сократив количество необходимого кода.

Теперь в App Store можно будет создавать разные страницы для приложений с возможностью подсветить разные особенности для разных типов пользователей. Так, можно будет подсветить события внутри приложений и игр и выносить их в форме виджетов на экран с приложениями.

Функциональность Xcode Cloud, позволяющая скомпилировать приложение прямо в облаке для дальнейшей работы над них сразу нескольких разработчиков и тем самым позволяющая сэкономить ресурсы железа. Когда приложение пройдет через все проверки, его автоматически разошлют тестировщикам. Эта функция станет доступна в 2022 году.

TestFlight появится на Mac, и его закрытый тест начнется уже на WWDC.


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

Подробнее..

Дайджест интересных материалов для мобильного разработчика 394 (17 23 мая)

23.05.2021 20:21:44 | Автор: admin
На этой неделе у нас новая Google I/O, доступность iOS, банки и штаны, автотесты и разумные A/B-тесты, методы атрибуции, свободная Цивилизация и многое другое.



Этот дайджест доступен в виде еженедельной рассылки. А ежедневно новости мы рассылаем в Telegram-канале.

iOS

Обертки свойств в Swift с примерами кода
Крейг Федериги назвал уровень безопасности Mac неприемлемым
Учебный курс Разработка приложений для iOS с использованием SwiftUI
Книга Про доступность iOS
Как создать приложение с использованием SwiftUI и CoreData
Swift инструмент автоматической стилизации кода в 2021
Советы iOS-разработчикам в 2021 году
App Thinning: синхронизация локализованных строк в Outlook для iOS
13 полезных методов работы с массивами в Swift
Вертикальный пейджинг в SwiftUI
SwiftUI + Core ML+ ARKit создаем приложение для определения объектов для iOS
Создаем утилиту командной строки с помощью Swift Argument Parser
Мои приложения в топе инструментов разработчиков (магазины приложений для iOS и Mac): я заработал 60 долларов
База данных Notion + iOS
Прохождение туториала Scrumdinger по SwiftUI от Apple
Взламывая iOS-интервью
Самые популярные тенденции в разработке приложений для iOS в 2021
MediumCup UI: стакан на SwiftUI
LocalConsole: консоль в приложении

Android

Банки ультимативно лезут к нам в штаны личную жизнь
Почему Kotlin хуже, чем Java?
Рисуем светом: длинная выдержка на Android
Google I/O 2021: что нового для Android-разработчиков (полный обзор)
То, чего нам так не хватало: Render Effect в Android 12
Google I/O: что нового представили Android-разработчикам
Производительность Android Runtime vs NDK
Пример модульного андроид приложения с помощью Navigation component и Koin (DI)
Developer Keynote с Google I/O 21
I/O 21: обновление Firebase
I/O 21: Android 12 Beta 1
I/O 21: 3 миллиарда устройств на Android
I/O 21: разговорный ИИ LaMDA
I/O 21: Flutter 2.2
I/O 21: Wear OS 3.0
I/O 21: Material You новый язык дизайна
Инструменты статического анализа для Android
Jetpack Compose: стили и темы
Понимаем паттерн MVVM для Android в 2021 году
Бесконечные списки с автоматической прокруткой с RecyclerView и LazyLists в Compose
Разрабатываем HelloAR в Android Studio с помощью ARCore и Sceneform
Миграция с LiveData на Kotlin Flow
Современный сплеш скрин в Android
Как мы улучшили процесс code review в инженерной команде Android
Kotlin SharedFlow или как я прекратил использовать RxJava и полюбил Flow
Интеграция Dagger 2 и Jetpack Compose
Лучшие практики View Binding
Исследуем новые тактильные функции в Android 12
Movies: кино на основе MVVM

Разработка

Три паттерна для улучшения работы с автотестами
Ремастеринг игрового контента, или как создать 800 единиц контента за семь месяцев
Flutter: флип-анимация
Wild Horizon или как осуществляется на практике мечта игродела
Все, что вы хотели знать про диалоговый UX/UI в проектировании чат-ботов
Mobile People Talks: Legacy
Podlodka #216: типографика
Исследование: кто находит работу после онлайн-обучения
Дизайн приложений: примеры для вдохновения #43
Google запустил курсы для технических писателей
Задачи с собеседований: размен
No-code платформа разработки приложений Adalo получила $8 млн
Книги о программировании на Python в Humble Book Bundle
Работает не трогай: как Snapchat переписал свое приложение для Android
10 уроков по UX дизайну, которые я хотел бы усвоить раньше
3 способа самостоятельно радикально улучшить свои навыки программирования
10 потрясающих шрифтов Google, которые вы будете использовать в 2021 году
Coinbase успешно перешел на React Native
5 самых сложных вопросов по программированию из интервью FAANG
Что не так с Flutter
5 лучших сервисов AWS для запуска любого проекта
Как развить сверхчеловеческую концентрацию при написании кода
Unciv: открытая Цивилизация

Аналитика, маркетинг и монетизация

Время деньги: анализируй А/В-тесты разумно
Какие ошибки совершает аналитик в первые полгода работы и как их избежать
Хочу всё знать о клиенте! Или как обогатить сухие факты DWH цифровыми путями и свойствами клиента из Amplitude
Игровая экономика: игры free-to-play
Somewhere Good: анти-социальная сеть
По данным Post-IDFA Alliance, UA затраты на Android выросли на 21% после внедрения iOS 14.5
Анализируем iOS 14.5: методы атрибуции
Как создавать эффективную видеорекламу для приложений
Быстрый рост неигровых приложений с Wow-booster
Нативная реклама мобильных приложений в TikTok
Все приложения делают это: крадут друг у друга. Как это влияет на мобайл и ASO?
Калькулятор экономики для мобильных подписок

AI, Устройства, IoT

Ребята взломали машину для мороженого и начали холодную войну с её производителем
Интервью с менеджером проектов АСУ: цифровизация, интернет вещей и умные города
Snap представил AR-очки Spectacles
Дата сайентисты вымрут через 10 лет
Сбер запускает набор Kidsar для AR-приложений на SberPortal
Как сделать монитор качества воздуха с помощью Raspberry Pi Zero W

Предыдущий дайджест. Если у вас есть другие интересные материалы или вы нашли ошибку пришлите, пожалуйста, в почту.
Подробнее..

Дайджест интересных материалов для мобильного разработчика 395 (24 30 мая)

30.05.2021 20:12:29 | Автор: admin
В этом дайджесте переезд на Swift и 36 секунд доступности, валидация встроенных покупок и кросс-системное тестирование, симпатичный чейнджлог, проблемы с неткодом, переезд Coinbase на React Nativeи многое другое!



Этот дайджест доступен в виде еженедельной рассылки. А ежедневно новости мы рассылаем в Telegram-канале.

iOS

Как Лёня с React на Swift переезжал
Доступность на iOS началась с 36 секунд
Самые популярные SDK после выхода iOS 14.5
Всемирная конференция Apple для разработчиков начнётся 7 июня и пройдёт в онлайн-формате
Эван Шпигель поддержал налог App Store и меры защиты Apple
Как управлять поведением клавиатуры в iOS-приложениях
MVP архитектура для iOS
Как разрабатывать приложения для iOS без Mac
Как использовать SnapKit в ваших iOS-приложениях
Как использовать Firebase Remote Config с Swift 5
3 способа стилизации представлений SwiftUI
HMS ML Kit: перевод в реальном времени (iOS Swift)
ScrollingContentViewController: простое создание скроллируемого View
NotificationToast: тосты для iOS
CalendarKit: календарь для iOS, iPadOS и macOS

Android

Интеграция и серверная валидация инаппов для стора Google Play как защититься от читеров
Обновляемся на новую версию API Android по наставлению Google
Создаем приложение для Android быстро и просто
Почему Kotlin лучше Java?
Особенности тестирования Android без Google-сервисов
Получаем результат правильно(Часть2). FragmentResultAPI
Как начинающему Android-разработчику прокачать свои навыки: 5 open source проектов для изучения
Полезные расширения Kotlin для Android
Hilt стабилен. Более простая инъекция зависимостей на Android
Повышаем уровень своего класса данных Kotlin с помощью расширений
Историческое введение в модель реактивного состояния Compose
Совершенно новое Состояние в Jetpack Compose
Улучшение преобразования кода Java в Kotlin: пример
Структурированный параллелизм в действии
Начните отсюда: 5 упражнений для подготовки вашего приложения к работе с большими экранами
Начинаем работать с WorkManager
Простые инструментальные тесты (UI-тесты) для Android в 2021 году
Введение в Security By Design
KodeEditor: редактор кода для Android
SuperForwardView: перемотка в стиле Netflix

Разработка

Почему мы решили создать отдел кросс-системного тестирования
Лаги, джиттер и потеря пакетов: откуда берутся проблемы с неткодом и как их решать
7 QA-шных грехов, которые помогут или помешают тестировщику (стать тем, кем ты хочешь)
За что банит Apple(и Google)
Как написать симпатичный чейнджлог: опыт Авито
Без тимлида не обойтись, а что насчет техлида?
Как сохранить нервы тестировщика или ускорить регресс с 8 до 2 часов
Как я хотел поработать нативным Android разработчиком, но устроился Flutter разрабом
Dart: Быстрые неизменяемые коллекции
6 способов снизить когнитивную нагрузку от интерфейса
Podlodka #217: фасилитация
Flutter Dev Podcast #27: как работает рендеринг UI
Как Coinbase перешел на React Native
Stack Overflow запустил новый ежегодный опрос разработчиков
Fuchsia получила свое первой устройство
Мой SaaS добился MRR $12.5K за один месяц: вот чему я научился
Куда уходят программисты?
Онлайн-конференция Google for Games Developer Summit 2021 пройдет в июле
Проблема дизайна это сами дизайнеры
Пользователям плевать на дизайн: как устроен хороший UX на самом деле
Хотите стать лучшим UX дизайнером? Создавайте эмоциональный дизайн
Лучшие языки программирования для изучения в 2021 году
10 вещей, которые хорошо знают опытные разработчики
Почему софтверные компании часто отвергают хороших программистов
Наплевать на доступность
Самые востребованные языки программирования в 2021 году
Избегайте блокировки CI/CD делайте свои сборки более портативными
Flutter: CRUD с использованием Firebase Cloud Firestore
Одна привычка, чтобы стать лучшим разработчиком
Что нового во Flutter 2.2
Библиотека разработчика от Google

Аналитика, маркетинг и монетизация

Датасет о мобильных приложениях
Реклама мобильных игр в первом полугодии 2021: мировая статистика
RevenueCat закрыл Серию B при оценке в $300 млн
Платформа отладки Lightrun получила $23 млн
Платформа потери веса Noom привлекла $540 млн
Тренды мобильных приложений 2021: отчет Adjust
Дейтинг-приложения предложат улучшения прошедшим вакцинацию
Google запускает рекламные кампании приложений на десктопах
Netflix думает над выходом на игровой рынок
Одних технологий недостаточно: что раздражает рекламный рынок в Apple и как она зарабатывает на закрытости системы

AI, Устройства, IoT

ML: нечеловеческие технологии для человеческих цен
TinyML. Сжимаем нейросеть
SberCloud + Intel oneAPI = льготное облако для ML-разработчиков
IBM разработала датасет Project CodeNet для обучения ИИ программированию
Как сделать бизнес на AR/VR
Mail.ru Group открыла новый набор на бесплатное обучение в Академию больших данных MADE
Microsoft использовала GPT-3 для создания кода на естественном языке
Best Buy начинает продажи смартфона для пожилых

Предыдущий дайджест. Если у вас есть другие интересные материалы или вы нашли ошибку пришлите, пожалуйста, в почту.
Подробнее..

За что банит Apple(и Google)

27.05.2021 02:21:05 | Автор: admin

У платформодержателей мобильных сторов множество причин для блокировок. Если напрямую с этим не сталкиваться, то, кажется, что все просто - не нарушай описанные правила и все будет отлично. На деле не все блокировки легко предугадать простым следованием гайдлайнов.

Рассмотрим некоторые из них.

Покупки не через сервисы Google&Apple

Начнем с одной из самых известных сейчас блокировок - удаление игры Fortnite от Epic Games из мобильных сторов. Издатель решил, что отдавать 30 процентов комиссии с каждой покупки слишком много и сделал оплату в обход стандартного механизма In-app payment. Что, конечно, запрещено. И ни Apple, ни Google не захотели терять свой доход(хотя на некоторые послабления уже пошли Apple Google).

При этом нельзя забывать, что на самом деле оплата сторонними средствами возможна в приложениях, распространяемых в сторах. Например, можно продавать реальные товары(как в Ozon) или услуги(как Uber). Но нельзя продавать то, что потребляет пользователь в самом приложении(игровая валюта, скин на персонажа и т.п.)

COVID-19

Множество блокировок было ровно год назад. Большое количество разработчиков начали выкладывать разные приложения с ковид-тематикой(от агрегаторов статей и карт распространения до фейковых анализаторов на наличие болезни). При этом реальной информацией тогда еще мало кто владел.

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

В итоге в мае сторы на поисковые запросы давали такие результатыВ итоге в мае сторы на поисковые запросы давали такие результаты

Apple ссылались на пункт 5.2.1 Apps should be submitted by the person or legal entity that owns or has licensed the intellectual property and other relevant rights.

Google блочил со ссылкой на пункт 8.3, в котором говорится, что компания не берет на себя отвественности за надзор за контентом приложений, но может заблочить, если решит, что содержимое что-нибудь нарушает.

Сейчас публикация приложений, связанных с ковид, разрешена в основном государственным организациям.

Хранение данных

Когда-то я работал в компании, которой прилетел реджект за то, что мы храним данные приложения в iCloud'е пользователя. Делали мы это не специально, а по не знанию) При этом, как оказалось, какие-то данные хранить в iCloud можно, но это должен быть сгенерированный пользователем контент.

Это самый первый пункт из iOS Data Storage Guidelines: "Only documents and other data that is user-generated, or that cannot otherwise be recreated by your application, should be stored in the <Application_Home>/Documents directory and will be automatically backed up by iCloud. "

Убрали хранение данных в локальный кеш и смогли пройти ревью.

Пермишены

В iOS 14.5 стал обязательным запрос нового пермишена - про трекинг данных пользователя. Компании принялись рассказывать юзерам на предварительных экранах почему же надо разрешить трекинг и... некоторые столкнулись с блокировками как раз из-за онбординг экрана для пермишена. Дело было в добавлении двух кнопок на этот экран. По нажатию одной - запрашивалось разрешение, второй - нет. В гайдланах это строчка "If you display a custom screen that precedes a privacy-related permission request, it must offer onlyoneaction, which must display the system alert."

При этом, например, у facebook'а получалось проходить ревью с двумя кнопками При этом, например, у facebook'а получалось проходить ревью с двумя кнопками Но позже и facebook, и instagram заменили эти экраны на однокнопочныеНо Но позже и facebook, и instagram заменили эти экраны на однокнопочныеНо

Ссылки на другие приложения

Когда я начинал разрабатывать свои приложения, то пользовался кросслинками из одного в другое. И так мои новые игры набирали лояльную аудиторию из старых. Довольно неплохо работало. Делал я это максимально примитивно - ставил иконку нового приложения в угол экрана меню старых. А еще на экране подтверждения закрытия приложения третьей кнопкой был переход в новую игру. Но через какое-то время Google начал поочередно блокировать одно приложение за другим, т.к. "Ads must not simulate the user interface of any app". Оказалось, что к подобным переходам надо явно писать, что они являются рекламой.

Слишком взрослый рейтинг

Напоследок совсем забавная для меня формулировка. Первая от Google. Приложения не пропускали в стор из-за того, что google play решил, что поставлен слишком высокий возрастной рейтинг. Сделано это, чтобы не заморачиваться с контентом, который мог где-нибудь(например, в рекламе) появиться, а детям его показывать не стоит. Но google сказал, что "We determine that some elements of your store listing may appeal to children under 13: Animated characters in app icon, young characters". Пришлось понижать возрастной рейтинг и фильтровать "опасные" категории рекламы.

А с какими блокировками приходилось сталкиваться вам?

Подробнее..

Перевод Доступность на iOS началась с 36 секунд

27.05.2021 16:21:56 | Автор: admin

8 июня 2009 года Фил Шиллер выступил на WWDC. Всего 36 секунд он неловко говорил о VoiceOver, Zoom, White on Black (с iOS 6 называется Invert Colors) и Mono Audio. Это были первые реальные специальные функции на платформе iPhone OS, как её тогда называли. Однако, они не произвели большого впечатления 36 секунд закончились, а потом не было никакой демонстрации или аплодисментов, и Шиллер просто перешел к описанию приложения Nike+.

Но в сообществе людей с проблемами зрения всё было иначе. Казалось, что время остановилось где-то после 1:51:54. Произошло нечто совершенно удивительное, и только несколько человек, казалось, понимали, что это значит.

Примечание. Статья переведена и адаптирована в качестве поддержки книги Миши Рубанова Про доступность iOS. Надеемся, что статья поможет вам глубже погрузиться в мир доступности и начать разрабатывать доступные приложения. В этом и поможет книга. Первые четыре главы уже доступны на сайте. Остальные будут выходить в канале Dodo Mobile. Подписывайтесь.

Что произошло 8 июня 2009 года

8 июня 2009 года Фил Шиллер два часа выступал на WWDC. В 1:51:54, после того, как он продемонстрировал голосовое управление и новое приложение Compass, на экране появился логотип Apple accessibility фигура в виде пряника с вытянутыми руками и ногами, которая используется по сей день.

Мы также очень заботимся о доступности.

Сказал Шиллер, и слайд переключился на экран настроек iPhone с перечислением функций доступности: VoiceOver, Zoom, White on Black (с iOS 6 называется Invert Colors) и Mono Audio.

36 неловких секунд и всё кончилось: никакой демонстрации или аплодисментов. Доступность не произвела большого впечатления, и от первых реальных специальных функциях на платформе iPhone OS, Фил перешёл к описанию приложения Nike+.

Но в сообществе людей с проблемами зрения всё было совсем по-другому. Время, казалось, остановилось где-то после 1:51:54 на видео. Произошло нечто совершенно удивительное: одни были вне себя от радости, другие сомневались, третьи пребывали в шоке.

У всех возникли вопросы: смогут ли теперь пользоваться iPhone люди, которым он был недоступен? Спустя 10 лет мы знаем ответ теперь у Apple лучшая мобильная доступность. Но всё это происходило не сразу, и не каждый шаг на этом пути был верным. Я бы хотел рассказать об этом пути.

В дополнении к моему аудио-документальному фильму 36 секунд, которые изменили все: как iPhone научился говорить, я собрал список основных этапов доступности iOS за последние 10 лет. Я сосредоточился на аппаратном обеспечении и ОС Apple. Обновления приложений Apple и сторонние приложения, которые открыли двери для новых способов использования iOS, тоже важны, но с ними список будет слишком длинным. Поэтому, за некоторыми исключениями, я обратился к особенностям доступности iOS. Многие основные функции имеют специальные приложения и преимущества, даже если они не подходят напрямую.

2007-2009: до появления iPhone

В 2007 году на Mac всего пару лет было доступно ПО для чтения экрана для людей с проблемами зрения Mac Screen Reader. Это теперь он называется VoiceOver, а в 2005 его представили как Tiger версии 10.4. До Tiger ни одна версия Mac OS X не предоставляла инструменты доступности.

Поэтому немного пользователей Mac с проблемами зрения были настроены услышать что-то кардинальное на MacWorld Expo в 2007 году. До Mac OS X Apple действительно предлагала несколько настроек доступности, и программу для чтения с экрана от сторонних разработчиков.

Источник: https://www.macintoshrepository.org/2483-outspoken-8Источник: https://www.macintoshrepository.org/2483-outspoken-8

Некоторые энтузиасты технологий с проблемами зрения перешли на Mac после прихода VoiceOver с Tiger. Именно они больше всего интересовались, будет ли доступен iPhone.

Потому что в 2007 году среди покупателей iPhone не было людей с проблемами зрения iPhone был им недоступен. Многие люди, как незрячие, так и зрячие, полагали, что этого не будет никогда.

В конце концов, как перемещаться по холодному гладкому стеклу без зрения?

Примечание: о проблеме холодного стекла у нас есть перевод статьи Будущее интерактивного дизайна в руках.

Весной 2008 года Apple добавила VoiceOver в iPod Nano. В то же время iTunes на Mac стал доступен для VoiceOver. Старое приложение Carbon раньше не работало с устройством чтения экрана.

Это означало, что незрячий человек теперь мог подключить Nano к iTunes, включить VoiceOver на устройстве, скопировать на него песни и использовать VoiceOver для поиска и воспроизведения.

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

Теперь, когда iTunes стал доступен через Mac, Apple заложила основу для доступности iPhone, сделав возможным для человека с проблемами зрения синхронизировать iPhone со своим компьютером.

Следующая остановка настоящий, доступный iPhone.

2009: iPhone OS 3, 3GS и iPod Touch

Анонс iPhone, которого все ожидали на WWDC 2009, обещал быть грандиозным. Все ждали существенного обновления с длинным списком новых функций, учитывая, что App Store существовал уже год, а за плечами Apple два года разработки. iPhone 3GS был солидным релизом, а iPhone OS 3.0 принесла такие важные и запоздалые достижения, как copy/paste.

Июнь: iPhone OS 3 и 3GS

Поспешное, позднее открытие VoiceOver, Zoom, White on Black и Mono Audio принесло только неопределенность отсутствие демо-версии не внушало доверия. Кроме того, существующие устройства даже не были совместимы с iPhone OS 3.

Чтобы получить доступ, придется подождать и купить iPhone 3GS. Пользователи, которые были довольны или, по крайней мере, смирились со своими телефонами, внезапно обнаружили, что подписались на AT&T и перешли на новый, доступный iPhone.

Как работает VoiceOver

Из четырех новых специальных функций в iPhone OS 3 самой важной была функция VoiceOver. Когда он включен, прикосновение к экрану iPhone заставляло устройство озвучивать то, что было под вашим пальцем: название приложения, пункт меню или кнопки.

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

VoiceOver также включал в себя интерфейсное устройство под названием ротор, которое работает немного как контекстное меню. Это один из самых гениальных и недооцененных элементов озвучки. Со временем его важность и функциональность только возросли. Чтобы его использовать, вы кладете два пальца на экран и поворачиваете как ручку громкости у магнитофона, а iOS произносит контекстные опции в ответ.

Источник: https://support.apple.com/ru-ru/HT204783Источник: https://support.apple.com/ru-ru/HT204783

Если, например, вы находитесь в Заметках, эти параметры позволяют читать по строкам, словам или символам, позволяя редактировать текст.

Остальные функции специальных возможностей

  • Масштабирование увеличивает экран iPhone. Pinch-to-Zoom был доступен в оригинальной ОС iPhone, но работал только в некоторых поддерживаемых приложениях, таких как Safari. Общесистемный зум увеличивал экран по всему интерфейсу.

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

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

Осень: iPod Touch третьего поколения

Следующая возможность получить доступное устройство от Apple появилась с выпуском iPod Touch третьего поколения старые модели не поддерживали iPhone OS 3.

Самым большим недостатком iPod, конечно, было отсутствие навигационных функций, предоставляемых GPS-оборудованным iPhone. Навигация представляла огромный интерес для незрячих пользователей.

Тем не менее, iPod Touch был явно лучшим мобильным устройством с поддержкой Интернета, доступным для людей с ограниченными возможностями, при ограниченном бюджете.

2010: iPad, iBooks, iPod Touch

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

Весна: iPad первого поколения и iBooks

Но ещё одна особенность первого iPad также была интересна людям с ограниченными возможностями чтения iPad был первым устройством Apple, с приложением iBooks и iBooks Store. Можно не только добавить любую книгу Apple на iPad, но и использовать VoiceOver, чтобы прочитать её вслух. Это означало, что если книга не была доступна в шрифте Брайля, на ленте или в другом доступном формате, владелец iPad всё равно мог её изучить.

На iPad первого поколения также показали предварительный просмотр новых функций, которые появятся в iOS 4 осенью. Некоторые из них были новыми жестами VoiceOver, такими как почесывание экрана двумя пальцами для перехода на экран назад.

Осень: iOS 4

Ввод текста одним касанием (Touch typing). Сначала он был представлен как второй режим набора текста на iPad. Сенсорный ввод на виртуальной клавиатуре работает быстрее для пользователей VoiceOver, чем стандартный. Не нужно выбирать, а затем дважды нажимать клавишу на клавиатуре, чтобы ввести её. Теперь это проще: опустите палец на клавиатуру, наведите на нужную кнопку и отпустите палец для ввода буквы под ним. Разделенное нажатие делает сенсорный ввод гораздо эффективнее с помощью VoiceOver. Перейти в такой режим набора можно через ротор.

В iOS 4 добавили веб-ориентированный ротор с определенными опциями для навигации по элементам в Safari. Эта функция в конечном итоге будет свернута в ротор общего назначения, но iOS 4 это то место, где впервые появились веб-опции.

Использование ротора в Safari.Использование ротора в Safari.

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

Дисплей Брайля. Источник: http://com-v.ru/tiflomarket/braille-edge-40/90_m_bild1_brailleedge/Дисплей Брайля. Источник: http://com-v.ru/tiflomarket/braille-edge-40/90_m_bild1_brailleedge/

Количество таких дисплеев, поддерживаемых iOS, увеличивается с каждой версией, и Apple ведет текущий список в Интернете.

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

Доступность получила важные обновления в iOS 4, некоторые из которых придали легитимность iOS в глазах скептиков, которые предпочитали Windows.

2011: iPhone 4s, Siri и iOS 5

iPhone 4S был первым телефоном с Siri. Это не функция доступности, как таковая, но человек с физической или зрительной инвалидностью может управлять iOS голосом, что быстрее и проще.

Осень: iOS 5

iOS 5 освободила всех пользователей от необходимости настраивать устройство с компьютера, а пользователи VoiceOver получили возможность выполнять свою собственную настройку с помощью программы чтения с экрана. Начать настройку можно было через iTunes, поскольку Mac OS X также включала программу чтения с экрана.

Тройной щелчок. Незрячим людям стало проще благодаря корректировке поведения кнопки Домой. Раньше тройной щелчок вызывал выбор между масштабированием и голосом за кадром. К сожалению, пользователь VoiceOver с проблемами зрения не мог определить нужную опцию. В iOS 5 теперь можно было сделать тройной щелчок во время процесса установки, чтобы вызвать VoiceOver он включался по умолчанию.

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

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

Выбор речи и автотекст. В iOS также добавили эти новые функции речи. При включенном Speak Selection можно выбрать текст в любом месте iOS появившееся меню теперь включает кнопку Speak Selection. Speak Auto-Text делает именно это, когда применяется автокоррекция или автокапитализация. Обе эти функции речи используют тот же выбор голосов, что и VoiceOver можно выбрать голос, который вы хотите использовать, независимо от VoiceOver, и скорость.

VoiceOver Item Chooser также дебютировал в iOS 5. При посещении веб-страницы с множеством ссылок и элементов контента вызовите средство выбора элементов, чтобы вызвать алфавитный список элементов на странице. Если знаете, что вам нужно, вводите текст, чтобы сузить поиск. Затем дважды коснитесь элемента, который хотите выбрать.

Средство выбора элементов экономит время при навигации по знакомому сайту. В качестве альтернативы выбору элементов для пользователей Bluetooth-клавиатуры также был добавлен ряд веб-специальных сочетаний клавиш VoiceOver, например, набрав H (от heading) на подключенной клавиатуре можно переходить по заголовкам

Обнаружение лиц. Дебютировало в iOS 5 в приложении камеры. При включенном VoiceOver наведите устройство на объект или объекты, и VoiceOver покажет, сколько лиц видит камера и где они находятся в кадре.

Ротор. Прежние функции веб-ротора были свернуты обратно в основной ротор. Добавили больше вариантов ротора, а также больше инструментов для управления его поведением. Можно изменить порядок элементов ротора, а также добавить или удалить элементы, чтобы упростить и настроить то, что там появилось.

Метки. Добавили пользовательскую маркировку VoiceOver, которая позволяет пользователю присваивать метку элементу управления в приложении без метки разработчика. Многие приложения частично доступны для VoiceOver люди могут перемещаться и пользоваться с помощью скринридера, хотя одна или несколько кнопок или других элементов управления могут не иметь названий, потому что разработчик этим не озаботился. Пользовательская маркировка позволяет компенсировать этот недостаток.

Особенности слуха

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

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

Новый режим слухового аппарата. Позволил устройствам iOS лучше работать со слуховыми аппаратами Bluetooth. Это было началом расширенной поддержки слуховых аппаратов, которая расцветет в более крупную инициативу Made for iPhone для слуховых аппаратов. Начиная с iPhone 5, они сертифицированы как совместимые со слуховыми аппаратами (Hearing Aid Compatible, HAC) Федеральной комиссией по связи США.

2012: iOS 6

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

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

Осень: iOS 6

Home-Click Speed. Позволяла пользователю регулировать чувствительность кнопки Home, что облегчало человеку с моторной задержкой эффективное нажатие на неё. Guided Access даже получил демо-версию WWDC Keynote.

Контекстные действия в iOS 6. У некоторых элементов появились дополнительные действия. Чтобы переключиться на них проведите пальцем вверх или вниз, двойное нажатие выполняет действие. Например, так можно пометить письмо как прочитанное или удалить. Это немного похоже на использование ротора VoiceOver, но без необходимости делать жест открытия ротора.

Карты. Получили серьезное обновление в iOS 6. Pause to Follow позволяет найти и выбрать улицу, а затем провести пальцем когда вы слышите Pause to Follow.

Применение Pause to Follow на карте.Применение Pause to Follow на карте.

Действие даёт представление в каком направлении проходит дорога, и насколько она прямая или извилистая. Звуковая обратная связь направляет, когда вы идете по улице, и визуально подсвечивается для людей с низким зрением. Ротор VoiceOver также включал в себя пункт Точки интереса позволяющий пользователю пролистывать близлежащие важные и интересные места, чтобы найти конкретный объект или просто просмотреть свое окружение.

Guided Access. Новинка в iOS 6. Позволило ограничить доступ к элементам iOS, например, отключить кнопки громкости или запретить пользователям доступ к определенным приложениям. Управляемый доступ позволяет учителям сосредоточить внимание учащихся, часто детей со спектром аутизма. Вызовите управляемый доступ и свободно передайте ученику iPad, который может запускать только то образовательное приложение или обучающую игру, которую вы хотите использовать. Также можно замаскировать кнопки или другие элементы интерфейса в выбранном приложении.

AssistiveTouch. AssistiveTouch делает ключевые элементы управления устройствами доступнее.

AssistiveTouchAssistiveTouch

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

2013: iOS 7

Apple лихо переработала внешний вид интерфейса iOS и практически всех своих собственных приложений. Сквеоморфизм исключили, а тонкие шрифты, прозрачные слои и анимация добавили.

Шаг назад с iOS 7

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

Благодаря отрицательной реакции на iOS 7 Apple исправила то, что сломала: откатила первоначальный дизайн ОС и добавила настройки доступности, которые могли бы компенсировать проблематичность определенных элементов дизайна. Например, они включали в себя формы кнопок, уменьшающие движения и метки включения/выключения. Кроме того, iOS 7 представила увеличенную контрастность, полужирный текст и настройку размера шрифта. Они помогли компенсировать проблемы 7.0.

Все выровнялось в iOS 7.1. Это был единственный релиз iOS, созданный специально для слабовидящих пользователей вроде меня.

Более крупный текст используется внутри сообщений.Более крупный текст используется внутри сообщений.

Доступность на виду. Несмотря на недостатки, iOS 7 была большим шагом в сторону доступности. Это видно, если заглянуть внутрь приложения Настройки. Доступность переместили с самого низа Общей категории почти наверх. Это важно и на эмоциональном уровне для пользователей, и на практическом уровне для тех, кто не тратил много времени на использование инструментов доступа, но планировал исследовать теперь, когда iOS 7 добавила так много.

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

Обновления. iOS 7 представила множество основных обновлений интерфейса, включая Центр управления и усиленный переключатель приложений. Они были сразу же доступны VoiceOver и AssistiveTouch, а также новому интерфейсу управления коммутатором.

Динамичный Текст. Функция Увеличенный текст была доступна в iOS 6, хотя и не сильно повлияла на iOS. Можно выбрать один из шести увеличенных размеров текста и увидеть их в нескольких приложениях, таких как Сообщения или Почта.

Более крупный текст в iOS 7 и поздних версиях это пользовательский интерфейс для Динамичного Текста. Если разработчик поддерживает Динамичный тип в приложении, пользователь может использовать ползунок Размера текста, чтобы сделать его больше или меньше. Даже Apple не поддерживала Динамический тип во всех своих приложениях iOS 7, но постепенно исправила. Многие другие разработчики приняли эту функцию, но не все.

Слуховые аппараты iPhone. Apple никогда не создавала собственные слуховые аппараты, но работала с производителями, чтобы увеличить количество доступных продуктов MFi программу Made for iPhone. Технологические усовершенствования в характеристиках Bluetooth Low Energy (BLE) и согласованные усилия Apple распространили MFi на слуховые аппараты, которые компания начала сертифицировать как совместимые с устройствами iOS.

Субтитры. Фильмы и телепередачи, купленные в iTunes или приобретенные из других источников, можно просматривать с подробными субтитрами или обычными. В iOS 7 появился интерфейс для настройки стиля и размера текста, появляющегося на видео с субтитрами.

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

Switch Control. AssistiveTouch был частью iOS начиная версии 6. Switch Control расширил идею интерфейса, который поддерживает пользователей с моторными задержками.

Сканирование главного экрана с помощью переключателя управления.Сканирование главного экрана с помощью переключателя управления.

С его помощью мы используем:

  • внешние переключающие устройства, которые представляют собой кнопки с двумя состояниями;

  • сам экран iOS в качестве переключателя или даже камеры: глядя влево или вправо, мы активируем переключатель на основе камеры.

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

Многие пользователи Switch Control оснащают свои iOS-устройства несколькими устройствами. А iPad, установленный на инвалидном кресле вместе с переключателями, может создать очень эффективную iOS-установку для человека с тяжелыми двигательными нарушениями.

Быстрый доступ к специальным возможностям. Раньше эта функция называлась Triple-Click Home. Позволяет включать и выключать специальные возможности с помощью тройного щелчка. Теперь на тройное нажатие можно добавить несколько специальных функций. При срабатывании iOS покажет меню из тех, которые вы включили.

2014: iPhone 6 и 6 Plus

Первые большие айфоны включили новую функцию под названием Display Zoom.

Это не функция доступности, но она увеличивает вид экрана, уменьшая разрешение. На экране появляется меньше значков приложений, а на некоторых экранах iOS-текст больше. Масштабирование дисплея можно сочетать с функцией масштабирования специальных возможностей или по отдельности.

Осень: iOS 8

Несколько новых функций в iOS 8 были важны для доступности.

Клавиатура QuickType. Предсказывала текст и отображала панель с предложениями по набору текста над виртуальной клавиатурой.

Новый режим набора текста прямым касанием позволял пользователю VoiceOver положить обе руки на виртуальную клавиатуру и просто начать печатать. QuickType, автокоррекция и собственное ноу-хау VoiceOver вместе помогают исправлять ошибки набора с высокой точностью. Естественно, это экономит много времени и сил, и значительно улучшает набор текста с помощью прямого прикосновения, особенно для пользователей iPad.

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

Использование контроллера масштабирования.Использование контроллера масштабирования.

Алекс. В iOS 8 из Mac OS X пришёл голос Алекс. У Алекса есть естественное звучание дыхания во время разговора, что намного удобнее чтения длинных текстов, чем более старые альтернативы из iOS 5.

Оттенки серого. В iOS 8 появился Режим оттенков серого для некоторых людей отсутствие ярких цветов на экране легче для восприятия.

Обновления Guided Access. Обновления включают таймеры, поддержку активации Touch ID и улучшенный масштаб: новый контроллер масштабирования позволял пользователю выбирать область экрана для масштабирования, регулировать скорость масштабирования и использовать цветовые фильтры для адаптации к дальтонизму.

Ввод с экрана Брайля. Как и функция рукописного ввода, экранный ввод Брайля облегчает ввод текста на экране.

Вместо того, чтобы рисовать символы пальцем, мы используем метафору ячеек Брайля для ввода ячеек Брайля на экране. Это полезная функция для тех, у кого нет удобного дисплея Брайля при работе с iPhone.

Speak Screen. Функция полезна для тех, кто не использует озвучивание текста, но слушает длинные отрывки текста. После включения просто проведите двумя пальцами вниз от верхней части экрана, чтобы его содержимое, например, электронная почта было произнесено. Speak Screen помещает на экран всплывающее меню с возможностью изменения скорости чтения, перемещения вперед или назад, остановки и начала речи.

Экран Speak используется внутри Safari.Экран Speak используется внутри Safari.

2015: Apple Watch и iOS 9

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

3D Touch. Функция появилась на новых iPhone в iOS 9. Несмотря на альтернативные голосовые жесты и необходимость сильно нажимать, чтобы вызвать 3D Touch, пользователи VoiceOver с поддерживаемыми телефонами получили доступ к жестам 3D Touch первого уровня, а также Peek и Pop.

Многозадачность iPad. Появились новые жесты, которые позволяли пользователю VoiceOver работать с Split View или Slide Over. Опять же, пользователи специальных инструментов могли пользоваться новыми инструментами прямо из коробки.

С точки зрения доступности iOS 9 не выдающаяся версия. Но в ней появились новые настройки для людей с физическими недостатками, а также некоторые обновления VoiceOver. Вот исчерпывающий список обновлений, связанных с VoiceOver.

Touch Accommodation. Эта новая функция позволяет пользователю регулировать чувствительность сенсорного экрана и время касания. Полезно для людей с моторными задержками, которые случайно активируют предметы прикосновением или нуждаются в более чувствительном действии для регистрации движений пальцев.

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

Switch Recipes для Switch Control. При использовании управления переключателем каждый переключатель выполняет одну функцию. Функция Switch Recipes эффективно позволяет пользователю создавать комбинации действий.

Изменения Ротора выбора текста VoiceOver. Изменения в роторе VoiceOver облегчили выбор текста по символу, слову, строке или странице.

2016: iOS 10

Изменения в iOS 10 в основном косметические. Но не все.

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

Новый редактор произношения. Позволяет произносить или вводить имя так, как его должен произносить VoiceOver, и сохранять правильное произношение. А с VoiceOver audio routing можно передавать звук на устройство по вашему выбору, например на Bluetooth-динамик. Теперь Switch Control позволяет пользователям управлять устройствами, подключенными к устройству iOS, включая Apple TV.

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

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

Когда лупа стала функцией iOS, она была доступна непосредственно из Центра управления или с помощью ярлыка специальных возможностей. Мы могли применять цветовые фильтры, как это часто бывает в электронных портативных лупах, ориентированных на рынок слабовидящих.

Цветовые фильтры. iOS предлагала переключение оттенков серого с iOS 8, но теперь появились цветовые фильтры, предназначенные для настройки вида экрана в зависимости от потребностей пользователей с тремя распространенными формами дальтонизма.

Программное обеспечение TTY. Пользователи iPhone всегда могли подключать свои телефоны к TDD (телекоммуникационное устройство для глухих) если у них был соответствующий аппаратный адаптер. Начиная с iOS 10, можно звонить или отвечать на звонок TTY без допоборудования, а также сохранять стенограммы звонков.

2017: iOS 11

iPhone X первое iOS-устройство без кнопок Home. Это повлияло на доступность: отсутствие кнопки Home изменило жесты по умолчанию, используемые для таких вещей, как open Control Center или App Switcher.

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

iOS 11 была первой версией iOS, которая поддерживает устройства Face ID. Некоторые люди с ограниченными возможностями, особенно незрячие и с протезами глаз, не могут уделять необходимое внимание датчику Face ID. Поэтому iOS добавила переключатель, который позволяет разблокировать телефон без зрительного контакта. Из-за этого Face ID вызывает споры в сообществе людей с проблемами зрения из-за предполагаемого риска безопасности. Также некоторым слепым пользователям трудно заставить Face ID работать.

Однако функция всё равно полезна. Переключатель Require Attention, который включен по умолчанию (функция безопасности) предотвращает разблокировку телефона, если он просто проходит перед лицом своего владельца. Выключение этого переключателя позволяет большему количеству незрячих людей разблокировать телефон с помощью Face ID. Но пользователь потенциально рискует получить телефон разблокированным без их согласия. При настройке устройства, оснащенного Face ID, с помощью VoiceOver пользователю предлагается оставить его включенным или выключить.

Новые возможности. iOS 11 также принесла несколько новых и обновленных версий специальные возможности, например, поддержку VoiceOver для перетаскивания и специальные жесты VoiceOver для владельцев iPhone X. VoiceOver также добавил новый метод перемещения приложений, который был частью iOS 10. Теперь можно использовать ротор для выбора и перетаскивания нескольких приложений в любое место на любом домашнем экране.

Смарт-инверсия цвета. Invert Colors появились ещё в iOS 3, и отображали всё как обратное нормальному внешнему виду. Но Smart Invert Colors отображает изображения как положительные, а не отрицательные, до тех пор, пока рассматриваемое приложение поддерживает его.

Вы все еще можете выбрать между Invert Colors и Smart Invert Colors и добавить их в ярлык специальных возможностей.

Но меню или фон некоторых приложений неправильно отображаются в цветах, контрастирующих с текстом или значками поверх них в режиме Smart Invert Colors. Это даже иногда происходит в приложениях Apple.

В основном это проблема разработчиков, которые не задумывались как будет вести себя их интерфейс и изображения при включенном Smart Invert Colors. Сочетание этих двух проблем причина того, что ни одна из опций инвертирования не работает как эффективный тёмный режим для iOS. Из того, что я видел, тёмный режим предлагает разработчикам возможность использовать затемнение и слои для настройки внешнего вида интерфейса. Это может быть полезно и для пользователей Smart Invert Colors, а также для общего понимания того, что люди, не имеющие слабого зрения, пытаются использовать iOS в тёмном режиме.

Type to Siri. Если вы не можете говорить или это неудобно, Type to Siri даёт возможность выдавать команды Siri с клавиатуры. Можно печатать с виртуальной, с Bluetooth-клавиатуры или в шрифте Брайля с дисплея Брайля.

2018: iOS 12

Все выпуски iOS содержат ошибки. Пользователи специальных возможностей часто находят те, которые относятся к функциям, что они используют каждый день и ждут, пока Apple их исправит, например, когда шрифт Брайля и VoiceOver глючили в iOS 11. Но, как и iOS в целом, iOS 12, казалось, исправила много проблем доступности и добавила некоторые новые функции.

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

Живое Прослушивание. Уже некоторое время можно использовать микрофон iPhone как усилитель окружающего звука, посылая звук на слуховой аппарат. В iOS 12 функция Live Listen была расширена до AirPods. Теперь можно слышать собеседника даже если вокруг шумно.

2019: iOS 13

Доступности уделили много внимания на WWDC 2019. Вот несколько важных особенностей.

Голосовое управление. Последняя и совершенно новая функция специальных возможностей, анонсированная для iOS 13, а также Mac OS Catalina, имеет очень старое название. До появления Siri в iOS была функция голосового управления (и до сих пор существует). Но можно было только инициировать телефонный звонок или воспроизвести песню с помощью голосовой команды.

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

Тёмный режим. Мы не знаем всех различий между грядущей основной функцией тёмного режима и Smart Invert Colors. Apple заявила, что разработчики смогут использовать многоуровневый подход к своим интерфейсам, так что не все экраны или их части должны будут иметь одинаковый тёмный оттенок. Выглядит как улучшение по сравнению со Smart Invert Colors. Если разработчики будут тщательно применять слои, тёмный режим может стать подходящей альтернативой умным инвертированным цветам для некоторых людей с плохим зрением, которые его используют.

Итог

Если вы измеряете доступность iOS по количеству доступных сегодня функций, 2009 год кажется примитивным временем. В тот год на программном слайде WWDC Фила Шиллера появилось всего четыре пункта. Но один из них VoiceOver точно революционизировал реальную доступность на iPhone почти сразу.

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


Полезные материалы:

Статьи по VoiceOver:

Voice Control и VoiceOver: как адаптировать приложение для незрячих или неподвижных.

VoiceOver на iOS: каждый контрол ведёт себя по-разному.

VoiceOver на iOS: решение типовых проблем.

Другие полезные:

Зачем и как мы пишем постмортемы по критичным багам.

Будущее интерактивного дизайна в руках.

Как выйти на китайский рынок с mini-app для WeChat, чтобы не прогореть.

На пути к 10x инженеру: шорткаты, сниппеты, шаблоны.

Подписывайтесь на Dodo Engineering chat в Телеграм будем обсуждать статью, и на канал там новости и разное интересное.

Подробнее..

Как сделать экран подтверждения СМС-кода на iOS

03.06.2021 16:16:28 | Автор: admin

Привет, Хабр!

Меня зовут Игорь, я Head of Mobile в компании AGIMA.

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

Важно: в примере кода на github будет полноценный пример с вводом номера телефона и кодом, но экран ввода номера телефона совсем скучный, поэтому сегодня мы вводим код :)

Выглядит не очень сложно, но, если присмотреться, функционал экрана довольно большой, а именно:

  • отправить код на сервер;

  • включить таймер повторной отправки + отобразить визуально;

  • после завершения таймера показать кнопку отправить еще раз;

  • отправить повторный запрос на получение кода;

  • отобразить все ошибки;

  • обработать успешное подтверждение кода.

Если попробовать разделить экран на UI и логику, получается примерно такое взаимодействие между логикой и интерфейсом.

Можно, конечно, отправить всю логику про таймеры и isLoading на View слой, но мне больше нравится относить это к логике. Особенно учитывая то, что я большой поклонник MVVM+Rx (и буду это использовать в статье), это более чем уместно смотрится. Ну да ладно.

ViewModel в этом случае играет роль некоего преобразователя пользовательских действий: у нее есть input и output (видно на картинке выше). За навигацию будет отвечать кто-то еще, например, координатор.

Со стороны UI нам будут интересны следующие компоненты:

final class ConfirmCodeViewController: BaseViewController {  /// поле ввода кода  private lazy var codeTextField = CodeTextField()  /// лейбл для отображения ошибок   private lazy var errorLabel = UILabel()  /// один лоадер для запросов на отправку кода и на повторный запрос кода  private lazy var loader = UIActivityIndicatorView()  /// лейбл с обратным отсчетом для повторной отправки кода  private lazy var timerLabel = UILabel()  /// кнопка повторной отправки кода  private lazy var retryButton = UIButton(type: .system)  /// это все будет в стеквью  private lazy var stackView = UIStackView()}

ViewModel будет выглядеть так:

/// Например, после успешного подтверждения кода нам могут предложить ввести перс. данныеenum AuthResult {case successcase needPersonalData}protocol ConfirmCodeViewModelProtocol {    /// Введенный пользователем код для подтверждения    var code: AnyObserver<String> { get }        /// Пользователь нажал на отправить повторно    var getNewCode: AnyObserver<Void> { get }        /// Результат подтверждения кода    var didAuthorize: Driver<AuthResult> { get }        /// Один индикатор на все запросы на этом экране    var isLoading: Driver<Bool> { get }        /// Ошибки из всех запросов на этом экране    var errors: Driver<String> { get }        /// Таймер отправки нового кода    var newCodeTimer: Driver<Int> { get }        /// Запросили новый код при нажатии на отправить заново    var didRequestNewCode: Driver<Void> { get }      /// Таймер отправки нового кода запущен    var codeTimerIsActive: Driver<Bool> { get }}

Обратите внимание, что при таком подходе мы стараемся не использовать PublishSubject, BehaviourRelay итп, чтобы четко разделить input и output у ViewModel. Теперь давайте это все свяжем.

View отдает следующие потоки данных:

let codeText = codeTextField.rx.text.share()codeText    .bind(to: viewModel.code)    .disposed(by: disposeBag)retryButton.rx.tap    .bind(to: viewModel.getNewCode)    .disposed(by: disposeBag)

ViewModel будет как-то (покажу ниже) обрабатывать ввод кода пользователя, а также делать запрос на повторную отправку кода, если мы нажмем на кнопку.

Сначала давайте посмотрим ViewModel целиком, далее разберем ее более подробно.

ViewModel рассмотрим по кусочкам:

let _codeSubject = PublishSubject<String>()self.code = _codeSubject.asObserver()let codeObservable = _codeSubject.asObservable()let validCodeObservable = codeObservable.filter { $0.count == codeLength }

_codeSubject это поток данных из textfield ввода кода.

validCodeObservable отфильтровывает значения нужной длины, которые мы будем отправлять на сервер.

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

let codeEvents: Observable<Result<Void, Error>> = validCodeObservable    .flatMap { (code) in        authService.confirmCode(code: code, token: token).materialize()    }.share()

Собственно, отправка кода на сервер :) Обращаем внимание на .materialize(). Поскольку мы планируем использовать этот Observable в реактивных цепочках, мы не хотим получить ошибку и прерывать их. materialize позволяет завернуть все значения и ошибки в Result<Value, Error> и тем самым мы никогда не прервем реактивную цепочку из-за ошибки.

Ранее я описывал другой вариант с помощью RxAction, его также можно использовать для создания потоков событий значений, ошибок и isLoading.

Состояние загрузки

Здесь довольно интересный момент. Если мы получили валидный код, готовый к отправке, то мы отображаем интерфейс загрузки. Если мы получили ответ от сервера, это означает, что нам надо скрыть состояние загрузки. Таким образом, мы можем взять эти потоки данных (на примерах выше), смаппить их в true или false и забиндить в isLoading.

didAuthorize = codeEvents.elements()...

.elements() работает как фильтр и пропускает только значения из codeEvents и игнорирует ошибки. Напомню, что тип значений у codeEvents это Result<Void, Error> , что является частью RxSwiftExt.

Таймер повторной отправки кода

Таймер включается при следующих событиях:

  • мы отправили код на подтверждение (validCodeObservable.mapTo(Void()));

  • мы перезапросили код (didRequestNewCode);

  • сразу же при заходе на экран (.startWith(Void())).

Именно это описано в строчке Observable.merge... Сам таймер делается стандартными средствами RxSwift. Останавливаем таймер с помощью оператора take(while:), пока значение таймера не станет равно 0.

Лейбл с таймером и кнопка переотправить должны скрываться/показываться в зависимости от того, активен ли таймер:

viewModel.codeTimerIsActive    .drive(retryButton.rx.isHidden)    .disposed(by: disposeBag)        viewModel.codeTimerIsActive    .not()    .drive(timerLabel.rx.isHidden)    .disposed(by: disposeBag)

За ошибки отправки и запроса нового кода у нас будет отвечать один поток данных errors.

errors = codeEvents.errors().merge(with: fetchNewCode.errors())            .compactMap { ($0 as? ErrorType)?.localizedDescription }            .asDriver(onErrorJustReturn: "")

Также запретим редактировать код, во вркмя того, как он отправляется:

viewModel.isLoading    .not()    .drive(codeTextField.rx.isEnabled)    .disposed(by: disposeBag)

ViewModel получилась довольно-таки тестируемая, поэтому давайте напишем тесты! Я приведу примеры тестов, которые будут показывать, как ViewModel реагирует на пользовательский ввод. Создадим вспомогательный метод, который будет создавать поток событий ввода кода. Внимание, используется RxTest!

class ConfirmCodeViewModelTests: XCTestCase {    // properties// methods     //MARK:- Helpers    private func bindCodeInputEvents(        _ events: [Recorded<Event<String>>] = [.next(100, "1"), .next(200, "11"), .next(300, "111"), .next(400, "1111")])    {        codeInputEvents = scheduler.createHotObservable(events)        codeInputEvents.bind(to: viewModel.code).disposed(by: disposeBag)    }}

Например, таймер отправки нового кода должен запускаться и корректно отрабатывает сразу после открытия экрана напишем вот такой тест:

   func test_timerInvokedAutomatically() {        let sut = scheduler.start(created: 0, subscribed: 0, disposed: 1000) { self.viewModel.newCodeTimer }        XCTAssertEqual(sut.events, [.next(1, 2), .next(2, 1), .next(3, 0)])    }

Или вот такой: проверим, что у нас передается на UI событие об ошибках

 func test_errorEmmitedValueAtFailure() throws {        bindCodeInputEvents()        setConfirmCodeResult(.error(0, MockError.confirmFailure))         let sut = scheduler.start { self.viewModel.errors }        XCTAssertEqual(sut.events, [.next(400, "confirmFailure")])    }

Полный код тестов, да и вообще весь пример можно найти тут. Требования могут слегка меняться от проекта к проекту (например, код можно отправлять по кнопке а не автоматом), но этот код достаточно несложно приспособить к подобным изменениям.

Ну, а если вам понравился наш подход, вам интересны большие проекты по мобильной разработке, тогда напишите нам.

Подробнее..

Дайджест интересных материалов для мобильного разработчика 396 (31 мая 6 июня)

06.06.2021 16:09:40 | Автор: admin
Сегодня в нашем дайджесте архитектурные паттерны и победители Swift Student Challenge, инициализация цепочек и цветов Fuchsia, инди-акселератор и инди-фестиваль от Google, Android 12 для разработчиков, $643 млрд из App Store и многое другое!



Этот дайджест доступен в виде еженедельной рассылки. А ежедневно новости мы рассылаем в Telegram-канале.

iOS

Архитектурные паттерны в iOS: привет от дядюшки Боба, или Clean Architecture
Тернистый путь внедрения Swift Package Manager. Доклад Яндекса
Swift и CoreData. Или как построить Swift ORM на основе Objective-C ORM
Как сделать экран подтверждения СМС-кода на iOS
Мои приложения для разработчиков вышли в топ iOS и Mac App Store: сколько это принесло?
WWDC21: Школьники и студенты из России победители Swift Student Challenge
Объявлены номинанты Apple Design Awards 2021
Добавляем поддержку Siri в iOS-приложение за считанные минуты
Как сериализовать и десериализовать объекты в iOS
Как улучшить время компиляции и выполнения Xcode
Удаление фона с помощью Core ML и SwiftUI
Как извлечь функциональность из устаревшего iOS-кода
Приложение для чата без пароля для iOS с Auth0
Как добавить Swift-код в качестве кастомной LLDB команды
Design to Code: превращая дизайн в код
SPIndicator: индикатор в стиле Apple

Android

Проекты в Gradle 7: как не зависеть от зависимостей
Всё о PendingIntents
Инициализация Rx цепочки
Proto DataStore + AndroidX Preferences на Kotlin
Подробный обзор Android 12 для разработчиков
Введение в систему Снапшотов Compose
Недоверенные события касания
Понимаем юнит-тесты для Android в 2021
Polestar предлагает эмулятор для разработчиков, создающих приложения для Android Automotive
QA-инженеры, функциональное и UI-тестирование в Azimo
10 лучших библиотек для разработчиков Android в 2021 году
Сохранение данных на Android с помощью Room Database и Data Store Руководство для начинающих
CheckboxQuestions: вопросы и чекбоксы
Compose Space Invaders: игра для декстопа на Jetpack Compose
Carousel Recyclerview: красивая карусель

Разработка

Как художнику найти работу мечты в геймдеве. А также советы по оформлению портфолио
4 технических решения, которые делают API сервис успешным
C# vs Kotlin
Как и зачем Mail.ru Group провела редизайн мобильной версии главной страницы портала
Mobile People Talks: какого же цвета Fuchsia?
Podlodka #218: схемотехника
HarmonyOS заработала на смартфонах
Новый SDK от Loomдобавляет видео-сообщения в любые веб-приложения
Facebook открывает Messenger API в Instagram для всех
Задачи с собеседований: зарплата
Дизайн приложений: примеры для вдохновения #44
Stack Overflow продан за $1.8 млрд
Что не так с Flutter?
Исследование продакт-менеджеров 2021 от Product Plan
Как оставаться в физической и ментальной форме, продолжая программировать
О создании гибкого пользовательского интерфейса на примере Instagram Threads
Представляем новый язык дизайна Material You от Google
Сеты бесплатных иконок для разработчиков и дизайнеров
Как привлечь первых 100 клиентов в SaaS: 5 простых шагов
Следующим стартапом на триллион станет образовательная компания
5 задач для автоматизации с помощью Python
Я не мог быстро тратить деньги, и это чуть не убило мой стартап
Flutter 2.2: создаем первую Universal Windows Program (UWP)
Мой код плохо пахнет, но все в порядке
Как создать свою первую Облачную функцию Firebase
5 вещей, которые я узнал после двух лет работы инженером-программистом в Microsoft
Test-driven Development для создания пользовательских интерфейсов
Мой опыт интервью в Twitter
Flutter: создание красивых приложений для Windows удобная структура дизайна и навигация
Вселенная no-code/low-code стартапов и ее игроки
Пример дизайна: Safe Space wellness-приложение для Android
База данных с вопросам из интервью в Apple

Аналитика, маркетинг и монетизация

В Android также ограничивают действие рекламного идентификатора
make sense: О запуске агротех-стартапа
Voodoo открывает летний конкурс гиперказуальных игр
Google запускает Indie Games Accelerator и Indie Games Festival
Продажи в App Store в 2020 выросли на 24% до $643 млрд
Создатели читов для PUBG Mobile заработали $77 млн
3 лучшие техники геймификации
Greg: приложение для любителей растений
Маркетплейс для разработчиков Malt получил 80 млн
Социальная сеть Poparazzi стала 1 App Store: секреты роста
Проектирование продуктов, формирующих привычки
Ошибки при расчете юнит-экономики
9 способов встроить виральность в ваш продукт
Как создать отличные скриншоты для страницы приложения в App Store

AI, Устройства, IoT

Учиться, учиться, и ещё раз учиться?
Теория игр как механизм для анализа крупномасштабных данных

Предыдущий дайджест. Если у вас есть другие интересные материалы или вы нашли ошибку пришлите, пожалуйста, в почту.
Подробнее..

Создание прекрасных приложений с помощью Xamarin.Forms

09.06.2021 10:16:43 | Автор: admin

Есть вопрос, который мне постоянно задают в Твиттере: как создавать приложения с крутым дизайном с помощью Xamarin.Forms? Это отличный вопрос, ведь любой может создавать красивые приложения, немного вдохновившись и поработав над стилем. Я не дизайнер и не претендую на звание дизайнера, но есть много отличных источников вдохновения для дизайна приложений, включая Dribbble, Uplabs и другие. Эти дизайны от талантливых людей со всего мира могут повлиять на внешний вид ваших собственных приложений.

Приложение для ресторана от Oludayo AlliПриложение для ресторана от Oludayo Alli

Встроенные возможности Xamarin.Forms

В Xamarin.Forms есть несколько функций, которые можно использовать, чтобы воплотить важные проекты в жизнь. Зачем вам что-то, кроме нового Shapes API для рисования фигур, линий, многоугольников и многого другого. Хотите, чтобы ваши собственные элементы управления были единообразными? Как насчет добавления Material Design с помощью одной строчки кода. А еще сгруппируйте свои коллекции с помощью CarouselView в сочетании с IndicatorView и, конечно же, CollectionView.

Приложение "Галерея напитков" от Javier SurezПриложение "Галерея напитков" от Javier Surez

Пойдите дальше с кастомными элементами управления от сообщества

Xamarin Community Toolkit добавляет отличные элементы управления, включая DockLayout, Shield, TabView и другие. Но есть еще более потрясающие элементы управления от сообщества, включая потрясающие Magic Gradients, PancakeView, MaterialFrame, CardView, Shadows и многие другие. Наконец, мы не можем забыть SkiaSharp, систему 2D-графики общего назначения для .NET.

Компонентная экосистема

Переиспользуемые компоненты пользовательского интерфейса от ведущих поставщиков компонентов, таких как Telerik, UX Divers, GrapeCity и Syncfusion, помогут вам быстро повысить продуктивность. Обязательно ознакомьтесь с множеством вариантов, когда будете готовы начать работу.

Вдохновляйтесь

Наш коллега Хавьер уже несколько лет собирает интересные примеры крутых приложений с открытым исходным кодом, созданных с помощью Xamarin.Forms, которые вы можете изучить на GitHub. Выше вы уже видели несколько из этих приложений, но вот еще, чтобы вас вдохновить.

Кошелек карт от Altevir Кошелек карт от Altevir Приложение для авиаперелетов от Leomaris ReyesПриложение для авиаперелетов от Leomaris ReyesКнига рецептов от Steven ThewissenКнига рецептов от Steven ThewissenCake app от Shaw YuCake app от Shaw Yu

И есть еще очень много прекрасных дизайнов. Вы даже можете добавить свой собственный, просто создав pull request в репозитории Хавьера на GitHub.

Adobe XD Exporter

Многие дизайны, которые вы найдете в интернете или получите от вашего дизайнера, могут быть созданы с помощью таких инструментов, как Adobe XD. Вы можете легко импортировать цвета и стили в свое приложение Xamarin.Forms благодаря экспортеру XD в Xamarin.Forms (его автор -- наш коллега Kym Phillpotts).

Создавайте красивые приложения

Расскажите нам о своих приложениях, оставив комментарии ниже или отправив pull request в репозиторий Хавьера на GitHub.

Подробнее..

Apple убивает TeamCity, Bitrise, Appcenter, Fastlane, Firebase, Sentry и иже с ними. Краткий обзор Xcode Cloud

10.06.2021 14:04:32 | Автор: admin

Заголовок конечно громковат, может не убивает, но уменьшит им доходы точно. Давайте кратко посмотрим что представила Apple на WWDC 2021, что такое Xcode Cloud?

Xcode Cloud - это сервис CI/CD, встроенный в Xcode и разработанный специально для разработчиков Apple. Он ускоряет разработку и доставку приложений, объединяя облачные инструменты, которые помогают создавать приложения, параллельно запускать автоматические тесты, доставлять приложения тестировщикам, а также просматривать отзывы пользователей и управлять ими.

Цикл разработки по мнению Apple заключается в этапах 1) Написать код 2) протестировать его 3) Интегрировать (в текущий) 4) Доставить до пользователя 5) Улучшить, и по новой. На то он и цикл. В принципе похоже на правду, так оно и есть.

Если вы хоть раз настраивали CI/CD для iOS приложений, вы знаете примерно какие там шаги, ничего сложного, но это может включать в себя использование нескольких сервисов, генерации сертификатов и тд и тп.

Теперь же Apple предлагает нам сделать это все не выходя из Xcode, давайте взглянем на процесс.

Для начала нам нужно настроить первый workflow, а потом уже который будет пробегать при PR/MR (pull request/merge request) на main/develop ветку в системе контроля версий.

I CI/CD

1) Жмем в новом Xcode при подключенном сервисе Xcode Cloud кнопку "создать workflow" и видим настройки

Name - название воркфлоу, Start condition когда запускать воркфлоу (например при изменении в main ветке), Environment - можно выбрать стабильную версию Xcode или новую бета версию, Actions - что собственно надо сделать, обычно выполнить archive и опубликовать например в TestFlight, после прогонки тестов, Post-Actions - что сделать после того как воркфлоу пройден, например написать в slack/telegram канал об этом событии

2) Выбираем репозиторий где хранится наш код

3) Выбираем с какой ветки собрать билд (при первой настройке)

Собственно готово, теперь можем посмотреть как выглядит в Xcode место где можно управлять сборками, запускать их, пересобирать и тд

Давайте теперь посмотрим как выглядит управлени воркфлоу (выше показан путь настройки первой сборки)

1) Выбираем "управление воркфлоу"

2) Выбираем настройки (например при pull/merge request что-то выполнять)

3) Выбираем какие тесты мы хотим прогнать в воркфлоу (UI или Unit тесты), я так понимаю речь именно про нативные тесты, про Appium и тд, пока ничего не известно.

4) И выбираем отправить сообщение в Slack после того как воркфлоу пройден

5) Готово

II Тесты

1) Давайте посмотрим как выглядит интерфейс работы с тестами, мы видим тут тесты которые пройдены при сборке а также устройства на которых они прогонялись

2) Посмотрим какие конкретно тесты прогнались на iPad Air, видим что тест кейс с Light mode, портретный режим, с Английским языком, далее видим какие конкретно тесты пройдены

3) Ну и совсем чудеса, можно смотреть скриншоты пройденных тестов

4) Можно также посмотреть какой тест упал, можно также пометить тест как Flaky (Флаки тест или другими словами тест неактуальный, который надо либо удалить либо переписать), для этого используется XCTExpectFailure (что в переводе логично видно по названию метода ожидаемый фейл)

Удобно.

III - Работа с системой контроля версий (и переписка прямо в коде в Xcode)

1) Изменения теперь видно еще нагляднее (привет всем кто пользуется визуальными штуками, а не через консоль при работе с git). Сверху мы видим наши локальные изменения (которые мы накодили) а снизу "висящие" pr/mr реквесты, которые можно посмотреть, и дать свой комментарий или approve (одобрение на слияние кода)

2) Даже видно какой тест план для этой фичи, которая просится в главную ветку

3) Переписка,комменты прямо в Xcode при pr/mr (а не на веб мордах gitlab/github/bitbucket и тд)

В общем очень круто и удобно

IV - Улучшения (Crashes/Сбои/Ошибки)

1) Все краши/сбои теперь видно прямо в Xcode (а не в веб морде Firebase или Sentry), код приходит сразу символизированный (symbolized log), то есть человекопонятный с указанием что и как произошло

2) А тестер (возможно и пользователь) может оставить комментарий при краше который вы сможете прочитать (и даже ответить!)

3) Ну и самое интересное вы сможете кликнуть открыть место краша в проекте

4) И вас за ручку проведут к вашему куску кода который натворил зло

Послесловие

Плюс ко всему это обещает все генерить сертификаты которые нужно автоматически, обновлять провижн (provision) файл тоже автоматически, судя по всему даже UDID теперь не надо будет собирать с инженеров по тестированию и заинтересованных менеджеров которые хотят смотреть на билд.

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

Можете подать заявку на бета-тест здесь https://developer.apple.com/xcode-cloud/

Сколько он будет стоить пока тоже неизвестно.

И пока непонятно что с Android потому что обычно сервисы CI/CD используют сразу для двух платформ, так как приложения обычно тоже для двух платформ разрабатывают. Но может быть когда нибудь приложения для Android можно будет писать и в Xcode))

Изображение и информацию брал из видеосессий WWDC 2021, кому интересно как это выглядит вот видео про Xcode Cloud https://developer.apple.com/videos/play/wwdc2021/102/

Подробнее..

Дайджест интересных материалов для мобильного разработчика 397 (7 13 июня)

13.06.2021 14:11:44 | Автор: admin
В этом дайджесте обсуждаем конференцию WWDC и ее последствия, быстрые обновления Android и ответственность команд, автоматизацию с помощью таблиц, применение КММ, цвета, элементы управления и многое другое.



Этот дайджест доступен в виде еженедельной рассылки. А ежедневно новости мы рассылаем в Telegram-канале.

iOS

Xcode Cloud, SharePlay, Focus самое важное с Keynote WWDC21
Apple убивает TeamCity, Bitrise, Appcenter, Fastlane, Firebase, Sentry и иже с ними. Краткий обзор Xcode Cloud
Делаем OpenVPN клиент для iOS
iOS интервью в Vivid
Лучшие приложения для iPhone весят почти в 4 раза больше, чем пять лет назад
Mobile People Talks: WWDC21
Apple выпускает бета-версии прошивок AirPods для разработчиков
iOS 4 воссоздали как приложение для iPhone
Дырявим вьюхи на Swift
Apple уточняет правила публикации в App Store
Apple разрешит пользователям остаться на iOS 14
Новые функции iPadOS 15
Apple представила новые технологии и инструменты для разработчиков приложений
watchOS 8: новые функции доступа, возможности подключения и практики осознанности
Apple представила iOS 15
Главное в iOS 15 для дизайнеров
Доклад Platforms State of the Union с WWDC 2021
Отчеты о сбоях iOS с LLDB
Онбординг SwiftUI в приложении UIKit
Лучшая маршрутизация глубоких ссылок в iOS-приложении
Что мы узнали из инцидента с OOM в iOS-приложении Pinterest
Делаем бесконечную прокрутку фотографий в iOS
Что нового в SwiftUI после WWDC21
SwiftUI двунаправленный список SnapList
Использование SwiftUI с View Model, написанной на Kotlin Multiplatform Mobile
Пишем первое приложение для iOS с помощью Realm, SwiftUI и Combine
Что нового в StoreKit 2
Как мы используем SwiftUI в приложении Medium
Что нового в SwiftUI 3.0?
Как сделать иконку для темного режима для вашего приложения
iOS 15 привносит атрибутные строки в SwiftUI
Понимаем AsyncImage в SwiftUI
Indicate: тосты в стиле AirPods
SimpleAnalytics: своя аналитика для iOS

Android

Долгая дорога к быстрым обновлениям Android
Миграция с LiveData на Kotlins Flow
Бесконечная автопрокрутка списков с помощью RecyclerView и LazyLists в Compose
Разработчики могут подать заявку на снижение комиссии до 15% через Play Store
Flutter Dev Podcast #28: Google I/O 2021
Корутины обработки ошибок
Проблема трех фреймворков в Kotlin Multiplatform Mobile
Современная архитектура Android с шаблоном проектирования MVI
Азбука модульности Android в 2021 году
Навигация в Jetpack Compose
Несколько бэк-стэков
Работа с сетью в Kotlin Ktor на Android
Автогенерация пользовательских размеров для Android с помощью Kotlin
Глубокое погружение в интернационализацию приложений для Android на Jetpack Compose
Датабиндинг в Android
Чистая архитектура Android [точка зрения]
Создаем приложение CoroutineScope с помощью Hilt
Пагинация в Android с Paging 3, Retrofit и Kotlin Flow
CompleteKotlin: автодополнение для всех платформ
TimeRangePicker: круглый range picker для Android

Разработка

Кто, где, когда: система компонентов для разделения зон ответственности команды
Автоматизация или смерть: как управлять тысячами единиц игрового контента с помощью гугл-таблиц
Appwrite, open-source бэкэнд-платформа
Роль QA Lead в продуктовой компании: особенности и зоны ответственности
Вызов кода Go из Dart с использованием cgo и Dart FFI на простом примере
Создание прекрасных приложений с помощью Xamarin.Forms
We need to go deeper: как пасхалка в приложении Delivery Club сократила субъективное время ожидания еды
Тестируем и визуализируем с помощью Mind Map
Автоплатеж, автооплата или автопополнение? UX-кейс
Как стать тестировщиком с нуля
Podlodka #219: выбор первой профессии в IT
Дизайн приложений: лауреаты премии Apple Design Awards 2021
КММ на практике или выбор кроссплатформенного фреймворка для Леруа Мерлен
Исследование разработчиков HackerEarth 2021
Отключенные кнопки не должны путать пользователей
Распродажа книг по Data Science и аналитике данных в Humble Bundle
6 мощных инструментов для разработчиков, использующих Mac
Как мы улучшили сегментированные элементы управления (segmented control)
Руководство для новичков по применению цвета в UI дизайне
Пошаговое руководство по работе в Figma. Урок по созданию мобильного приложения
Принцип IBM Leadership-as-a-service обеспечивает профессиональный рост команд
Топ-5 шаблонов проектирования распределенных систем
ELI5: Flipper кроссплатформенный дебагер
Как ежедневно улучшать навыки архитектуры ПО
Анимированный TabBar Coinbase в React Native
Как проверять код Junior разработчику
Разработчики не могут исправить плохой менеджмент

Аналитика, маркетинг и монетизация

WWDC 2021: новое и полезное для разработчика, ASO спецалиста, маркетолога мобильных приложений
Почему подписываются пользователи? Как повысить конверсию мобильных приложений
Classplus: Spotify для образования
AppsFlyer: на 570% выросло количество неорганических установок финансовых приложений в России
Стратегия победителя: как покорить весь мир, начиная с Якутска? Кейс inDriver и Rocket10
Кейс: как вытеснить конкурентов из поиска, оптимизируя инаппы?
Практические инструменты и преимущества отслеживания удалений мобильных приложений
Онбординг в мобильном приложении: как поддерживать интерес пользователей

AI, Устройства, IoT

Как Яндекс применил генеративные нейросети для поиска ответов
Маленький и быстрый BERT для русского языка
Начинаются продажи карманной игровой приставки Playdate
Защищенный смартфон, контролируемый ФБР, раскрыл действия сотен преступников

Предыдущий дайджест. Если у вас есть другие интересные материалы или вы нашли ошибку пришлите, пожалуйста, в почту.
Подробнее..

За что App Store может отклонить приложение чек-лист

18.06.2021 14:19:30 | Автор: admin

App Store самая строгая площадка для размещения приложений. Ревью проходит дольше и строже, чем у Google Play и Huawei App Gallery. В 2020 году AppStore отклонил миллион приложений, которые публиковались впервые, и миллион апдейтов.

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

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

Мы составили чек-лист очевидных и не очень очевидных причин, по которым AppStore отклоняет приложения. Сам чек-лист в гугл-доке. В статье раскроем подробнее каждый пункт.

Нарушения политики конфиденциальности и пользовательских данных

Нет ссылки на пользовательское соглашение. Ссылка должна быть и внутри приложения, и на странице в магазине. Если ссылка ведёт на сайт компании, соглашение должно быть размещено там и ссылка должна работать.

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

Нарушение функциональных требований

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

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

У нас в Surf, например, однажды отклонили приложение, потому что в нём была подключена библиотека для Apple Pay, но она нигде не использовалась.

UI, не соответствующий Human Interface Guideline. Сложное для использования приложение, имеющее нелогичное поведение и расположение элементов, отклонят.

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

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

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

Изменение поведения системных функций, кнопок или жестов. Нельзя изменять поведение кнопок громкости или жестов свайпа панели управления.

Для распознавания по FaceID используются сторонние технологии. Идентификация пользователя по FaceID должна происходить только с помощью библиотеки LocalAuthentication.

Нет входа по AppleID, если есть возможность входа через соцсети. Это обязательно для iOS 13 и новее.

Нарушения в оформлении приложения

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

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

Есть слова Beta, Demo или Debug в названии приложения. Такие приложения запрещены к публикации в магазине App Store. Для бета-версий есть Test Flight.

Нет описания новой функциональности у обновлённого приложения. Если в приложении появилась новая функциональность, необходимо описать её в поле в App Store Connect. Без чёткого описания приложение ревью не пройдёт.

Скриншоты приложения, иконка и другой контент на странице магазина не подходят для аудитории 4+. И не важно, что приложение может быть не предназначено для такого возраста: аудитория App Store дети от четырёх лет.

Контент не соответствует возрастной метке. При публикации нужно пройти опрос, чтобы установить возрастную метку приложения. Если контент ей не соответствует, приложение или обновление отклонят при публикации.

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

Файл с расширением .ipa превышает размер 50 мб в момент публикации.

Нет демо-пользователя для ревью, если приложение требует обязательной авторизации.

Не указаны правила участия и выигрыша, если в приложении есть розыгрыши, рулетки или казино. Следует явно написать, что Apple не имеет никакого отношения к этим конкурсам и розыгрышам.

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

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

В период пандемии этот пункт стал особенно важен: Apple строго следит за распространением информации, связанной с COVID-19.

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

Контент оскорбляет людей разных рас, вероисповеданий, сексуальной ориентации, национальности.

Приложение поощряет незаконное использование оружия или позволяет его купить.

Есть откровенно сексуальный или порнографический контент.

Приложение разрешает анонимную отправку смс/ммс, анонимные звонки, розыгрыши.

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

У карты лояльности в wallet нет контактной информации о компании. Её нужно добавить, чтобы пользователи могли связаться с компанией, если захотят.

Покупки в приложении

Цифровой контент продаётся не через in-app purchase.К цифровому контенту относятся подписки, музыка в приложении, видео, расширенный доступ к функциям.

Не указана вероятность, с которой пользователь получит тот или иной предмет из лутбокса. Вероятность нужно обозначить перед покупкой этого игрового элемента.

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

Приложение не предоставляет пользователю всю необходимую информацию о покупке до момента продажи. Это важно, если приложение использует Apple Pay. Также недопустима кастомизация окна оплаты.

Категория Kids

Kids в App Store отдельный вид приложений. К ним Apple относится максимально строго. Категория Kids делится на три подкатегории: до 5 лет, 68 лет, 911 лет.

Есть внешние ссылки, покупки и другие отвлекающие факторы. Такие элементы требуют дополнительной защиты и отделения от функциональности, которую используют дети. Исключение составляют опции родительского контроля.

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

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

Составили гугл-док с чек-листом требований для ревью App Store.

А по каким причинам App Store отклонял ваши приложения? Расскажите в комментариях.

Подробнее..

Дайджест интересных материалов для мобильного разработчика 398 (14 20 июня)

20.06.2021 12:09:43 | Автор: admin
В этой подборке исследуем StoreKit 2, распознаем лица и позы на Android, улучшаем производительность React-приложений, учим сквирклморфизм и многое другое!



Этот дайджест доступен в виде еженедельной рассылки. А ежедневно новости мы рассылаем в Telegram-канале.

iOS

За что App Store может отклонить приложение: чек-лист
Meet StoreKit 2
Тим Кук: на Android в 47 раз больше вредоносных программ, чем на iOS
Новый антимонопольный акт может заставить Apple продать App Store
Что нового во встроенных покупках в iOS 15 WWDC 21
Строим лабиринты с SwiftUI
iOS 15: заметные дополнения к UIKit
Info.plist отсутствует в Xcode 13 вот как его вернуть
ScrollView в XCode 11
Создаем игры на SwiftUI с помощью SpriteKit
Мастерим списки в SwiftUI
Как лучше структурировать свои проекты в Xcode
Глубокое погружение в Акторы в Swift 5.5
Разработка функций iOS-приложения в виде модулей в Xcode
Как делать видеозвонки с помощью SwiftUI
Euler: вычислительный фреймворк на Swift
WorldMotion: положение устройства относительно Земли

Android

Как использовать Android Data Binding в пользовательских представлениях?
AppSearch из Jetpack вышел в альфа-версии
Распознавание лиц и поз за 40 минут
Android Broadcast: новости #10
Создайте свою библиотеку KMM
История моего первого а-ха-момента с Jetpack Compose
Как стать ассоциированным разработчиком Android (Kotlin Edition)
Анимации Jetpack Compose в реальном времени
RecyclerView с NestedScrollView: лучшие практики
Android Bitbucket Pipeline CI/CD с Firebase App Distribution
CompileSdkVersion и targetSdkVersion в чем отличие?
Нижняя панель навигации Android с Jetpack Compose
Интеграция Google Sign-in в Android-приложение
Focus в Jetpack Compose
DashedView: полосатые View
Screen Tracker: название видимого Activity/Fragment
SquircleView: красивые View

Разработка

5 000 000 строк кода, 500 репозиториев: зачем мы адаптировали приложение AliExpress для Рунета
Десятикратное улучшение производительности React-приложения
gRPC + Dart, Сервис + Клиент, напишем
Podlodka #220: волонтерство в IT
Хороший день разработчика: Good Day Project от GitHub
К 2024 году 80% технологических продуктов будут создавать непрофессионалы
Сквирклморфизм (Squirclemorphism) в дизайне интерфейсов
12 рекомендаций, которые помогут улучшить процесс регистрации и входа в систему
React Native в Wix Архитектура (глубокое погружение)
Как узнать плохой код? 8 вещей
5 лучших пакетов Flutter, которые вы должны знать
Советы по кодинг интервью в Google
Как стать плохим разработчиком

Аналитика, маркетинг и монетизация

Гайд по тестированию рекламы для мобильных приложений
Вслед за Apple и Google комиссию магазина приложений снизила Amazon
make sense: О инфлюенсер-маркетинге
UserLeap получает еще $38 млн на отслеживание пользовательского опыта
Классическая MMORPG RuneScape запускается на iOS и Android
Маркетологи в мобайле: Александр Плёнкин (Vprok.ru Перекрёсток)
Почему такие скриншоты пустая трата времени? (пока у вас нет 4,000 загрузок в месяц)
Amplitude получил еще $150 млн
$100 млн для Free Fire: как младший брат может обогнать старшего на уже сложившемся рынке?
App Annie: рынок мобильных игр в России в 2020 вырос на 25% до $933 млн
Темные паттерны и уловки в мобильных приложениях
Использование BigQuery и Firebase Analytics для привлечения, вовлечения и оценки пользователей

AI, Устройства, IoT

Запускаем DOOM на лампочке
Быстрое обнаружение Covid-19 на рентгеновских снимках с помощью Raspberry Pi
Как я учу Python на Raspberry Pi 400 в библиотеке
Топ-5 преемников GPT-3, о которых вы должны знать в 2021 году

? Предыдущий дайджест. Если у вас есть другие интересные материалы или вы нашли ошибку пришлите, пожалуйста, в почту.
Подробнее..

Когортный анализ подписок как понять, что экономика сходится?

15.06.2021 10:13:02 | Автор: admin

Когортный анализ это способ отследить плотность метрики для определенных групп пользователей. В отличие от обычных графиков, когорты показывают именно stickiness пользователей, распределенный во времени.

Звучит сложно, на деле понять проще. Возьмем конкретный пример: попробуем понять как ведет себя база подписчиков в мобильном приложении: как они платят, отписываются и как долго живут. Ответы на эти вопросы я покажу на примере нашей реализации в Adapty.

Пример когортного анализа подписокПример когортного анализа подписок

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

То есть, в строчках у нас когорты (группа) пользователей, которые установили приложение в определенный месяц, а в столбцах значения метрик по каждому месяцу с месяца установки (этот месяц первый или М1). В выделенной строчке М1 это январь, М2 февраль и тд. Каждый месяц количество подписчиков в данной когорте не возрастает, даже если пользователь установил в январе, а подписался в феврале, то он будет отнесен в когорту января. Нам кажется такой способ правильным для оценки сходимости.

Идея оценивать экономику так кроется в том, как работает привлечение пользователей. При закупке рекламы разработчик так или иначе платит за установки, а не за целевые действия. Даже в CPA кампания, все будет связано со стоимостью установки (CPI). Следовательно, чтобы оценить эффективность закупки трафика надо смотреть как именно люди установившие приложение в этот период будут монетизироваться. При этом, если пользователь установил приложение, но месяц не платил, он попадет только в М2.

Видим, что когорта пользователей января принесла нам суммарно до текущего момента времени $2900 выручки от 73 подписчиков.

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

Сойдется ли экономика?

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

Посмотрим внимательно на динамику подписчиков когорты января.

Когорта января в разбивке по месяцам (первая колонка установки)Когорта января в разбивке по месяцам (первая колонка установки)

На текущий момент приложение заработало $2900 до комиссии Apple, или $2465 после вычета 15% (приложение находится в программе Apple для SMB). Также будем считать, что мы продаем недельные подписки в среднем по $10.

Мы видим, что количество активных подписчиков после первого месяца упало почти в 2 раза, дальше на 20%, потом всего на 10% до 24. Так как на момент написания заметок месяц еще не кончился, возьмем лучший сценарий пусть все 24 подписчика будут с нами всегда. И даже пусть они в среднем платят $15.48 дальше, то есть их ARPPU не меняется.

Чтобы добить до $4000 нужно чтобы подписчики заплатили больше $1500, даже при сохранении выручки за месяц в $372 и нулевой отписке, когорта сойдется в лучшем случае через 4-5 месяцев непрерывных платежей. На практике, учитывая предыдущую динамику, и зная, что трафик закупается равномерно, когорта вряд ли сойдется меньше, чем за пару лет, а по факту скорее всего будет в убыток. Причина такая, что недельные подписки постоянно напоминают о себе и пользователи реже остаются в долгосрочных платежах, ведь если приложение хорошее, гораздо выгоднее купить год. Но даже с подписками на месяц при такой динамики на вряд ли стоит ожидать положительной прибыли.

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

Подробнее..

Архитектурные паттерны в iOS привет от дядюшки Боба, или Clean Architecture

03.06.2021 10:20:31 | Автор: admin

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

Все, кто хочет не просто знать что стоит за названием той или иной архитектуры, но ещё и в каком случае какую использовать наливайте чай и устраивайтесь поудобнее, будет лампово. Разбираем паттерны, реализующие концепцию Чистой Архитектуры самые масштабируемые и надёжные :)

Введение

Привет, Хабр! Я всё ещё ведущий инженер-разработчик iOS в КРОК и аспирант-препод в МЭИ. В этом посте я рассказывала про архитектурные паттерны MV(X). У всех MV(X) архитектур есть один общий недостаток: они не описывают как должно происходить взаимодействие между экранами, только то как данные циркулируют внутри экрана.

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

Все эти картинки с моделями и видами выглядят круто и красиво, но как только добираемся до реализации, вопросов возникает больше, чем ответов. В итоге, любая даже самая красивая и элегантная MV(X) архитектура превращается в месиво костылей и велосипедов, когда команда пытается заставить работать не просто пару десятков экранов, а ещё и какую-то сложную функциональность помимо собственно GUI и бизнес-логики.

По сути, MV(X) архитектуры и не являются архитектурами вовсе это презентационные паттерны, которые описывают слой представления и не более того. В этом-то и кроется вся проблема! Мы пытаемся использовать MVC как архитектуру, когда это просто паттерн для описания её кусочка.

Чистая архитектура

Основная часть заблуждений относительно того, является MV(X) архитектурой или нет кроется в том, что в MV(X) всегда отделяют слой Модели, и кажется что этого как-то достаточно. Но на самом деле нет.

Дело в том, что зачастую бизнес-логику удобно поделить на два уровня:

  1. Логика предметной области (Enterprise business logic) описывает собственно бизнес-процессы. Например объект студент можно преобразовать в магистра и в программера (по отдельности или одновременно) это описание предметной области. Также при преобразовании студента в магистра ему необходимо выдать шапочку то есть это уже целый бизнес-процесс.

  2. Логика приложения (Application logic) описывает процессы и потоки данных внутри приложения. Как правило, они мало связаны с логикой предметной области и больше зависят от UI/UX дизайна и внутренней кухни платформы. Например, чтобы этот человечек получил красивую шапочку, нужно запустить бизнес-процесс его преобразования из студента в магистра, а для этого надо перейти на экран выдавания шапочек и нажать кнопку дать шапку это и есть логика приложения. Иначе она может называться как сценарии использования (Use Cases) и, вообще говоря, описывает то, как модели предметной области применяются в нашем приложении.

В итоге получаем два вложенных слоя: логика приложения смотрит на логику предметной области. А логика предметной области ни от чего не зависит (с точки зрения архитектуры ПО) она либо есть, либо её нет.

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

Виды и весь UI-специфичный слой зависит, понятное дело, от презентеров и контроллеров.

Непокрытыми у нас остались только всякие нетворк-слои, data access layers и различные внешние зависимости. Обобщая, мы увидим, что во внутренних слоях, описанных выше, им места нет, а значит, придется их вывести наружу.

Получим примерно вот такое [1]:

Каждый круг изображает части ПО. Внешние круги описывают механизмы взаимодействия, а внутренние правила взаимодействия [1]. Названия в секторах на иллюстрации примерные и не обязаны быть именно такими [4] (может приложение вообще без нетворка работает имеет право!), и приведены просто чтобы вы представили что именно представляет из себя тот или иной слой. По сути их можно поделить следующим образом:

  1. Сущности (предметная область и логика)

  2. Сценарии использования (логика приложения)

  3. Адаптеры интерфейсов (контроллеры, презентеры всё, что помогает внешним фреймворкам общаться с приложением)

  4. Внешние фреймворки (и/или устройства)

Чем выше поднимаемся (чем ближе к центру) тем более высокоуровневое описание системы получаем. В итоге слой сущности полностью оторван от какой-либо реализации системы и в тупую описывает предметную область как она есть. Что позволяет:

а) переиспользовать описание предметной модели, просто взяв сорсы и впихнув в другое приложение

Гексагональная архитектура

Похожий принцип выделения адаптеров и логики используется в так называемой гексагональной архитектуре (Hexagonal Architecture, она же Ports&Adapters Pattern) за исключением того, что в гексагональной архитектуре нет разделения на слои.

Вкратце, вот отличная иллюстрация этого подхода [1]:

Пока что гексагональная архитектура в iOS разработке не слишком-то популярна (например про нее (пока) не спрашивают на собеседованиях), а посему она выходит за рамки этой статьи.

Но почитать о ней подробнее можно здесь:

[1] Hexagonal Architecture for iOS. An architecture pattern that focuses on | by Oleksandr Stepanov

[2] Clean and Hexagonal Architectures for Dummies | by Lus Soares | CodeX | Mar, 2021

Если представить эту же диаграмму как пирамидку, то запомнить что UI это низкоуровневое, а предметная модель верхнеуровневое, становится совсем легко:

Более того, таких слоёв может быть и больше (и меньше): порой имеет смысл какие-то из них разделить и вложить друг в друга или наоборот. Если говорить о чистой архитектуре в целом, то такую задачу разделения слоёв приходится решать каждый раз заново это и есть проектирование архитектуры. В [4] предлагается разделять компоненты на верхнеуровневые политики и низкоуровневые детали:

  • политики это правила по которым что-то происходит с данными (бизнес-логика, правила валидации)

  • детали это компоненты, которые что-то делают с данными согласно политикам (СУБД, UIKit)

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

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

Правило зависимостей

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

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

Это называется правило зависимостей (Dependency Rule) [1], и означает оно следующее: ничто во внутреннем круге не может знать или как-либо ссылаться на что-либо во внешнем круге. К примеру, ни одно понятие (класс, функция, переменная), упомянутое во внешнем круге, не должно упоминаться во внутреннем.

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

Это правило относится и к форматам данных: внутренние круги оперируют одними форматами данных, а внешние другими. Мы не хотим, чтобы внешние круги влияли на работу внутренних. Их задача передавать нам информацию, а не ломать нас!

Примечание: под форматами данных тут конечно же имеются в виду модели: классы или структуры, которыми описываются те или иные объекты.

Источники:

[1] Clean Coder Blog | The Clean Architecture

[2] madetech/clean-architecture: A (work-in-progress) guide to the methodology behind Made Tech Flavoured Clean Architecture

[3] Заблуждения Clean Architecture / Блог компании MobileUp / Хабр

[4] Clean Architecture | A CRAFTSMANS GUIDE TO SOFTWARE STRUCTURE AND DESIGN Robert C. Martin

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

VIPER

VIPER страшный сон большинства iOS разработчиков на рынке. На интервью вопросы про VIPER вызывают разные реакции, но самая распространенная бей и беги.

Кажется, VIPER это что-то прикольное, давайте разберёмся, что это все-таки за зверь.

VIPER расшифровывается в схожей манере с MV(X):

  • View показывает что скажет Презентер и передает ввод пользователя Презентеру

  • Interactor содержит описание сценария использования

  • Presenter содержит логику отображения и умеет подготавливать данные для представления пользователю, а также реагировать на ввод пользователя

  • Entity описание предметной модели

  • Routing описывает логику навигации между экранами

VIPER это про SOLID, так что у нас так много компонент для того чтобы обеспечить S из SOLID Single Responsibility Principle (принцип единственной ответственности: это когда каждый элемент отвечает за что-то одно).

Если рисовать, все это будет выглядеть примерно так:

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

  • Вид: наша любимая связка UIView+UIViewController.

    • знает о Презентере

      • посылает ему действия пользователя

      • получает от него запросы на обновление представлений

  • Презентер: содержит связанную с UI бизнес-логику (при этом не зависит от UIKit)

    • знает об Интеракторе

      • посылает ему запросы данных

      • получает от него события об обновлении данных

    • знает о Роутере

      • получает от него запросы на отображение Вида

    • влияет на Вид

      • посылает ему запросы на обновление представлений

  • Роутер: описывает навигацию между экранами (или VIPER модулями, если они не равны экранам)

    • влияет на Презентер

      • посылает ему запросы на отображение Вида

  • Интерактор: описывает взаимодействие с данными: что откуда взять и куда сохранить

    • влияет на Презентер

      • получает от него запросы данных

      • отправляет ему события об обновлении данных

    • знает о Моделях

      • использует Модели чтобы структурировать данные в принятый формат

  • Модель (Сущность, Entity): описывает структуру данных

    • больше ничего не умеет

    • это реально просто описание

Как мы видим, принципиально изменились две вещи:

  1. Модель стала тупым описанием данных, без какой-либо логики обработки или, боже упаси, CRUD

  2. Ответственность сильно поделилась между Презентером и Интерактором:

    1. Мама-Презентер отвечает за UI: просит данные у папы-Интерактора, подготавливает их для малыша-View и говорит малышу когда, как и что показывать

    2. Папа-Интерактор отвечает за данные: когда Презентер просит что-то показать, именно Интерактор идёт в базу, делает всякий CRUD, а потом отдает Презентеру готовый ответ (получилось или нет, вот данные или вот ошибка)

Так вот и выглядят VIPER модули. Если уж быть до конца честным, то в жизни они выглядят скорее вот так:

Интерактор может работать с несколькими Моделями, а Data Access Layer выделен в отдельный компонент, например сервис.

Глядя на диаграммы, несложно заметить, что собирать всё это дело так, чтобы соблюсти правило зависимостей непросто. Настолько, что проще всего выделить под сборку еще один, отдельный компонент, который знает все обо всех (похоже на MPV+C, как и весь VIPER похож на MVP) и где можно легко подставить вместо старого, например, интерактора новый. Такие компоненты называются Builder [6] (или Assembly [3]).

Рисовать это довольно страшно, давайте я просто покажу пример кода:

Тем временем в роутере другого модуля по имени Main:

Не идеальный, но показательный пример из https://github.com/theswiftdev/tutorials

Можно вместо этого сделать полноценный ServiceLocator или использовать уже готовый в составе Swinject и других библиотек. Подробнее про DI можно почитать в этой крутой статье.

Если полазить по репозиториям с VIPER кодом (особенно по шаблонизаторам и тем, которые описывают туториалы, например [3, 6, 7, 8]), можно больно напороться на кучу протоколов, классы-интерфейсы и все вот это вот ООП-шно абстрактное.

С одной стороны, все это велосипед, прикрывающий проблему сборки и неспособность VIPER соответствовать парадигме UIKit. С другой, каждый такой протокол и наследование очередной непокрытый участок кода, который придется тестировать отдельно. А значит, хоть VIPER и testable out of the box но тестов придется написать в X раз больше, чем хотелось бы.

Источники:

[1] Architecting iOS Apps with VIPER objc.io

[2] iOS Architecture Patterns and Best Practices for Advanced Programming - 2021

[3] strongself/The-Book-of-VIPER: the one and the only

[4] Getting Started with the VIPER Architecture Pattern

[5] The Good, The Bad and the Ugly of VIPER architecture for iOS apps.

[6] The ultimate VIPER architecture tutorial

[7] https://github.com/BinaryBirds/swift-template

[8] https://github.com/infinum/iOS-VIPER-Xcode-Templates

RIBs

Описанная выше вариация VIPER с билдером на самом деле очень близка к другому архитектурному паттерну, который придумали в Uber и назвали RIBs Architecture.

И если VIPER пытается привнести в Android какие-то iOS-специфичные проблемы (например высокую связность View и ViewController), то RIBs наоборот, привносит Android-специфичные заморочки в iOS :) Впрочем, и то и другое позволяет нам с наименьшими потерями переписывать код с одной платформы под другую, и, если верить Uber, RIBs с этой задачей справляется лучше.

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

RIBs заключается в том, что существуют определенные RIB-блоки, которые взаимодействуют между собой.

Router осуществляет навигацию между RIB-блоками

Interactor содержит бизнес-логику RIB-блока

Builder конструктор, который собирает RIB-блок

Вид и Презентер в этой иерархии опциональны: если в RIB-блоке нет необходимости рисовать UI, то Вид не нужен; если нет необходимости переводить данные из одного формата в другой Презентер не нужен. Формально тут Презентер как правило является протоколом, по которому Интерактор общается с Видом.

Еще есть Компонент это такая хитрая штука, которая управляет зависимостями RIB-блока. У RIB-блока есть определенные зависимости: такие вещи, которые спускаются ему указом сверху от родительского RIB-блока и хочется, чтобы они были корректно сформулированы. RIB Dependency это протокол, описывающий такие зависимости. А RIB Component это реализация такого протокола. (Если вы знакомы с Android и Dagger, то уже знаете о каких компонентах идёт речь ;))

То есть в Builder дочернего RIB-блока благодаря Component получаются от родителя все зависимости, которые этому ребёнку необходимы (и на шторы скинуться не забудьте!)

Выглядит немного запутанно, но на самом деле всё довольно просто. Presenter и View это одна целая штуковина, при необходимости опущенная или разделённая. Связь Builder с Component отображает процесс Dependency Injection на этапе сборки RIB-модуля. Router просто делает своё навигационное дело, к нему вопросов нет.

В итоге мы получаем возможность строить дерево из RIB-блоков не так, как захочет Navigation Controller и левая пятка UIKit, а так, как того требует бизнес-логика. Это удобно, прозрачно и понятно, к тому же сохраняется чистота наследований: дети не знают ничего о своих родителях, а родители знают о своих детях.

Вот дурацкий пример приложения-будильника-с-погодой:

  • Корневой RIB может включить в себя RIB с флоу будильника либо RIB с флоу погоды

  • RIB будильника умеет добавлять новый будильник и редактировать существующий

  • а RIB погоды показывать мою погоду и новости о погоде вообще

В итоге состояние приложения управляется и определяется тем, какие RIB-ы в текущий момент включены в дерево. К примеру если пользователь хочет добавить новый будильник, наше дерево (граф DI) будет выглядеть так:

Основная фича этого конструкта в том, что каждый RIB может управлять состоянием (навигироваться) только внутри своей ветки: к примеру из Alarm RIB нельзя попасть в News RIB. И он не принимает никаких решений, как только мы попали в Add new alarm RIB.

Проблема тут состоит в том, что не все состояния можно отслеживать добавлением или удалением RIB блоков из дерева. В этом случае Uber предлагают использовать неизменяемые (immutable) модели данных, которые при изменении (право на которое имеют только сетевые ответы, например) распространяют разницу вниз по DI графу.

В итоге RIBs дает нам хорошо структурированный и высоко модуляризированный код, полную свободу в разрезе параллельной разработки, общий язык с Android-командой и кучу головной боли в разрезе DI.

Источники:

[1] uber/RIBs: Uber's cross-platform mobile architecture framework.

[2] iOS Architecture: Exploring RIBs. Uber mobile architecture in details | by Stan Ostrovskiy | The Startup

[3] Как мы внедряли архитектуру RIBs. Доклад Яндекс.Такси

CleanSwift

CleanSwift это хорошая альтернатива VIPER и ещё один способ переложить концепцию Чистой Архитектуры на iOS разработку.

В отличие от VIPER, в CleanSwift парадигма UIKit с центральным элементом в виде UIViewController остается нетронутой, что позволяет нам сделать чистую архитектуру, не выдумывая велосипеды, а естественно вырастая из MVC.

CleanSwift ориентируется на VIP-модули: это тройка View-Interactor-Presenter, которая общается друг с другом посредством специальных структур данных, привязанных к взаимодействию одной компоненты с другой.

Так, например, ViewController запрашивает данные для отображения у Интерактора с помощью структуры Request, Интерактор передает данные в Презентер через Response, а Презентер преобразует полученные данные в вид, удобный для отображения Контроллером Вида, то есть собирает ViewModel и отправляет в ViewController:

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

Так, благодаря Request и Response, Интерактор ничего не знает о том как устроен изнутри Контроллер Вида. Ему нужны работники в виде массивов со сквозным индексированием, или в виде множества объектов? Интерактору все равно! Он отдаст Презентеру данные в том виде, в котором Презентер сможет их понять (Response), а уже Презентер приведет их в вид, нужный Контроллеру Вида (ViewModel).

Таким образом с помощью этих трех структур мы задаем интерфейсы взаимодействия между Видом, Интерактором и Презентером. А сами взаимодействия формируют однонаправленный поток данных: легко читать, приятно дебажить, понятно как тестировать красота!

Добавив в такой VIP модуль дополнительно компоненты для внешних взаимодействий (с другими модулями и с хранилищами данных) получим следующий концепт:

  • Контроллер Вида: делает всякие UIViewController штуки

    • знает об Интеракторе

      • посылает ему действия пользователя

      • запрашивает у него данные (с помощью Request)

    • знает о Роутере

      • запрашивает у него логику навигации, когда необходимо перейти с текущего экрана на другой

    • знает о Презентере:

      • получает от него запросы на отображение данных (via Viewmodel)

  • Интерактор: осуществляет логику приложения, знает как действовать в ответ на действия пользователя

    • знает о Презентере:

      • посылает ему запросы на отображение данных (с помощью Response)

    • знает о Воркере:

      • запрашивает у него данные из Data Storage (Persistence или Network API)

    • влияет на Контроллер Вида:

      • получает от него запросы данных (via Request)

      • получает от него действия пользователя

  • Презентер:

    • влияет на Интерактор:

      • получает от него данные для отображения

    • влияет на Контроллер Вида

      • передает ему данные, полученные от Интерактора (Response) в виде, удобном для отображения (ViewModel)

  • Роутер: осуществляет общение с другими модулями

    • влияет на Контроллер Вида:

      • получает от его запросы на навигацию и/или передачу данных другим модулям (другим ViewController)

  • Воркер: прослойка между Интерактором и Data Access Layer

    • влияет на Интерактор

      • получает от него запросы на получение данных из Data Storage (Persistence или Network API)

Такая структура позволяет нам полностью разделить непосредственно работу с UI (ViewController), адаптацию данных для вывода (Presenter), логику приложения (Interactor), работу с хранилищами данных (Worker), а также навигацию и сообщение между модулями (Router).

В итоге получаем в определённой степени лаконичные и понятные MVC-новичку классы-сателлиты UIViewController, которые он сам же и создает, когда Роутер из другого модуля создаёт его, чтобы отобразить на экране.

Источники:

[1] The Clean Swift Handbook

[2] Общее представление об архитектуре Clean Swift / Хабр

[3] Clean Swift GitHub

И?

Глядя на паттерны чистой архитектуры очень легко обмануться и решить, что вот только эти паттерны ТРУ, а остальные так, самописное что-то на коленочке. Это, разумеется, не так. И надо всегда четко понимать каких именно целей вы хотите достичь, выбирая архитектурный паттерн для своей кодовой базы (возможно что в разных частях приложения вы и вовсе захотите использовать разные паттерны?)

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

С другой стороны, если команда действительно большая, то следить за соблюдением выбранного паттерна становится тяжелее (какой бы вы ни выбрали, если честно). Но с паттернами Чистой Архитектуры это доставляет особенное неудобство, связанное с тем, что при добавлении одного экрана надо проревьюить не один класс, а в среднем около пяти. А при недостаточном контроле выходит так, что каждый разработчик понимает паттерн по-своему и каждый модуль оказывается описан по-разному. И тогда весь смысл теряется :С

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

P.S. В своем предыдущем посте я рассмотрела MV(X) архитектуры - http://personeltest.ru/aways/habr.com/ru/company/croc/blog/549590/

Подробнее..

Swift и CoreData. Или как построить Swift ORM на основе Objective-C ORM

04.06.2021 16:20:58 | Автор: admin

Хабр, здравствуй! Меня зовут Геор, и я развиваю iOS проекты в компании Prisma Labs. Как вы наверняка поняли, речь сегодня пойдет про кордату и многим из вас стало скучно уже на этом моменте. Но не спешите отчаиваться, так как говорить мы будет по большей части о магии свифта и про метал. Шутка - про метал в другой раз. Рассказ будет про то, как мы победили NSManaged-бойлерплейт, переизобрели миграции и сделали кордату great again.

Разработчики, пройдемте.

Пару слов о мотивации

Работать с кордатой сложно. Особенно в наше свифт-время. Это очень старый фреймворк, который был создан в качестве дата-слоя с акцентом на оптимизацию I/O, что по умолчанию сделало его сложнее других способов хранения данных. Но производительность железа со временем перестала быть узким горлышком, а сложность кордаты, увы, никуда не делась. В современных приложениях многие предпочитают кордате другие фреймворки: Realm, GRDB (топ), etc. Или просто используют файлы (почему бы и нет). Даже Apple в новых туториалах использует Codable сериализацию/десериализацию для персистенса.

Несмотря на то, что АПИ кордаты периодически пополнялся различными удобными абстракциями (напр. NSPersistentContainer), разработчики по-прежнему должны следить за жизненным циклом NSManaged объектов, не забывать выполнять чтение/запись на очереди контекста, к которому эти объекты привязаны и разумеется ругаться каждый раз, когда что-то пойдет не так. И наверняка во многих проектах есть дублирующий набор моделей доменного уровня и код для конвертации между ними и их NSManaged-парами.

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

У себя в Призме мы написали простой и мощный фреймворк, который позволяет забыть о недостатках кордаты и при этом использовать всю силу ее светлой стороны.

Встречайте - Sworm.

Я не буду рассказывать полностью про устройство фреймворка - для этого есть репозиторий, а сосредоточусь на основных моментах и хитростях имплементации.

Отказ от NSManagedObject-наследования и встроенной CoreData-кодогенерации

Вместо этого NSManagedObject'ы используются напрямую как key-value контейнеры. Идея не нова, а сложность заключается в том, как автоматизировать конвертацию между KV-контейнером и доменной моделью. Чтобы решить эту задачу нужно навести 3 моста:

  1. название

  2. аттрибуты

  3. отношения

С названием все просто - указав в типе вашей модели строчку с названием можно однозначно связать ее с сущностью в модели:

struct Foo {    static let entityName: String = "FooEntity"}

"Мост" отношений - уже более сложная техническая конструкция. В случае названия, статическое поле указанное внутри типа автоматически с ним связано:

Foo.entityName

Но чтобы определить отношение, помимо названия этого отношения нам нужен еще тип destination-модели, внутри которой так же должно быть название соответствующей сущности. Это наводит на две мысли. Во-первых, все модели, конвертируемые в NSManageObject должны следовать единому набору правил, то есть пришло время протокола, и, во-вторых, нам нужен дополнительный тип данных Relation<T: протокол>(name: String), который будет связывать название отношения в модели данных с типом, соответствующей ей доменной модели. Пока опустим детали, что отношения бывают разные - это на данном этапе неважно. Итак, протокол версия 1:

protocol ManagedObjectConvertible {    static var entityName: String { get }}

и тип для отношений:

Relation<T: ManageObjectConvertible>(name: String)

Применяем:

struct Foo: ManageObjectConvertible {    static var entityName: String = "FooEntity"    static let relation1 = Relation<Bar1>(name: "bar1")    static let relation2 = Relation<Bar2>(name: "bar2")}

Сразу напрашивается идея зафиксировать наличие связей (отношений) в нашем протоколе, но как это сделать, если количество связей всегда разное? Сделать коллекцию отношений не получится по нескольким причинам. Во-первых, в свифте дженерики инвариантны, во-вторых, рано или поздно нам придется вспомнить, что Relation распадется на несколько типов - one/many/orderedmany, и это автоматически приведет к мысли о гомогенности через стирание типов, что нас не устраивает. Но на самом деле, нас не интересуют сами отношения и мы можем даже не думать об их количестве. Поэтому мы добавим в протокол не конкретный тип отношений, а ассоциацию с типом отношений. Звучит странно и на первый взгляд непонятно, но подержите мое пиво - протокол версия 2:

protocol ManagedObjectConvertible {    associatedtype Relations    static var entityName: String { get }    static var relations: Relations { get }}

Все еще странно, продолжаем держать пиво:

struct Foo: ManageObjectConvertible {    static let entityName: String = "FooEntity"    struct Relations {        let relation1 = Relation<Bar1>(name: "bar1")        let relation2 = Relation<Bar2>(name: "bar2")    }    static let relations = Relations()}

И вот сейчас станет понятно - с помощью такой имплементации можно легко достать название отношения:

extension ManagedObjectConvertible {    func relationName<T: ManagedObjectConvertible>(        keyPath: KeyPath<Self.Relations, Relation<T>>    ) -> String {        Self.relations[keyPath: keyPath].name    }}

Пиво-то верни, что стоишь :)

Финальный мост - атрибуты

Как известно у любого босса есть слабые места и этот не исключение.

На первый взгляд, задача выглядит аналогичной "мосту" отношений, но в отличие от них, нам необходимо знать о всех доступных атрибутах, и обойтись ассоциированным типом не получится. Нужна полноценная коллекция атрибутов, каждый из которых должен уметь делать две вещи: заэнкодить значение из модели в контейнер и задекодить из контейнера обратно в модель. Очевидно, что это связь WritableKeyPath + String key. Но, как и в случае отношений, нам понадобится решить задачу - как сохранить информацию о типах, учитывая инвариантность дженериков и необходимость иметь гомогенную коллекцию атрибутов.

Пусть в роли атрибута выступит специальный объект типа Attribute<T>, где T - доменная модель. Тогда коллекцией атрибутов будет `[Attribute<T>]` и для нашего протокола заменим T на Self. Итак, протокол - версия 3:

public protocol ManagedObjectConvertible {    associatedtype Relations    static var entityName: String { get }    static var attributes: [Attribute<Self>] { get }    static var relations: Relations { get }}

И теперь попробуем реализовать непосредственно класс Attribute. Напомню, что в зону его ответственности входит сериализация/десериализация поля между моделью и KV-контейнером. Сперва, попробуем ненадолго забыть про ограничения на гомогенность типов и сделаем в лоб:

final class Attribute<T: ManagedObjectConvertible, V> {    let keyPath: WritableKeyPath<T, V>    let key: String    ...    func update(container: NSManagedObject, model: T) {        container.setValue(model[keyPath: keyPath], forKey: key)    }    func update(model: inout T, container: NSManagedObject) {        model[keyPath: keyPath] = container.value(forKey: key) as! V    }}

Имплементация атрибута могла бы выглядеть так, но [Attribute<T, V>] - не наш случай. Как можно избавиться от V в сигнатуре класса, сохранив информацию об этом типе? Не все знают, но в свифте можно добавлять дженерики в сигнатуру инициализатора:

final class Attribute<T: ManagedObjectConvertible> {    ...    init<V>(        keyPath: WritableKeyPath<T, V>,        key: String    ) { ... }    ...}

Теперь у нас есть информация о V в момент инициализации атрибута. А для того, чтобы не потерять ее и дальше, расчехлим свифт аналог BFG - кложуры:

final class Attribute<T: ManagedObjectConvertible> {    let encode: (T, NSManagedObject) -> Void    let decode: (inout T, NSManagedObject) -> Void    init<V>(keyPath: WritableKeyPath<T, V>, key: String) {        self.encode = {            $1.setValue($0[keyPath: keyPath], forKey: key)        }        self.decode = {            $0[keyPath: keyPath] = $1.value(forKey: key) as! V        }    }}

В нашем протоколе осталось еще одно пустое место. Мы знаем как создать NSManagedObject и заполнить его данными из модели, знаем как заполнить модель из NSManagedObject'а, но НЕ знаем, как создать инстанс нашей модели при необходимости.

Протокол - версия 4, финальная:

protocol ManagedObjectConvertible {    associatedtype Relations    static var entityName: String { get }    static var attributes: Set<Attribute<Self>> { get }    static var relations: Relations { get }    init()}

Все - мы победили наследование от NSManagedObject'ов, заменив его на имплементацию протокола.

Далее рассмотрим как можно сделать систему атрибутов гибче и шире.

Гибкая система атрибутов

Кордата поддерживает набор примитивных аттрибутов - bool, int, double, string, data, etc. Но помимо них есть малоиспользуемый Transformable, который позволяет сохранять в кордате данные различных типов. Идея отличная и мы решили вдохнуть в нее новую жизнь с помощью системы типов свифта.

Определим следующий набор атрибутов-примитивов:

Bool, Int, Int16, Int32, Int64, Float, Double, Decimal, Date, String, Data, UUID, URL

И утвердим правило: тип атрибута валиден, если данные можно сериализовать в один из примитивов и десериализовать обратно.

Это легко выразить в виде двух протоколов:

protocol PrimitiveAttributeType {}protocol SupportedAttributeType {    associatedtype P: PrimitiveAttributeType    func encodePrimitive() -> P    static func decode(primitive: P) -> Self}

Применив SupportedAttributeType в нашей имплементации Attribute

final class Attribute<T: ManagedObjectConvertible> {    let encode: (T, NSManagedObject) -> Void    let decode: (inout T, NSManagedObject) -> Void    init<V: SupportedAttributeType>(keyPath: WritableKeyPath<T, V>, key: String) {        self.encode = {            $1.setValue($0[keyPath: keyPath].encodePrimitive(), forKey: key)        }        self.decode = {            $0[keyPath: keyPath] = V.decode(primitive: $1.value(forKey: key) as! V.P)        }    }}

мы получим возможность хранить в кордате данные любых типов по аналогии с Transformable, но без objc-легаси.

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

Благодаря ManagedObjectConvertible мы однозначно связали типы наших моделей и информмацию о схеме данных. Но для того, чтобы на основе этой информации мы могли выполнять операции с данными нам потребуется слой data access объектов или DAO, поскольку доменные модели обычно выступают в роли DTO - data transfer объектов.

Скрываем NSManaged под капот

Если рассматривать NSManaged-слой в терминах DAO и DTO, то контекст+объекты это DAO+DTO, причем равны суммы, но не компоненты по отдельности, так как NSManagedObject помимо трансфера данных еще может их обновлять, но с участием контекста. Попробуем перераспределить функциональность между NSManaged-сущностями и нашими доменными моделями. Наши модели это DTO + метаинформация о схеме данных (имплементация ManagedObjectConvertible). Составим псевдоуравнение:

доменные модели + raw NSManaged- объекты + X = DAO+DTO

я пометил NSManaged как raw - так как с точки зрения компилятора мы забрали от них информацию о схеме данных и передали ее во владение доменным моделям.

А X - это тот недостающий фрагмент, который свяжет информацию о схеме данных, информацию о типах моделей с NSManaged-слоем.

Решением нашего псевдоуравнения будет выступать новая сущность:

final class ManagedObject<T: ManagedObjectConvertible> {    let instance: NSManagedObject    ...}

Этот класс будет служить фасадом для NSManaged слоя, используя дженерик в сигнатуре типа для доступа к схеме данных.

Я не буду вдаваться в подробности конечной имплементации из-за масштабности фреймворка, но хотел бы на примере отношений между моделями продемонстрировать мощь dynamicMemberLookup в Swift.

Если мы вспомним ManagedObjectConvertible предоставляет информацию о названи сущности в схеме данных, о атрибутах-конвертерах и отношениях между моделями. Я специально заострил тогда внимание на том, как с помощью Keypaths можно получить название отношения. Адаптируем тот код под нужды ManagedObject:

final class ManagedObject<T: ManagedObjectConvertible> {    ...    subscript<D: ManagedObjectConvertible>(        keyPath: KeyPath<T.Relations, Relation<D>>    ) -> ManagedObject<D> {        let destinationName = T.relations[keyPath: keyPath]        // получаем объект отношения через NSManaged API        return .init(instance: ...)    }}

И, соответственно, использование:

managedObject[keyPath: \.someRelation]

Достаточно просто, но мы можем применить спец заклинание в свифте - dynamicMemberLookup:

@dynamicMemberLookupfinal class ManagedObject<T: ManagedObjectConvertible> {    ...    subscript<D: ManagedObjectConvertible>(        dynamicMember keyPath: KeyPath<T.Relations, Relation<D>>    ) -> ManagedObject<D> { ... }}

и сделать наш код проще и более читаемым:

managedObject.someRelation

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

Типизированные предикаты

Идея заключается в том, чтобы заменить строковые запросы кордаты типизированными свифт выражениями:

Вместо "foo.x > 9 AND foo.y = 10" написать \Foo.x > 9 && \Foo.y == 10 и из этого выражения получить обратно "foo.x > 9 AND foo.y = 10"

Сделать это имея на руках информацию из сущности Attribute и протоколов Equatable и Comparable достаточно просто. От нас понадобится заимплементировать набор операторов сравнения и логических операторов.

Разберем для примера логический оператор >. В левой части у него находится KeyPath нужного атрибута, а в правой - значение соответствующего типа. Наша задача превратить выражение \Foo.x > 9 в строку "x > 9". Самое простое - это знак оператора. Просто в имплементации функции оператора зашиваем литерал ">". Чтобы из кипаса получить название обратимся к имплементации нашего протокола ManagedObjectConvertible у сущности Foo и попытаемся найти в списке атрибутов тот, что соответствует нашему кипасу. Сейчас мы не храним кипас и ключ контейнера внутри объекта атрибута, но ничего не мешает нам это сделать:

final class Attribute<T: ManagedObjectConvertible> {    let key: String    let keyPath: PartialKeyPath<T>    let encode: (T, NSManagedObject) -> Void    let decode: (inout T, NSManagedObject) -> Void    ...}

Обратите внимание, что WritableKeyPath стал PartialKeyPath. И самое важное, что мы можем в рантайме сравнивать кипасы межды собой, так как они имплементируют Hashable. Это крайне интересный момент, который говорит о том, что кипасы играют важную роль не только в комплайл тайме, но и в рантайме.

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

Также нам нужно понимать, к каким атрибутам можно применять операции сравнения. Очевидно, что не все типы имплементируют Equatable и/или Comparable. Но на самом деле, нас интересует не сам тип атрибута, а тип его конечного примитива (см. SupportedAttributeType).

Поскольку в кордате мы оперируем именно примитивами, нам будут подходить те атрибуты, чьи примитивы имплементируют Equatable и/или Comparable:

func == <T: ManagedObjectConvertible, V: SupportedAttributeType>(    keyPath: KeyPath<T, V>,    value: V) -> Predicate where V.PrimitiveAttributeType: Equatable {    return .init(        key: T.attributes.first(where: { $0.keyPath == keyPath })!.key,        value: value.encodePrimitiveValue(),        operator: "="    )}

где Predicate - это специальный тип, который нужен для абстракции отдельных фрагментов целого выражения.

И для полноты картины не хватает логического оператора. Например AND. Его имплементация по сути дела является склейкой двух фрагментов в выражении и верхнеуровнево его можно представить как "(\(left)) AND (\(right))".

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

Заключение

Я постарался осветить основные и наиболее интересеные моменты в имплементации, не пытаясь рассказать про кажду строчку нашего фреймворка. Я не затронул некоторые важные темы, например - прогрессивные миграции, но про это и многое другое подробно написано в репозитории.

Надеюсь, что Sworm сделает вашу жизнь чуточку проще, как помогает нам уже на протяжении года.

Всем добра!

Подробнее..

Делаем OpenVPN клиент для iOS

10.06.2021 02:22:28 | Автор: admin
Привет всем!
Давайте рассмотрим как создать собственное приложение, поддерживающее OpenVPN-протокол. Для тех, кто об этом слышит впервые ссылки на обзорные материалы, помимо Википедии, приведены ниже.

С чего начать?


Начнем с фреймворка OpenVPNAdapter написан на Objective-C, ставится с помощью Pods, Carthage, SPM. Минимальная поддерживаемая версия ОС 9.0.
После установки необходимо будет добавить Network Extensions для таргета основного приложения, в данном случае нам понадобится пока Packet tunnel опция.

image

Network Extension


Затем добавляем новый таргет Network Extension.
Сгенерированный после этого класс PacketTunnelProvider приведем к следующему виду:

import NetworkExtensionimport OpenVPNAdapterextension NEPacketTunnelFlow: OpenVPNAdapterPacketFlow {}class PacketTunnelProvider: NEPacketTunnelProvider {    lazy var vpnAdapter: OpenVPNAdapter = {        let adapter = OpenVPNAdapter()        adapter.delegate = self        return adapter    }()    let vpnReachability = OpenVPNReachability()    var startHandler: ((Error?) -> Void)?    var stopHandler: (() -> Void)?    override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {        guard            let protocolConfiguration = protocolConfiguration as? NETunnelProviderProtocol,            let providerConfiguration = protocolConfiguration.providerConfiguration        else {            fatalError()        }        guard let ovpnContent = providerConfiguration["ovpn"] as? String else {            fatalError()        }        let configuration = OpenVPNConfiguration()        configuration.fileContent = ovpnContent.data(using: .utf8)        configuration.settings = [:]        configuration.tunPersist = true        let evaluation: OpenVPNConfigurationEvaluation        do {            evaluation = try vpnAdapter.apply(configuration: configuration)        } catch {            completionHandler(error)            return        }        if !evaluation.autologin {            guard let username: String = protocolConfiguration.username else {                fatalError()            }            guard let password: String = providerConfiguration["password"] as? String else {                fatalError()            }            let credentials = OpenVPNCredentials()            credentials.username = username            credentials.password = password            do {                try vpnAdapter.provide(credentials: credentials)            } catch {                completionHandler(error)                return            }        }        vpnReachability.startTracking { [weak self] status in            guard status == .reachableViaWiFi else { return }            self?.vpnAdapter.reconnect(afterTimeInterval: 5)        }        startHandler = completionHandler        vpnAdapter.connect(using: packetFlow)    }    override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {        stopHandler = completionHandler        if vpnReachability.isTracking {            vpnReachability.stopTracking()        }        vpnAdapter.disconnect()    }}extension PacketTunnelProvider: OpenVPNAdapterDelegate {        func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, configureTunnelWithNetworkSettings networkSettings: NEPacketTunnelNetworkSettings?, completionHandler: @escaping (Error?) -> Void) {        networkSettings?.dnsSettings?.matchDomains = [""]        setTunnelNetworkSettings(networkSettings, completionHandler: completionHandler)    }    func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, handleEvent event: OpenVPNAdapterEvent, message: String?) {        switch event {        case .connected:            if reasserting {                reasserting = false            }            guard let startHandler = startHandler else { return }            startHandler(nil)            self.startHandler = nil        case .disconnected:            guard let stopHandler = stopHandler else { return }            if vpnReachability.isTracking {                vpnReachability.stopTracking()            }            stopHandler()            self.stopHandler = nil        case .reconnecting:            reasserting = true        default:            break        }    }    func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, handleError error: Error) {        guard let fatal = (error as NSError).userInfo[OpenVPNAdapterErrorFatalKey] as? Bool, fatal == true else {            return        }        if vpnReachability.isTracking {            vpnReachability.stopTracking()        }        if let startHandler = startHandler {            startHandler(error)            self.startHandler = nil        } else {            cancelTunnelWithError(error)        }    }    func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, handleLogMessage logMessage: String) {    }}


И снова код


Возвращаемся к основному приложению. Нам необходимо работать с NetworkExtension, предварительно импортировав его. Обращу внимание на классы NETunnelProviderManager, с помощью которого можно управлять VPN-соединением, и NETunnelProviderProtocol, задающий параметры новому соединению. Помимо передачи конфига OpenVPN, задаем возможность передать логин и пароль в случае необходимости.

var providerManager: NETunnelProviderManager!    override func viewDidLoad() {        super.viewDidLoad()        loadProviderManager {            self.configureVPN(serverAddress: "127.0.0.1", username: "", password: "")        }     }    func loadProviderManager(completion:@escaping () -> Void) {       NETunnelProviderManager.loadAllFromPreferences { (managers, error) in           if error == nil {               self.providerManager = managers?.first ?? NETunnelProviderManager()               completion()           }       }    }    func configureVPN(serverAddress: String, username: String, password: String) {      providerManager?.loadFromPreferences { error in         if error == nil {            let tunnelProtocol = NETunnelProviderProtocol()            tunnelProtocol.username = username            tunnelProtocol.serverAddress = serverAddress            tunnelProtocol.providerBundleIdentifier = "com.myBundle.myApp"             tunnelProtocol.providerConfiguration = ["ovpn": configData, "username": username, "password": password]            tunnelProtocol.disconnectOnSleep = false            self.providerManager.protocolConfiguration = tunnelProtocol            self.providerManager.localizedDescription = "Light VPN"            self.providerManager.isEnabled = true            self.providerManager.saveToPreferences(completionHandler: { (error) in                  if error == nil  {                     self.providerManager.loadFromPreferences(completionHandler: { (error) in                         do {                           try self.providerManager.connection.startVPNTunnel()                         } catch let error {                             print(error.localizedDescription)                         }                                                                   })                  }            })          }       }    }


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

image

Добавим возможность выключения VPN-соединения.

do {            try providerManager?.connection.stopVPNTunnel()            completion()        } catch let error {            print(error.localizedDescription)        }


Можно также отключать соединение с помощью метода removeFromPreferences(completionHandler:), но это слишком радикально и предназначено для окончательного и бесповоротного сноса загруженных данных о соединении:)

Проверять статус подключения Вашего VPN в приложении можно с помощью статусов.

if providerManager.connection.status == .connected {      defaults.set(true, forKey: "serverIsOn")}


Всего этих статусов 6.

@available(iOS 8.0, *)public enum NEVPNStatus : Int {    /** @const NEVPNStatusInvalid The VPN is not configured. */    case invalid = 0    /** @const NEVPNStatusDisconnected The VPN is disconnected. */    case disconnected = 1    /** @const NEVPNStatusConnecting The VPN is connecting. */    case connecting = 2    /** @const NEVPNStatusConnected The VPN is connected. */    case connected = 3    /** @const NEVPNStatusReasserting The VPN is reconnecting following loss of underlying network connectivity. */    case reasserting = 4    /** @const NEVPNStatusDisconnecting The VPN is disconnecting. */    case disconnecting = 5}


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

Полезные ссылки:
OpenVPNAdapter
Habr
Конфиги для теста
Подробнее..
Категории: Разработка под ios , Vpn , Swift , Ios , Openvpn

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru