Skip to content

AppManager

MicroPythonOS provides a centralized app management service called AppManager. It handles app discovery, installation, uninstallation, launching, and version management across the system.

Overview

AppManager provides:

  • App discovery - Automatically finds and catalogs all installed apps
  • App registry - Maintains a sorted list of apps with metadata (name, version, icon, etc.)
  • App installation - Installs apps from .mpk (MicroPython Package) ZIP files
  • App uninstallation - Removes user-installed apps (preserves built-in apps)
  • App launching - Starts apps with proper environment setup and activity management
  • Version management - Compares versions and detects available updates
  • Intent resolution - Resolves activities that handle specific intents (Android-inspired)
  • Launcher management - Finds and restarts the system launcher
  • Service management - Registers, resolves, and starts boot services

Quick Start

Initialization

AppManager is initialized at system startup and automatically discovers all apps:

from mpos import AppManager

# Get list of all installed apps (auto-discovers on first call)
apps = AppManager.get_app_list()

for app in apps:
    print(f"{app.name} v{app.version}")

Listing Apps

from mpos import AppManager

# Get all apps (sorted by name)
all_apps = AppManager.get_app_list()

# Get specific app by fullname
app = AppManager.get("com.example.myapp")

# Access app by fullname (raises KeyError if not found)
try:
    app = AppManager["com.example.myapp"]
except KeyError:
    print("App not found")

Launching Apps

from mpos import AppManager

# Start an app by fullname
success = AppManager.start_app("com.example.myapp")

if success:
    print("App started successfully")
else:
    print("Failed to start app")

Installing Apps

from mpos import AppManager

# Install an app from a .mpk file
# .mpk files are ZIP archives containing the app structure
AppManager.install_mpk(
    temp_zip_path="/tmp/myapp.mpk",
    dest_folder="apps/com.example.myapp"
)

# AppManager automatically refreshes the app list after installation

Uninstalling Apps

from mpos import AppManager

# Uninstall a user-installed app
AppManager.uninstall_app("com.example.myapp")

# Built-in apps cannot be uninstalled
# AppManager automatically refreshes the app list after uninstallation

App Discovery

AppManager discovers apps by scanning two directories:

  1. builtin/apps/ - System-provided apps (cannot be uninstalled)
  2. apps/ - User-installed apps (can be uninstalled)

User-installed apps override built-in apps with the same fullname.

Discovery Process

from mpos import AppManager

# Manually trigger app discovery (called automatically on first use)
AppManager.refresh_apps()

# Clear cached app list
AppManager.clear()

# Refresh will repopulate the cache
AppManager.get_app_list()

App Structure

Each app must have this directory structure:

apps/com.example.myapp/
├── META-INF/
│   └── MANIFEST.JSON          # App metadata
├── assets/
│   ├── main.py                # Main activity entry point
│   ├── icon.png               # App icon
│   └── ...                    # Other assets
└── ...

The MANIFEST.JSON file contains app metadata:

{
  "fullname": "com.example.myapp",
  "name": "My App",
  "version": "1.0.0",
  "description": "A sample app",
  "main_launcher_activity": {
    "entrypoint": "assets/main.py",
    "classname": "Main"
  }
}

App Information

Each app object provides metadata:

from mpos.content.app_manager import AppManager

app = AppManager.get("com.example.myapp")

# Access app properties
print(f"Name: {app.name}")
print(f"Fullname: {app.fullname}")
print(f"Version: {app.version}")
print(f"Description: {app.description}")
print(f"Installed path: {app.installed_path}")
print(f"Icon: {app.icon}")
print(f"Main activity: {app.main_launcher_activity}")

Version Management

AppManager provides version comparison utilities:

Comparing Versions

from mpos import AppManager

# Compare two version strings
# Returns True if ver1 > ver2, False otherwise
is_newer = AppManager.compare_versions("2.0.0", "1.5.0")
# Returns: True

is_newer = AppManager.compare_versions("1.5.0", "2.0.0")
# Returns: False

is_newer = AppManager.compare_versions("1.0.0", "1.0.0")
# Returns: False (equal versions)

Checking for Updates

from mpos import AppManager

# Check if a newer version is available
has_update = AppManager.is_update_available("com.example.myapp", "2.0.0")

