run method

  1. @override
Future<void> run(
  1. List<String> args, {
  2. required Logger logger,
})
override

The execution body of the command.

Implementation

@override
Future<void> run(List<String> args, {required Logger logger}) async {
  final finder = ProjectFinder();
  final projectRoot = finder.findProjectRoot();
  final project = FlutterProject(projectRoot);

  final configManager = ConfigManager(projectRoot);
  if (!configManager.configExists()) {
    logger.error('No configuration found. Please run "deeplink init" first.');
    return;
  }

  final config = configManager.load();

  // 1. Gather domains
  final List<String> domains = [];
  if (args.isNotEmpty) {
    domains.addAll(
      args.join(' ').split(',').map((d) => d.trim().replaceAll(RegExp(r'^https?://'), '')).where((d) => d.isNotEmpty),
    );
  } else {
    final defaultDomains = config.domains.isNotEmpty ? config.domains.join(', ') : 'example.com';
    final domainsInput = Console.ask('Enter domain names (comma-separated)', defaultValue: defaultDomains);
    domains.addAll(
      domainsInput
          .split(',')
          .map((d) => d.trim().replaceAll(RegExp(r'^https?://'), ''))
          .where((d) => d.isNotEmpty),
    );
  }

  if (domains.isEmpty) {
    logger.error('At least one domain is required to enable App Links.');
    return;
  }

  final spinner = Spinner('Enabling Android App Links...');
  spinner.start();

  try {
    // 2. Update AndroidManifest.xml
    if (FileUtils.exists(project.androidManifestPath)) {
      var manifestContent = FileUtils.readAsString(project.androidManifestPath);
      manifestContent = AndroidManifestEditor().enableAppLinks(manifestContent, domains);
      FileUtils.writeString(project.androidManifestPath, manifestContent);
    }

    // 3. Update configuration
    final updatedConfig = DeepLinkConfig(
      schemes: config.schemes,
      generateSampleRoutes: config.generateSampleRoutes,
      generateDeepLinkManager: config.generateDeepLinkManager,
      androidAppLinks: true,
      iosUniversalLinks: config.iosUniversalLinks,
      domains: domains,
    );

    configManager.save(updatedConfig);

    // 4. Regenerate setup artifacts
    final setupDir = PathUtils.join(projectRoot, 'deeplink_setup');
    FileUtils.createDirectory(setupDir);

    final templateEngine = TemplateEngine();
    final packageName = project.getAndroidPackageName();

    final renderedAssetLinks = templateEngine.render(
      TemplatesBundle.assetLinksJson,
      {
        'PACKAGE_NAME': packageName,
        'SHA256_FINGERPRINT': 'YOUR_SHA256_FINGERPRINT_HERE',
      },
    );
    FileUtils.writeString(PathUtils.join(setupDir, 'assetlinks.json'), renderedAssetLinks);

    // Regenerate README.md
    final primaryScheme = config.schemes.isNotEmpty ? config.schemes.first : 'myapp';
    final renderedInstructions = templateEngine.render(
      TemplatesBundle.setupInstructions,
      {
        'SCHEME': primaryScheme,
        'DOMAINS': domains.join(', '),
        'PACKAGE_NAME': packageName,
        'DOMAIN_1': domains[0],
        'DOMAIN_2': domains.length > 1 ? domains[1] : 'your-second-domain.com',
      },
    );
    FileUtils.writeString(PathUtils.join(setupDir, 'README.md'), renderedInstructions);

    // Run Flutter generator to keep code constant file in sync
    final generator = FlutterGenerator(projectRoot, logger);
    generator.generate(updatedConfig);

    spinner.stop(success: true, finalMessage: 'Android App Links enabled and assets generated.');
    logger.info('Check "deeplink_setup/assetlinks.json" for host-side verification setup.');
  } catch (e) {
    spinner.stop(success: false, finalMessage: 'Failed to enable App Links.');
    logger.error('Failed to enable App Links: ${e.toString()}');
  }
}