Skip to content
Titanium SDK

Certificates & provisioning

Written for Titanium SDK 13.4.0 and later

Development signing - getting a build onto your own device - is covered in environment setup. This page is the identities you need to give a build to somebody else.

Android: a keystore

A keystore is a file you generate once and keep for the life of the app.

keytool -genkey -v -keystore myapp.keystore -alias myapp \
  -keyalg RSA -keysize 2048 -validity 10000

keytool ships with the JDK, so it is already on the machine.

Warning

Back this up somewhere you will still have in five years, and record the passwords with it. Google Play identifies your app by its signing key. Lose the keystore or its password and you cannot ship an update - not with a support ticket, not with anything. The app has to be republished under a new id, losing its listing, reviews and installs.

Do not commit it. A keystore in the repository is the signing identity of your app in every clone of it.

Build against it:

ti build --platform android --target dist-playstore \
  --keystore /secure/myapp.keystore --alias myapp --output-dir ./dist

The CLI prompts for the password. --store-password exists for CI, where it should come from a secret rather than a shell history.

Save the path and alias so you stop retyping them:

{
  "titanium.android.keystorePath": "/secure/myapp.keystore",
  "titanium.android.keystoreAlias": "myapp"
}

That is the VS Code extension's settings. The password is asked for each time and is not stored.

Play App Signing

Google Play can hold the signing key for you: you sign with an upload key, Play re-signs with the real one. It removes the catastrophic-loss problem, because an upload key can be reset by support.

Turn it on when you first publish. It cannot be added to an existing app without Google's involvement.

iOS: a certificate and a profile

Two things, and both come from Apple.

A distribution certificate identifies you. One per team, reused across apps, valid for a year.

A provisioning profile ties a certificate to an app id and, for ad-hoc builds, to a list of device UDIDs. One per app per distribution method.

Make them in Xcode - Settings, Accounts, Manage Certificates - or in the developer portal. Xcode is less error-prone because it puts the private key in your keychain at the same time.

Titanium reads certificates from the keychain and profiles from where Xcode keeps them, so anything Xcode can see it can use:

ti info -t ios

That lists the certificates and profiles it found, with their UUIDs. It is the fastest way to answer "which profile does it think it has".

ti build --platform ios --target dist-appstore \
  --distribution-name "Apple Distribution: Example Ltd (ABCDE12345)" \
  --pp-uuid 12345678-1234-1234-1234-123456789012 \
  --output-dir ./dist

Set ios.distributionName in CLI configuration to stop passing the certificate every time.

The private key is the part that matters

A certificate without its private key is useless, and the key lives in the keychain of the machine that made the request. Moving to a new machine means exporting a .p12 from the old one, not downloading the certificate again.

Export it when you create it, not when you need it.

Which target signs with what

Target Signing Produces
device Development An app on the connected device
dist-adhoc Distribution + ad-hoc profile .ipa for named devices
dist-appstore Distribution + App Store profile .ipa for upload
dist-playstore Your keystore .aab for upload

Next

Apple App Store and Google Play take it from here.

Edit this page on GitHubLast updated Nov 9, 2026