packages

Application

Read the installed app's identity: name, bundle or package id, version and build number as plain constants, the install and update time as UTC datetimes, the Android id and Play install referrer, and on iOS the vendor id, how the build was signed and the push environment. A call that does not exist on this platform raises NotSupportedError instead of returning a made-up value. Nothing here needs a permission.

  • pyxpo-application
  • v0.1.0a1
  • Native: Swift + Kotlin
  • Like expo-application
App name, id, version, build, install time and platform ids on Android and iOS.
App name, id, version, build, install time and platform ids on Android and iOS.

Install

Install the package into the same environment as pyxpo.

$pip install pyxpo-application

Add application to modules in your app config, then import it in your code.

pyproject.toml
[tool.pyxpo]
modules = ["application"]
python
import pyxpo_application as Application

Needs Python 3.9+ and pyxpo>=0.1.0a2.

This module has native code. After you add it, run pyxpo run or pyxpo build again so it is compiled into the app. Hot reload alone is not enough.

Platforms

iOSConstants, install time, vendor id, release type, push environment.
AndroidAPI 24+. Constants, install and update time, Android id, install referrer.
Desktop previewConstants are None; functions raise NotSupportedError.
WebSame as the desktop: there is no installed app.

Quick start

app/index.py
import pyxpo_application as Application
from pyxpo import Platform, Text, View, component, use_async


@component
def About():
    async def load():
        info = {"installed": await Application.get_installation_time_async()}
        if Platform.OS == "android":
            info["updated"] = await Application.get_last_update_time_async()
        return info

    info = use_async(load, [])           # (loading, value, error)
    return View(
        Text("%s %s (%s)" % (Application.application_name,
                             Application.native_application_version,
                             Application.native_build_version)),
        Text(Application.application_id),
        Text("Installed %s" % (info.value["installed"].date() if info.value else "...")),
    )

Permissions

pyxpo adds these to Info.plist and AndroidManifest.xml for you when the module is listed.

iOSNone.
AndroidNone.

API reference

Constants

Read from Info.plist (iOS) and PackageInfo (Android). They resolve when you read them, so read them inside a component or function, not into module-level variables at import. None on the desktop and web.

application_name→ str or None

CFBundleDisplayName or CFBundleName; the Android app label.

application_id→ str or None

The bundle identifier or package name.

native_application_version→ str or None

CFBundleShortVersionString or versionName.

native_build_version→ str or None

CFBundleVersion or versionCode, as a string on both platforms.

Install and update time

await get_installation_time_async()→ datetime (UTC)

iOS: creation time of the Documents folder, so a reinstall gives a new date. Android: firstInstallTime.

await get_last_update_time_async()→ datetime (UTC)

Android only: lastUpdateTime.

Platform ids

These ids are not secret and not stable forever. Do not use them as a login.

get_android_id()→ str

Android. Settings.Secure.ANDROID_ID: unique per signing key, user and device; changes on factory reset. Synchronous.

await get_install_referrer_async()→ str

Android. The Google Play install referrer. Raises RuntimeError where the Play Store is missing.

await get_ios_id_for_vendor_async()→ str or None

iOS. identifierForVendor. None right after a restart, before the first unlock.

iOS build

await get_ios_application_release_type_async()→ ApplicationReleaseType

Read from the embedded provisioning profile.

await get_ios_push_notification_service_environment_async()→ str or None

The aps-environment entitlement: "development", "production" or None.

Types

Every name also has its expo-application spelling, such as Application.applicationId and Application.getInstallationTimeAsync.

ApplicationReleaseType (IntEnum)

KeyTypeDescription
UNKNOWN0The profile could not be read.
SIMULATOR1Running in the iOS Simulator.
ENTERPRISE2Enterprise distribution.
DEVELOPMENT3A development profile (run from Xcode).
AD_HOC4An ad hoc profile.
APP_STORE5The App Store or TestFlight.

Errors

KeyTypeDescription
NotSupportedErrorpyxpo.module_apiThe call does not exist on this platform. Guard with Platform.OS.
ModuleNotLinkedErrorpyxpo.module_api"application" is missing from modules. Add it and rebuild.
RuntimeErrorinstall referrerNo Play Store on the device. Treat the referrer as unknown.

Examples

Store build or test build

Tell a TestFlight or App Store build from a development build on iOS.

Constants and ids on Android and iOS.
Constants and ids on Android and iOS.
python
import pyxpo_application as Application


async def is_store_build():
    kind = await Application.get_ios_application_release_type_async()
    return kind == Application.ApplicationReleaseType.APP_STORE

Recipe: About screen with an update check

Show the version, and say "Updated recently" when Android installed a new build in the last week.

python
from datetime import datetime, timedelta, timezone

import pyxpo_application as Application
from pyxpo import Platform, Text, View, component, use_async


async def recently_updated() -> bool:
    if Platform.OS != "android":
        return False
    updated = await Application.get_last_update_time_async()
    return datetime.now(timezone.utc) - updated < timedelta(days=7)


@component
def AboutScreen():
    fresh = use_async(recently_updated, [])
    return View(
        Text(Application.application_name or "My app"),
        Text("Version %s (%s)" % (Application.native_application_version or "dev",
                                  Application.native_build_version or "0")),
        Text("Updated recently") if fresh.value else None,
    )

Testing

Patch the constant reader in a unit test.

python
import pyxpo_application as Application


def test_about_text(monkeypatch):
    fake = {"applicationName": "Demo", "nativeApplicationVersion": "2.0.0"}
    monkeypatch.setattr(Application, "_const", lambda name: fake.get(name))
    assert Application.application_name == "Demo"

Good to know

  • No module options and no config plugin. On Android the module adds the com.android.installreferrer library.
  • The version and build you set for the app are written into Info.plist and the Android manifest at build time; this module reads them back.
  • native_build_version is a string on both platforms. Use int(...) for a number.
  • In the iOS Simulator the release type is SIMULATOR and the push environment is None.
  • Write UI code so a None version shows a placeholder, for example Application.native_application_version or "dev".