installed_apps_manager

A strictly focused, high-performance Flutter plugin for managing installed applications on Android devices.

Designed with open-source scalability in mind, it safely handles large application counts (1000+ apps) by utilizing Native Caching, Pagination, and Lazy Icon Loading.

Features

  • Fetch Installed Apps: Retrieve all user and system apps.
  • Robust Pagination: Fetch applications in chunks to prevent TransactionTooLargeException and UI stutter on devices with hundreds of apps.
  • Lazy Icon Loading: Load app icons dynamically on-demand using AppIconImageProvider.
  • App Actions: Launch apps, open app settings, and uninstall applications directly from Flutter.
  • Extract APKs: Extract the raw APK (or split .apks) of any installed app to the user's Downloads folder.
  • Save Icons: Save the high-resolution icon of any app directly to the device's Pictures gallery.

Permissions

To fetch the list of installed applications on Android 11 (API level 30) and above, you must declare the QUERY_ALL_PACKAGES permission in your android/app/src/main/AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.app">
    <!-- Required to query ALL installed applications -->
    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>

    <application>
        ...
    </application>
</manifest>

Note: If you are publishing to the Google Play Store, you will need to justify the use of this permission in your Play Console declarations.

Safe Alternative: Targeted Intent Fetching

If you do not want to declare QUERY_ALL_PACKAGES and risk Play Store rejection, you can fetch specific apps by providing an intent action:

// Safely fetch only apps that appear in the device launcher
List<AppInfo> apps = await InstalledAppsManager.getAppsWithIntent('android.intent.action.MAIN');

Usage

To avoid freezing the UI when fetching a large list of applications, use the paginated method:

import 'package:installed_apps_manager/installed_apps_manager.dart';

// Fetch the first 50 apps, searching for "whatsapp", sorted by base APK size
Page<AppInfo> page = await InstalledAppsManager.getInstalledAppsPaginated(
  limit: 50,
  offset: 0,
  includeSystemApps: false,
  searchQuery: 'whatsapp',
  sortBy: AppSortBy.size,
  sortOrder: SortOrder.descending,
);

List<AppInfo> apps = page.items;
bool isLast = page.isLastPage;

2. Rendering Lazy Icons

To render the icon of an app, use the AppIconImageProvider. This fetches the icon from the native Android side only when the widget is rendered on the screen.

CircleAvatar(
  backgroundImage: AppIconImageProvider(app.packageName),
)

3. Application Actions

All application actions throw strongly-typed exceptions (AppLaunchException, AppUninstallException, etc.) instead of returning weak booleans. This allows you to handle failures gracefully in your UI.

try {
  // Launch the app
  await InstalledAppsManager.openApp('com.whatsapp');

  // Open App Settings
  await InstalledAppsManager.openSettingsScreen('com.whatsapp');

  // Prompt Uninstall
  await InstalledAppsManager.uninstallApp('com.whatsapp');
} on InstalledAppsManagerException catch (e) {
  print('Action failed: ${e.message}');
}

4. Extracting APKs & Icons

Extract the base APK or split APKs to the user's Downloads folder:

String? path = await InstalledAppsManager.extractApk('com.whatsapp', 'WhatsApp');
print('Saved to: $path');

Save the app's icon to the gallery:

String? path = await InstalledAppsManager.saveAppIcon('com.whatsapp', 'WhatsApp');
print('Saved to: $path');