getAvailableApps static method

Future<List<AppInfo>> getAvailableApps({
  1. required LaunchType type,
  2. required Uri uri,
  3. List<String>? iOSAppSchemes,
})

Checks for the availability of common apps for a given LaunchType on iOS.

Returns a list of AppInfo for apps that can handle the URI.

Implementation

static Future<List<AppInfo>> getAvailableApps({
  required LaunchType type,
  required Uri uri,
  List<String>? iOSAppSchemes,
}) async {
  final List<AppInfo> availableApps = [];

  // Define common schemes for various LaunchTypes
  final Map<LaunchType, List<Map<String, String>>> commonAppSchemes = {
    LaunchType.map: [
      {'name': 'Apple Maps', 'scheme': 'maps://'},
      {'name': 'Google Maps', 'scheme': 'comgooglemaps://'},
      {'name': 'Waze', 'scheme': 'waze://'},
    ],
    LaunchType.website: [
      {'name': 'Safari', 'scheme': 'https://'},
    ],
    LaunchType.email: [
      {'name': 'Mail', 'scheme': 'mailto:'},
    ],
    LaunchType.phone: [
      {'name': 'Phone', 'scheme': 'tel:'},
    ],
    LaunchType.sms: [
      {'name': 'Messages', 'scheme': 'sms:'},
    ],
    LaunchType.whatsapp: [
      {'name': 'WhatsApp', 'scheme': 'whatsapp://'},
    ],
    LaunchType.instagram: [
      {'name': 'Instagram', 'scheme': 'instagram://'},
    ],
    LaunchType.tiktok: [
      {'name': 'TikTok', 'scheme': 'tiktok://'},
    ],
    LaunchType.linkedin: [
      {'name': 'LinkedIn', 'scheme': 'linkedin://'},
    ],
  };

  final List<Map<String, String>> schemesToCheck = [
    ...(commonAppSchemes[type] ?? []),
    if (iOSAppSchemes != null)
      ...iOSAppSchemes.map((scheme) => {'name': scheme, 'scheme': scheme}),
  ];

  // Parallelize checks using Future.wait
  final List<Future<AppInfo?>> checkFutures =
      schemesToCheck.map((appScheme) async {
    final String scheme = appScheme['scheme']!;
    final String appName = appScheme['name']!;

    // Use cache if available
    if (_checkCache.containsKey(scheme)) {
      return _checkCache[scheme]!
          ? AppInfo(name: appName, scheme: scheme)
          : null;
    }

    final Uri checkUri = Uri.parse(
        scheme.endsWith(':') || scheme.endsWith('://')
            ? scheme
            : '$scheme://');
    try {
      final bool canLaunch = await canLaunchUrl(checkUri);
      _checkCache[scheme] = canLaunch; // Cache the result
      if (canLaunch) {
        return AppInfo(name: appName, scheme: scheme);
      }
    } catch (e) {
      debugPrint('Error checking scheme $scheme: $e');
    }
    return null;
  }).toList();

  final List<AppInfo?> results = await Future.wait(checkFutures);
  availableApps.addAll(results.whereType<AppInfo>());

  return availableApps;
}