if has_update:
    print("Update available!")

Installation Management

Installing Apps

from mpos import AppManager

# Install from a .mpk file (ZIP archive)
AppManager.install_mpk(
    temp_zip_path="/tmp/downloaded_app.mpk",
    dest_folder="apps/com.example.newapp"
)

# After installation, the app is immediately available
app = AppManager.get("com.example.newapp")

Checking Installation Status

from mpos import AppManager

# Check if app is installed (by name)
is_installed = AppManager.is_installed_by_name("com.example.myapp")

# Check if app is installed at specific path
is_installed = AppManager.is_installed_by_path("apps/com.example.myapp")

# Check if app is built-in
is_builtin = AppManager.is_builtin_app("com.example.myapp")

# Check if app is an override of a built-in app
is_override = AppManager.is_overridden_builtin_app("com.example.myapp")

Uninstalling Apps

from mpos import AppManager

# Uninstall a user-installed app
AppManager.uninstall_app("com.example.myapp")

# Built-in apps cannot be uninstalled
# Attempting to uninstall a built-in app will fail silently

Intent Resolution

AppManager implements Android-inspired intent resolution for activity discovery:

Registering Activities

Activities register themselves with AppManager to handle specific intents:

from mpos import AppManager
from mpos import Activity

class ShareActivity(Activity):
    pass

# Register activity to handle "android.intent.action.SEND" intent
AppManager.register_activity("android.intent.action.SEND", ShareActivity)

Resolving Intents

from mpos import AppManager, Intent

# Create an intent
intent = Intent(action="android.intent.action.SEND")

# Find all activities that handle this intent
activities = AppManager.resolve_activity(intent)

# Or use the Android-like method name
activities = AppManager.query_intent_activities(intent)

for activity_class in activities:
    print(f"Activity: {activity_class.__name__}")

Launcher Management

AppManager provides utilities for launcher discovery and restart:

Finding the Launcher

from mpos import AppManager

# Get the system launcher app
launcher = AppManager.get_launcher()

if launcher:
    print(f"Launcher: {launcher.fullname}")
    print(f"Name: {launcher.name}")

Restarting the Launcher

from mpos import AppManager

# Stop all activities and restart the launcher
AppManager.restart_launcher()

# This is useful when:
# - Exiting an app to return to home screen
# - Recovering from a crash
# - Refreshing the app list after installation/uninstallation

App Execution

AppManager handles the low-level execution of app scripts:

Starting Apps

from mpos import AppManager

# Start an app (high-level interface)
success = AppManager.start_app("com.example.myapp")

if success:
    print("App started")
else:
    print("Failed to start app")

Script Execution

AppManager can execute an app entrypoint module with proper environment setup:

from mpos import AppManager

# Execute a script file
success = AppManager.execute_script(
    script_source="assets/main.py",
    classname="Main",
    cwd="apps/com.example.myapp/assets/"
)

Execution Details

When executing a script, AppManager:

  1. Adds app assets path to the front of sys.path (if cwd provided)
  2. Imports the module derived from script_source filename
  3. Lets MicroPython choose .py first, then .mpy in the same directory
  4. Finds the main activity class by name
  5. Starts the activity using the Activity framework
  6. Restores sys.path and module cache entry (sys.modules) to clean up

If a cwd is provided, it's temporarily placed first in sys.path for import resolution.

Complete Example: App Store Integration

Here's how the App Store uses AppManager:

from mpos import Activity, AppManager
import lvgl as lv

class AppStoreActivity(Activity):
    def onCreate(self):
        self.screen = lv.obj()

        # List all installed apps
        apps = AppManager.get_app_list()

        # Create a list view
        list_view = lv.list(self.screen)
        list_view.set_size(lv.pct(100), lv.pct(100))

        for app in apps:
            # Create button for each app
            btn = list_view.add_button(lv.SYMBOL.DOWNLOAD, app.name)
            btn.add_event_cb(
                lambda e, a=app: self.on_app_selected(a),
                lv.EVENT.CLICKED,
                None
            )

        self.setContentView(self.screen)

    def on_app_selected(self, app):
        # Check if update is available
        if AppManager.is_update_available(app.fullname, "2.0.0"):
            print(f"Update available for {app.name}")
            # Download and install update
            # AppManager.install_mpk(...)
        else:
            # Launch the app
            AppManager.start_app(app.fullname)

