Android and iOS
versions, signing, permissions, identifier
What it is
Besides its code, a mobile application has a passport: who released it, which version it is, what it is allowed to do and what the system calls it. Those four things live not in the code but in the settings of the platform folders — and they are exactly why a build that ran beautifully on your own phone isn't accepted by the store.
An AI helps less here than with code: the requirements change every year while the training data stays the same. The concepts themselves, though, don't change for decades — and those are the ones worth knowing.
What it looks like in code
1. The version is two different numbers
version: 1.2.0+34One line in pubspec.yaml, and the build turns it into two values:
| Part | Android | iOS | Who sees it |
|---|---|---|---|
1.2.0 | versionName | Version | the user, in the store |
34 | versionCode | Build | the store only |
The first is for people, shown in the update's description. The second is for the store, and it has to grow with every upload. If it didn't, the upload is rejected with a message that this version already exists.
That is the most frequent and most foolish waste of time when shipping: the build takes twenty minutes and the rejection comes because of a number nobody incremented.
2. The identifier is forever
Android: com.lunario.weather (applicationId)
iOS: com.lunario.weather (bundle identifier)This is the application's internal name in the system and in the store. There is one rule and it is hard: after the first release it cannot be changed. You can only publish a different application and ask users to reinstall — losing every review, rating and install.
Project templates put com.example.<name> here. You can't publish with
com.example: the stores don't accept such identifiers. Change it before
the first release, and preferably on day one.
3. Permissions are declared in two places, differently
Android — a list in the manifest:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>iOS — not a list but explanations for the user:
<key>NSLocationWhenInUseUsageDescription</key>
<string>Needed to show the weather in your city.</string>The difference is fundamental. On Android you declare what the application needs. On iOS you are obliged to write why — in text the user will see in the system dialog. No text and the application won't pass review, and on a device it will crash at the moment of the request.
And one more thing people often misunderstand: a declaration in the manifest isn't a permission. The permission is granted by the user, while the application is running, and they can refuse (article 11.5). The declaration only gives you the right to ask.
4. Signing
The artifact that goes to the store is signed with a cryptographic key. The signature answers one question: is this an update to the same application, or a different one?
| Platform | What signs it | Where it is kept |
|---|---|---|
| Android | a key in a keystore file | with you, not in the repository |
| iOS | a developer certificate and a profile | in your Apple account |
There is one thing you need to know about the Android key, and it is unpleasant: lose the key and you can't release an update. Ever. The application stays in the store and cannot be updated — only republished under a new identifier. The store's signing service partly saves the situation, but it has to be switched on in advance, before the first release.
Hence two rules:
- The key and its passwords do not go into the repository. The keystore
file, the passwords and the paths to them go into a file that is in
.gitignore. That is exactly the conversation about.envfrom article 5.7, only with higher stakes. - A backup of the key in two places, and neither of them your laptop.
The debug signature the tools use for development builds is no good for the
store. The sign of trouble: the artifact is called app-debug.apk, or the
build log shows signingConfig debug.
What else will cut users off
minSdk 26 ← below this Android version the app won't installThe minimum system version is a quiet decision with loud consequences. Raised it to make a library work and you cut off some of your users. That is a normal trade, but it has to be a conscious one: an AI raises the minimum version in passing, with one line in the settings, and doesn't mention it in the explanation.
What to tell the AI
The key technique for this article is to demand an account of the consequences, not edits. Platform settings change rarely and cost a lot.
Propose what to change to make this library work.
For each edit in android/ and ios/, write separately what it
changes for the user: minimum system version, new
permissions, app size. Flag edits touching minSdk
explicitly.Here is my application's permission list: <list>.
The application only does <description>.
Which permissions are unnecessary? For each one that is
needed, write the iOS explanation text — one sentence.That second request solves two problems at once: it removes the surplus permissions that get releases rejected, and it writes the very explanation texts people forget.
I'm preparing an update. What has to be raised in the
version, and where exactly is it recorded in the project?
Show the line before and after.Check whether signing files and passwords have got into the
repository: keys, keystores, profiles, properties files.
A list of what you find and the lines for .gitignore.What to look for
Permissions "just in case". An application with a list of cities has acquired the camera and contacts. An AI adds permissions when a library could theoretically use them. Stores reject you for that, and users uninstall.
No explanation text for iOS. The permission is declared, the explanation isn't: rejected at review.
The version wasn't raised. Upload rejected, twenty minutes of building wasted.
The identifier is still com.example. The template wasn't edited.
A debug signature. app-debug.apk instead of a signed artifact.
Signing files in the repository. The keystore, passwords, profiles — all of it goes into the git history, and from there it isn't simply removed.
minSdk raised with no explanation. One line, and some of your users
can no longer install the application.
A permission declared but refusal unhandled. The most frequent code mistake on this subject — the same one as in article 11.5.
Cheat sheet
1.2.0+34: the first is for people, the second is for the store and has to grow.The application identifier can't be changed after release — decide at once.
Android declares permissions, iOS demands an explanation — in text.
A manifest declaration ≠ a permission: the user grants it and can refuse.
Lose the signing key and there are no more updates. A copy in two places.
Keys and passwords go in
.gitignore, not in the repository.minSdkis a decision about who won't be able to install the app.Ask an AI not for a settings edit but for an edit with its price to the user.