run method
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);
logger.println('=== Initializing Deep Link Configuration ===\n');
// 1. Gather inputs
final defaultScheme = PathUtils.basename(projectRoot).replaceAll(RegExp(r'[^a-zA-Z0-9]'), '').toLowerCase();
final scheme = Console.ask('Enter Custom URL Scheme (e.g. myapp)', defaultValue: defaultScheme).toLowerCase();
final genRoutes = Console.askYesNo('Generate sample routes?', defaultValue: true);
final genManager = Console.askYesNo('Generate DeepLinkManager?', defaultValue: true);
final appLinks = Console.askYesNo('Enable Android App Links?', defaultValue: false);
final universalLinks = Console.askYesNo('Enable iOS Universal Links?', defaultValue: false);
final domains = <String>[];
if (appLinks || universalLinks) {
final domainsInput = Console.ask('Enter domain names for App/Universal links (comma-separated, e.g. example.com)');
domains.addAll(
domainsInput
.split(',')
.map((d) => d.trim().replaceAll(RegExp(r'^https?://'), ''))
.where((d) => d.isNotEmpty),
);
}
final spinner = Spinner('Configuring files...');
spinner.start();
try {
// 2. Load Config Manager and Backup Manager
final configManager = ConfigManager(projectRoot);
final backupManager = BackupManager(projectRoot);
// Create new configuration
final config = DeepLinkConfig(
schemes: [scheme],
generateSampleRoutes: genRoutes,
generateDeepLinkManager: genManager,
androidAppLinks: appLinks,
iosUniversalLinks: universalLinks,
domains: domains,
);
// 3. Android Changes
// Manifest
if (FileUtils.exists(project.androidManifestPath)) {
backupManager.backupFile(project.androidManifestPath);
var manifestContent = FileUtils.readAsString(project.androidManifestPath);
final manifestEditor = AndroidManifestEditor();
manifestContent = manifestEditor.addScheme(manifestContent, scheme);
if (appLinks && domains.isNotEmpty) {
manifestContent = manifestEditor.enableAppLinks(manifestContent, domains);
}
FileUtils.writeString(project.androidManifestPath, manifestContent);
}
// MainActivity
try {
final mainActivityInfo = project.findMainActivity();
backupManager.backupFile(mainActivityInfo.path);
var mainActivityContent = FileUtils.readAsString(mainActivityInfo.path);
final isKotlin = mainActivityInfo.language == MainActivityLanguage.kotlin;
mainActivityContent = MainActivityEditor().inject(mainActivityContent, isKotlin);
FileUtils.writeString(mainActivityInfo.path, mainActivityContent);
} catch (e) {
logger.warning('MainActivity adjustment skipped: ${e.toString()}');
}
// 4. iOS Changes
// Info.plist
if (FileUtils.exists(project.iosPlistPath)) {
backupManager.backupFile(project.iosPlistPath);
var plistContent = FileUtils.readAsString(project.iosPlistPath);
plistContent = PlistEditor().addScheme(plistContent, scheme);
FileUtils.writeString(project.iosPlistPath, plistContent);
}
// AppDelegate.swift
if (FileUtils.exists(project.iosAppDelegatePath)) {
backupManager.backupFile(project.iosAppDelegatePath);
var appDelegateContent = FileUtils.readAsString(project.iosAppDelegatePath);
appDelegateContent = AppDelegateEditor().inject(appDelegateContent);
FileUtils.writeString(project.iosAppDelegatePath, appDelegateContent);
}
// 5. Generate Flutter code
final generator = FlutterGenerator(projectRoot, logger);
generator.generate(config);
// 6. Generate Associated Domain Assets & Documentation if required
if (appLinks || universalLinks) {
final setupDir = PathUtils.join(projectRoot, 'deeplink_setup');
FileUtils.createDirectory(setupDir);
final templateEngine = TemplateEngine();
final packageName = project.getAndroidPackageName();
// Write assetlinks.json
if (appLinks) {
final renderedAssetLinks = templateEngine.render(
TemplatesBundle.assetLinksJson,
{
'PACKAGE_NAME': packageName,
'SHA256_FINGERPRINT': 'YOUR_SHA256_FINGERPRINT_HERE',
},
);
FileUtils.writeString(PathUtils.join(setupDir, 'assetlinks.json'), renderedAssetLinks);
}
// Write apple-app-site-association
if (universalLinks) {
final renderedAasa = templateEngine.render(
TemplatesBundle.appleAppSiteAssociation,
{
'TEAM_ID': 'YOUR_APPLE_TEAM_ID',
'BUNDLE_ID': 'YOUR_APPLE_BUNDLE_ID',
},
);
FileUtils.writeString(PathUtils.join(setupDir, 'apple-app-site-association'), renderedAasa);
}
// Write instructions
final renderedInstructions = templateEngine.render(
TemplatesBundle.setupInstructions,
{
'SCHEME': scheme,
'DOMAINS': domains.join(', '),
'PACKAGE_NAME': packageName,
'DOMAIN_1': domains.isNotEmpty ? domains[0] : 'your-domain.com',
'DOMAIN_2': domains.length > 1 ? domains[1] : 'your-second-domain.com',
},
);
FileUtils.writeString(PathUtils.join(setupDir, 'README.md'), renderedInstructions);
}
// Save Config
configManager.save(config);
spinner.stop(success: true, finalMessage: 'Deep Link Integration initialized successfully.');
if (appLinks || universalLinks) {
logger.info('Action Required: Setup files and verification guides generated under "deeplink_setup/".');
}
} catch (e) {
spinner.stop(success: false, finalMessage: 'Initialization failed.');
throw DeepLinkException('Init command failed to complete successfully', e);
}
}