API Reference

App Discovery

get_app_list()

Get list of all installed apps (sorted by name).

  • Returns: list[App] - List of App objects

get(fullname)

Get app by fullname.

  • Parameters:
  • fullname (str): App fullname (e.g., "com.example.myapp")

  • Returns: App or None - App object or None if not found

__getitem__(fullname)

Get app by fullname (raises KeyError if not found).

  • Parameters:
  • fullname (str): App fullname

  • Returns: App - App object

  • Raises: KeyError - If app not found

refresh_apps()

Scan directories and rebuild app list.

  • Behavior: Clears cache and rediscovers all apps

clear()

Clear cached app list.

  • Behavior: Empties internal caches; call get_app_list() to repopulate

App Installation

install_mpk(temp_zip_path, dest_folder)

Install app from .mpk (ZIP) file.

  • Parameters:
  • temp_zip_path (str): Path to temporary .mpk file
  • dest_folder (str): Destination folder (e.g., "apps/com.example.myapp")

  • Behavior: Extracts ZIP, removes temp file, refreshes app list

uninstall_app(app_fullname)

Uninstall a user-installed app.

  • Parameters:
  • app_fullname (str): App fullname

  • Behavior: Removes app folder from apps/, refreshes app list

  • Note: Built-in apps cannot be uninstalled

Version Management

compare_versions(ver1, ver2)

Compare two version strings.

  • Parameters:
  • ver1 (str): First version (e.g., "1.2.3")
  • ver2 (str): Second version (e.g., "1.0.0")

  • Returns: bool - True if ver1 > ver2, False otherwise

  • Behavior: Parses versions as dot-separated integers, compares component-wise

is_update_available(app_fullname, new_version)

Check if newer version is available.

  • Parameters:
  • app_fullname (str): App fullname
  • new_version (str): New version to check

  • Returns: bool - True if new_version > installed version

Installation Status

is_installed_by_name(app_fullname)

Check if app is installed (user or built-in).

  • Parameters:
  • app_fullname (str): App fullname

  • Returns: bool - True if installed

is_installed_by_path(dir_path)

Check if app is installed at specific path.

  • Parameters:
  • dir_path (str): Directory path (e.g., "apps/com.example.myapp")

  • Returns: bool - True if directory exists and has valid manifest

is_builtin_app(app_fullname)

Check if app is built-in (in builtin/apps/).

  • Parameters:
  • app_fullname (str): App fullname

  • Returns: bool - True if built-in

is_overridden_builtin_app(app_fullname)

Check if user app overrides a built-in app.

  • Parameters:
  • app_fullname (str): App fullname

  • Returns: bool - True if both user and built-in versions exist

App Execution

start_app(fullname)

Start an app by fullname.

  • Parameters:
  • fullname (str): App fullname

  • Returns: bool - True if successful

  • Behavior:

  • Sets app as foreground
  • Loads app metadata
  • Executes main activity script
  • Shows/hides top menu bar based on app type

execute_script(script_source, classname, cwd=None)

Execute a Python script with proper environment.

  • Parameters:
  • script_source (str): Script path used to derive module name (e.g., assets/main.py -> main)
  • classname (str): Name of main activity class to instantiate
  • cwd (str, optional): Working directory to add to sys.path

  • Returns: bool - True if successful

  • Behavior:

  • Temporarily prioritizes cwd in sys.path (if provided)
  • Imports module name derived from script_source
  • Uses normal MicroPython import precedence (.py then .mpy)
  • Finds and instantiates main activity class
  • Starts activity using Activity framework
  • Restores sys.path and the previous sys.modules entry for that module name

Intent Resolution

register_activity(action, activity_cls)

Register activity to handle intent action.

  • Parameters:
  • action (str): Intent action (e.g., "android.intent.action.SEND")
  • activity_cls (type): Activity class

resolve_activity(intent)

Find activities that handle intent.

  • Parameters:
  • intent (Intent): Intent object with action attribute

  • Returns: list[type] - List of Activity classes

query_intent_activities(intent)

