Android и iOS
версии, подписи, разрешения, идентификатор
Что это
У мобильного приложения, кроме кода, есть паспорт: кто его выпустил, какая это версия, что ему разрешено делать и как он называется для системы. Эти четыре вещи живут не в коде, а в настройках платформенных папок — и именно из-за них сборка, которая прекрасно запускалась на твоём телефоне, не принимается магазином.
ИИ помогает здесь хуже, чем с кодом: требования меняются каждый год, а обучающие данные остаются прежними. Зато сами понятия не меняются десятилетиями — их и стоит знать.
Как выглядит в коде
1. Версия — это два разных числа
version: 1.2.0+34Одна строка в pubspec.yaml, а при сборке из неё получается два значения:
| Часть | Android | iOS | Кто её видит |
|---|---|---|---|
1.2.0 | versionName | Version | пользователь в магазине |
34 | versionCode | Build | только магазин |
Первое — для людей, его показывают в описании обновления. Второе — для магазина, и оно обязано расти при каждой загрузке. Не вырастило — загрузка отклоняется с сообщением, что такая версия уже есть.
Это самая частая и самая глупая потеря времени при публикации: сборка идёт двадцать минут, а отказ приходит из-за числа, которое забыли увеличить на единицу.
2. Идентификатор — навсегда
Android: com.lunario.pogoda (applicationId)
iOS: com.lunario.pogoda (bundle identifier)Это внутреннее имя приложения в системе и в магазине. Правило одно и оно жёсткое: после первой публикации его сменить нельзя. Можно только выпустить другое приложение и просить пользователей переустановить — с потерей всех отзывов, оценок и установок.
Шаблоны проектов подставляют сюда com.example.<имя>. Опубликовать с
com.example не получится: магазины такие идентификаторы не принимают. Менять
надо до первой публикации, и лучше — в первый день.
3. Разрешения объявляются в двух местах по-разному
Android — список в манифесте:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>iOS — не список, а объяснения для пользователя:
<key>NSLocationWhenInUseUsageDescription</key>
<string>Нужно, чтобы показать погоду в вашем городе.</string>Разница принципиальная. На Android ты объявляешь, что приложению нужно. На iOS ты обязан написать, зачем — текстом, который пользователь увидит в системном окне. Нет текста — приложение не пройдёт проверку, а на устройстве упадёт в момент запроса.
И ещё одно, что часто понимают неправильно: объявление в манифесте — это не разрешение. Разрешение даёт пользователь, во время работы приложения, и может отказать (статья 11.5). Объявление лишь даёт право спросить.
4. Подпись
Артефакт, который уходит в магазин, подписан криптографическим ключом. Подпись отвечает на один вопрос: это обновление того же приложения или другого?
| Платформа | Чем подписывают | Где хранится |
|---|---|---|
| Android | ключ в файле-хранилище (keystore) | у тебя, не в репозитории |
| iOS | сертификат разработчика и профиль | в учётной записи Apple |
Про Android-ключ надо знать одну вещь, и она неприятная: потерял ключ — не можешь выпустить обновление. Никогда. Приложение в магазине остаётся, а обновить его нельзя — только публиковать заново под новым идентификатором. Сервис подписи от магазина частично спасает ситуацию, но включать его надо заранее, до первой публикации.
Отсюда два правила:
- Ключ и пароли к нему — не в репозиторий. Файл хранилища, пароли, пути к
ним выносятся в файл, который в
.gitignore. Это ровно тот же разговор, что про.envв статье 5.7, просто ставка выше. - Резервная копия ключа — в двух местах, и ни одно из них не твой ноутбук.
Отладочная подпись, которой инструменты подписывают сборки при разработке,
для магазина не годится. Признак проблемы: артефакт называется app-debug.apk
или в логе сборки видно signingConfig debug.
Что ещё отрежет пользователей
minSdk 26 ← ниже этой версии Android приложение не установитсяМинимальная версия системы — тихое решение с громкими последствиями. Подняли, чтобы заработала библиотека, — отрезали часть пользователей. Это нормальный обмен, но он должен быть осознанным: ИИ поднимает минимальную версию мимоходом, одной строкой в настройках, и в объяснении об этом не пишет.
Как сказать ИИ
Ключевой приём для этой статьи — требовать объяснения последствий, а не правок. Настройки платформы меняются редко и стоят дорого.
Предложи, что изменить, чтобы заработала эта библиотека.
Для каждой правки в android/ и ios/ отдельно напиши,
что она меняет для пользователя: минимальная версия
системы, новые разрешения, размер приложения.
Правки, затрагивающие minSdk, помечай явно.Вот список разрешений моего приложения: <список>.
Приложение делает только <описание>.
Какие из разрешений лишние? Для каждого нужного напиши
текст объяснения для iOS — по-русски, одно предложение.Второй запрос решает сразу две задачи: убирает лишние разрешения, из-за которых отказывают в публикации, и пишет те самые тексты объяснений, которые забывают.
Я готовлю обновление. Что надо поднять в версии
и где именно это записано в проекте?
Покажи строку до и после.Проверь, не попали ли в репозиторий файлы подписи
и пароли: ключи, хранилища, профили, файлы свойств.
Список найденного и строки для .gitignore.На что смотреть
Разрешения «на всякий случай». В приложении со списком городов появились камера и контакты. ИИ добавляет разрешения, когда библиотека теоретически умеет ими пользоваться. Магазины за это отказывают, а пользователи — удаляют.
Нет текста объяснения для iOS. Разрешение объявлено, объяснения нет: отказ при проверке.
Версия не поднята. Загрузка отклонена, двадцать минут сборки впустую.
Идентификатор остался com.example. Шаблон не правили.
Отладочная подпись. app-debug.apk вместо подписанного артефакта.
Файлы подписи в репозитории. Хранилище ключа, пароли, профили — всё это попадает в историю git, а оттуда уже не удаляется просто так.
minSdk поднят без объяснения. Одна строка, и часть пользователей больше
не может установить приложение.
Разрешение объявлено, но отказ не обработан. Самая частая ошибка в коде на эту тему — та же, что в статье 11.5.
Шпаргалка
1.2.0+34: первое для людей, второе для магазина и обязано расти.Идентификатор приложения после публикации не меняется — решай сразу.
Android объявляет разрешения, iOS требует объяснить зачем — текстом.
Объявление в манифесте ≠ разрешение: его даёт пользователь и может отказать.
Потерял ключ подписи — обновления не будет. Копия в двух местах.
Ключи и пароли — в
.gitignore, а не в репозиторий.minSdk— это решение о том, кто не сможет поставить приложение.Проси у ИИ не правку настроек, а правку с ценой для пользователя.