Praman
Invitation links on Android
Every invitation Praman sends links to one Notils page. Configure your Android app once, and the link opens your app at the invitation, or installs it from Google Play and keeps the invitation through the install.
How invitation links work
A project's invitation link starts as https://notils.com/i/<project id>/<token>, for example https://notils.com/i/acme-shop/pri_8Hc2…. A Development environment has its own prefix, /i/acme-shop-dev/. You can change the link on the project's Invitations page if you would rather host your own.
| The person opens the link… | What happens |
|---|---|
| On Android, app installed | Android App Links open your app directly with the link. If the browser opens the page instead, its Open button launches your app. |
| On Android, app not installed | The page shows the invitation and sends them to Google Play with notils_invite=<token> in the install referrer. Your app reads it on first launch. |
| On a computer or iPhone | The page shows a QR code to open the link on an Android phone. |
| Expired, used or revoked | One neutral message: the invitation can't be used, ask for a new one. |
The page only shows the invitation. Accepting happens in your app, after the person signs in and proves the number or address it was sent to.
Configure your project
Add the package and fingerprints in the dashboard
Open the project in the dashboard, then Configure → Mobile app. Enter the Android package (
com.acme.shop), the SHA-256 fingerprints of the keys your builds are signed with (up to 10), and your Play Store listing. Production and Development are configured separately, so a debug build can use its own package and key.For a release on Google Play, the fingerprint that matters is the app signing key: Play Console → your app → Test and release → App integrity → App signing → App signing key certificate → SHA-256. Add your upload key too if you test locally signed builds.
Terminal# Your upload or debug key (Play App Signing's key is in Play Console) keytool -list -v -keystore ~/.android/debug.keystore \ -alias androiddebugkey -storepass android | grep SHA256 # Or, in an Android project ./gradlew signingReportClaim your path in the app
Add an intent filter for your own project's prefix. Use the project id from the dashboard; Development builds use the
-devid.AndroidManifest.xml<activity android:name=".MainActivity" android:exported="true"> <!-- Notils invitation links for this project only --> <intent-filter android:autoVerify="true"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="https" android:host="notils.com" android:pathPrefix="/i/acme-shop/" /> </intent-filter> </activity>In an Expo app, the same filter goes in the app config:
app.json{ "expo": { "android": { "package": "com.acme.shop", "intentFilters": [ { "action": "VIEW", "autoVerify": true, "category": ["BROWSABLE", "DEFAULT"], "data": [ { "scheme": "https", "host": "notils.com", "pathPrefix": "/i/acme-shop/" } ] } ] } } }Read the token
When the link opens your app, the token is the last path segment. Keep it until the person has signed in, then show the invitation and accept it.
Kotlin// https://notils.com/i/acme-shop/pri_8Hc2… → "pri_8Hc2…" fun invitationToken(uri: Uri, projectId: String): String? { val segments = uri.pathSegments // ["i", "acme-shop", "<token>"] if (segments.size != 3 || segments[0] != "i" || segments[1] != projectId) return null return segments[2] }Read the install referrer on first launch
When someone installs from the invitation page, Google Play hands your app the referrer
notils_invite=<token>. Read it once with the Play Install Referrer library and treat it exactly like an opened link.Kotlin// implementation("com.android.installreferrer:installreferrer:2.2") val client = InstallReferrerClient.newBuilder(context).build() client.startConnection(object : InstallReferrerStateListener { override fun onInstallReferrerSetupFinished(code: Int) { if (code == InstallReferrerClient.InstallReferrerResponse.OK) { // "notils_invite=pri_8Hc2…" (other keys may be present: split on &) val referrer = client.installReferrer.installReferrer val token = referrer.split("&") .map { it.split("=", limit = 2) } .firstOrNull { it.size == 2 && it[0] == "notils_invite" } ?.let { Uri.decode(it[1]) } if (token != null) savePendingInvitation(token) // once, on first launch } client.endConnection() } override fun onInstallReferrerServiceDisconnected() {} })
Check that Android verified your app
Notils publishes https://notils.com/.well-known/assetlinks.json from every project's package and fingerprints, refreshed within about five minutes of a change. After installing a build, ask Android to verify again and check the result:
adb shell pm verify-app-links --re-verify com.acme.shop
adb shell pm get-app-links com.acme.shop
# notils.com: verifiedWhy the whole host, but only your path
assetlinks.json on notils.com. Which links your app then opens is decided by your intent filter. Claim only /i/<your project id>/, so your app never opens another app's invitations, and theirs never open yours.Testing on staging
staging.notils.com. A build that talks to staging Praman needs android:host="staging.notils.com" in its filter.