diff --git a/starter/dart_runner.js b/starter/dart_runner.js index f940e020f..f238f281d 100644 --- a/starter/dart_runner.js +++ b/starter/dart_runner.js @@ -8,32 +8,32 @@ const modules = [ { name: 'camera', path: 'scripts/modules/enable_camera.dart', - parameters: ['camera_description', 'platform'] + parameters: ['camera_description'] }, { name: 'files', path: 'scripts/modules/enable_files.dart', - parameters: ['photo_library_description', 'music_description', 'platform'] + parameters: ['photo_library_description', 'music_description'] }, { name: 'contacts', path: 'scripts/modules/enable_contacts.dart', - parameters: ['contacts_description', 'platform'] + parameters: ['contacts_description'] }, { name: 'connect', path: 'scripts/modules/enable_connect.dart', - parameters: [], + parameters: ['camera_description'], }, { name: 'location', path: 'scripts/modules/enable_location.dart', - parameters: [] + parameters: ['in_use_location_description', 'always_use_location_description', 'google_maps', 'google_maps_api_key'] }, { name: 'deeplink', path: 'scripts/modules/enable_deeplink.dart', - parameters: [] + parameters: ['branch_live_key', 'branch_test_key', 'use_test_key'] }, { name: 'firebaseAnalytics', diff --git a/starter/scripts/modules/enable_connect.dart b/starter/scripts/modules/enable_connect.dart index 1582641f5..8e4013410 100644 --- a/starter/scripts/modules/enable_connect.dart +++ b/starter/scripts/modules/enable_connect.dart @@ -28,6 +28,13 @@ ensemble_connect: } ]; + final iOSPermissions = [ + { + 'key': 'camera_description', + 'value': 'NSCameraUsageDescription', + } + ]; + try { // Update the ensemble_modules.dart file updateEnsembleModules( @@ -39,6 +46,20 @@ ensemble_connect: // Update the pubspec.yaml file updatePubspec(pubspecFilePath, pubspecDependencies); + // Add the camera usage description to the iOS Info.plist file + if (platforms.contains('ios')) { + updateIOSPermissions(iosInfoPlistFilePath, iOSPermissions, arguments); + } + + // Add the ', + ); + } + print( 'Connect module enabled successfully for ${platforms.join(', ')}! 🎉'); exit(0); diff --git a/starter/scripts/modules/enable_location.dart b/starter/scripts/modules/enable_location.dart index 550cf1582..61cc9dca8 100644 --- a/starter/scripts/modules/enable_location.dart +++ b/starter/scripts/modules/enable_location.dart @@ -1,9 +1,12 @@ import 'dart:io'; - import '../utils.dart'; void main(List arguments) { List platforms = getPlatforms(arguments); + bool? hasGoogleMaps = + getArgumentValue(arguments, 'google_maps')?.toLowerCase() == 'true'; + String? googleMapsApiKey = getArgumentValue(arguments, 'google_maps_api_key', + required: hasGoogleMaps); final statements = { 'moduleStatements': [ @@ -28,6 +31,21 @@ ensemble_location: } ]; + final androidPermissions = [ + '', + ]; + + final iOSPermissions = [ + { + 'key': 'in_use_location_description', + 'value': 'NSLocationWhenInUseUsageDescription', + }, + { + 'key': 'always_use_location_description', + 'value': 'NSLocationAlwaysUsageDescription', + } + ]; + try { // Update the ensemble_modules.dart file updateEnsembleModules( @@ -39,6 +57,30 @@ ensemble_location: // Update the pubspec.yaml file updatePubspec(pubspecFilePath, pubspecDependencies); + // Add the location permissions to AndroidManifest.xml + if (platforms.contains('android')) { + updateAndroidPermissions(androidManifestFilePath, androidPermissions); + } + + // Add the location usage description to the iOS Info.plist file + if (platforms.contains('ios')) { + updateIOSPermissions(iosInfoPlistFilePath, iOSPermissions, arguments); + } + + // Update Google Maps API key if available + if (hasGoogleMaps == true && googleMapsApiKey != null) { + updatePropertiesFile( + ensemblePropertiesFilePath, 'googleMapsAPIKey', googleMapsApiKey); + if (platforms.contains('ios')) { + updateAppDelegateForGoogleMaps(appDelegatePath, googleMapsApiKey); + } + + if (platforms.contains('web')) { + updateHtmlFile(webIndexFilePath, '', + ''); + } + } + print( 'Location module enabled successfully for ${platforms.join(', ')}! 🎉'); exit(0); diff --git a/starter/scripts/utils.dart b/starter/scripts/utils.dart index 7663a7bb3..a34e19fbb 100644 --- a/starter/scripts/utils.dart +++ b/starter/scripts/utils.dart @@ -5,6 +5,9 @@ const String pubspecFilePath = 'pubspec.yaml'; const String androidManifestFilePath = 'android/app/src/main/AndroidManifest.xml'; const String iosInfoPlistFilePath = 'ios/Runner/Info.plist'; +const String webIndexFilePath = 'web/index.html'; +const String ensemblePropertiesFilePath = 'ensemble/ensemble.properties'; +const String appDelegatePath = 'ios/Runner/AppDelegate.swift'; // To read file content String readFileContent(String filePath) { @@ -16,13 +19,19 @@ String readFileContent(String filePath) { } // Helper function to parse individual arguments in key=value format -String? getArgumentValue(List arguments, String key) { +String? getArgumentValue(List arguments, String key, + {bool required = false}) { for (var arg in arguments) { final parts = arg.split('='); if (parts.length == 2 && parts[0] == key) { return parts[1]; } } + + if (required) { + throw Exception('Missing required argument: $key'); + } + return null; } @@ -188,11 +197,17 @@ void updatePubspec( // Update AndroidManifest.xml with permissions and throw error if not updated void updateAndroidPermissions( String manifestFilePath, List permissions) { + String manifestContent = readFileContent(manifestFilePath); + for (var permission in permissions) { - addPermissionToAndroidManifest( - manifestFilePath, - '', - permission); + // Check if the permission already exists in the manifest + if (!manifestContent.contains(permission)) { + // Add the permission if it doesn't exist + addPermissionToAndroidManifest( + manifestFilePath, + '', + permission); + } } } @@ -225,3 +240,65 @@ void updateIOSPermissions(String plistFilePath, } } } + +// To update an HTML file with a new content before a specific marker (like ) +void updateHtmlFile(String filePath, String marker, String contentToAdd) { + // Check if the HTML file exists + if (!File(filePath).existsSync()) { + throw Exception('Error: $filePath not found'); + } + + String content = File(filePath).readAsStringSync(); + + if (!content.contains(contentToAdd)) { + // Insert the new content before the marker (e.g., ) + content = content.replaceFirst(marker, ' $contentToAdd\n$marker'); + File(filePath).writeAsStringSync(content); + } +} + +void updatePropertiesFile(String filePath, String key, String value) { + File propertiesFile = File(filePath); + if (!propertiesFile.existsSync()) { + throw Exception('Error: $filePath not found.'); + } + + List lines = propertiesFile.readAsLinesSync(); + bool updated = false; + + for (int i = 0; i < lines.length; i++) { + if (lines[i].startsWith('$key=')) { + lines[i] = '$key=$value'; + updated = true; + break; + } + } + + if (!updated) { + lines.add('$key=$value'); + } + + propertiesFile.writeAsStringSync(lines.join('\n').trim()); +} + +void updateAppDelegateForGoogleMaps(String filePath, String googleMapsApiKey) { + File appDelegateFile = File(filePath); + if (!appDelegateFile.existsSync()) { + throw Exception('Error: $filePath not found.'); + } + + // Read the file content + String content = appDelegateFile.readAsStringSync(); + + // Uncomment the Google Maps import and API key lines if they are commented + content = content.replaceAllMapped( + RegExp(r'\/\/\s*import\s+GoogleMaps'), (match) => 'import GoogleMaps'); + + content = content.replaceAllMapped( + RegExp(r'\/\/\s*GMSServices\.provideAPIKey\("(.*?)"\)'), + (match) => ' GMSServices.provideAPIKey("$googleMapsApiKey")'); + + // Write the updated content back to the file + appDelegateFile.writeAsStringSync(content.trim()); + print('AppDelegate.swift updated successfully with Google Maps API key.'); +}