Same as resolve_activity() (Android-like naming).

  • Parameters:
  • intent (Intent): Intent object

  • Returns: list[type] - List of Activity classes

Launcher Management

get_launcher()

Find the system launcher app.

  • Returns: App or None - Launcher app object

restart_launcher()

Stop all activities and restart launcher.

  • Behavior:
  • Removes and stops all activities
  • Starts launcher app
  • Useful for returning to home screen

Service Management

register_service(action, service_cls, fullname=None)

Register a service class to handle an intent action (programmatic registration, used by system services).

  • Parameters:
  • action (str): Intent action (e.g., "boot_completed")
  • service_cls (type): Service subclass
  • fullname (str, optional): App fullname to associate with the service

  • Example: ```python from mpos.content.app_manager import AppManager from mpos import Service

class MyBootService(Service): def onStart(self, intent): print("Boot service started")

AppManager.register_service("boot_completed", MyBootService, fullname="com.example.myapp") ```

get_services_for_action(action)

Resolve all services (manifest-declared and programmatically registered) that handle a given intent action.

  • Parameters:
  • action (str): Intent action (e.g., "boot_completed")

  • Returns: list[(str, type)] - List of (app_fullname, ServiceClass) tuples

  • Behavior:

  • Scans all installed apps' manifests for matching service entries
  • Imports each service module and extracts the class
  • Merges with programmatically registered services from _service_registry

start_boot_services()

Start all services that subscribe to the boot_completed intent. Called once during system boot after the launcher is displayed.

  • Behavior:
  • Calls get_services_for_action("boot_completed") to discover all boot services
  • For each service: instantiate, set appFullName, call onCreate(), then onStart(boot_intent)
  • Handles errors per-service so one failing service does not block others

  • Called by: main.py during system boot sequence

Best Practices

Do's

✅ Call AppManager.refresh_apps() after installing/uninstalling apps
✅ Check AppManager.get(fullname) before starting an app
✅ Use AppManager.start_app() for user-initiated app launches
✅ Handle version comparison for update checks
✅ Use intent resolution for extensible app interactions

Don'ts

❌ Directly manipulate app directories (use install_mpk() and uninstall_app())
❌ Assume app is installed without checking
❌ Start apps without verifying they exist
❌ Modify app metadata directly (read-only)
❌ Uninstall built-in apps (will fail)

Troubleshooting

App Not Found

Symptom: AppManager.get(fullname) returns None

Causes: - App not installed - Fullname is incorrect - App list not refreshed after installation

Solution:

from mpos import AppManager

# Refresh app list
AppManager.refresh_apps()

# Check if app exists
app = AppManager.get("com.example.myapp")
if app:
    print(f"Found: {app.name}")
else:
    print("App not found")
    # List all apps to verify
    for app in AppManager.get_app_list():
        print(f"  - {app.fullname}")

App Fails to Start

Symptom: start_app() returns False

Possible causes: - App not installed - Missing or invalid manifest - Main activity class not found - Script execution error

Solution:

from mpos import AppManager

# Verify app exists
app = AppManager.get("com.example.myapp")
if not app:
    print("App not installed")
    return

# Check app has installed path
if not app.installed_path:
    print("App has no installed path")
    return

# Check main activity is defined
if not app.main_launcher_activity:
    print("App has no main launcher activity")
    return

# Try to start
success = AppManager.start_app("com.example.myapp")
if not success:
    print("Failed to start - check console for errors")

Installation Fails

Symptom: install_mpk() doesn't create app

Possible causes: - Invalid ZIP file - Destination folder already exists - Insufficient permissions - Missing manifest in ZIP

Solution:

from mpos import AppManager

# Verify ZIP file is valid
import zipfile
try:
    with zipfile.ZipFile("/tmp/app.mpk", "r") as z:
        print("ZIP contents:", z.namelist())
except Exception as e:
    print(f"Invalid ZIP: {e}")
    return

# Install with error handling
try:
    AppManager.install_mpk("/tmp/app.mpk", "apps/com.example.newapp")
    print("Installation successful")
except Exception as e:
    print(f"Installation failed: {e}")

# Verify installation
app = AppManager.get("com.example.newapp")
if app:
    print(f"App installed: {app.name}")

See Also

Back to top