$MobileDir = "D:\07-Logiciels\20-FIN65\fin65_mobile" $AndroidMain = Join-Path $MobileDir "android\app\src\main" $Manifest = Join-Path $AndroidMain "AndroidManifest.xml" $GradleKts = Join-Path $MobileDir "android\app\build.gradle.kts" $GradleGroovy = Join-Path $MobileDir "android\app\build.gradle" Write-Host "" Write-Host "==========================================" Write-Host " FIN65 - Repair MainActivity Java" Write-Host "==========================================" Write-Host "" if (!(Test-Path $MobileDir)) { Write-Host "[ERREUR] Dossier mobile introuvable : $MobileDir" -ForegroundColor Red Read-Host "Appuie sur Entree pour fermer" exit 1 } if (!(Test-Path $Manifest)) { Write-Host "[ERREUR] AndroidManifest.xml introuvable : $Manifest" -ForegroundColor Red Read-Host "Appuie sur Entree pour fermer" exit 1 } $Stamp = Get-Date -Format "yyyyMMdd_HHmmss" function Backup-File($Path) { if (Test-Path $Path) { Copy-Item $Path "$Path.before_java_mainactivity_$Stamp.bak" -Force Write-Host "Sauvegarde : $Path.before_java_mainactivity_$Stamp.bak" } } Backup-File $Manifest if (Test-Path $GradleKts) { Backup-File $GradleKts } if (Test-Path $GradleGroovy) { Backup-File $GradleGroovy } # 1) Package/applicationId exact. $PackageName = "com.example.fin65_mobile" if (Test-Path $GradleKts) { $g = Get-Content $GradleKts -Raw $mApp = [regex]::Match($g, 'applicationId\s*=\s*"([^"]+)"') $mNs = [regex]::Match($g, 'namespace\s*=\s*"([^"]+)"') if ($mNs.Success) { $PackageName = $mNs.Groups[1].Value } if ($mApp.Success) { $PackageName = $mApp.Groups[1].Value } } elseif (Test-Path $GradleGroovy) { $g = Get-Content $GradleGroovy -Raw $mApp = [regex]::Match($g, 'applicationId\s+["'']([^"'']+)["'']') $mNs = [regex]::Match($g, 'namespace\s+["'']([^"'']+)["'']') if ($mNs.Success) { $PackageName = $mNs.Groups[1].Value } if ($mApp.Success) { $PackageName = $mApp.Groups[1].Value } } Write-Host "Package Android retenu : $PackageName" # 2) Désactiver toutes les anciennes MainActivity pour éviter les doublons. Write-Host "" Write-Host "Desactivation des anciennes MainActivity..." $oldMainActivities = @() $kotlinRoot = Join-Path $AndroidMain "kotlin" $javaRoot = Join-Path $AndroidMain "java" if (Test-Path $kotlinRoot) { $oldMainActivities += Get-ChildItem $kotlinRoot -Recurse -Filter MainActivity.kt -ErrorAction SilentlyContinue } if (Test-Path $javaRoot) { $oldMainActivities += Get-ChildItem $javaRoot -Recurse -Filter MainActivity.java -ErrorAction SilentlyContinue } foreach ($file in $oldMainActivities) { $disabled = "$($file.FullName).disabled_$Stamp" Move-Item $file.FullName $disabled -Force Write-Host "Desactive : $($file.FullName)" } # 3) Créer une MainActivity Java. Java est compilé par Android sans dépendre du plugin Kotlin. $PackagePath = $PackageName.Replace(".", "\") $JavaDir = Join-Path $AndroidMain "java\$PackagePath" $MainActivityJava = Join-Path $JavaDir "MainActivity.java" if (!(Test-Path $JavaDir)) { New-Item -ItemType Directory -Force -Path $JavaDir | Out-Null } $MainActivityText = @" package $PackageName; import io.flutter.embedding.android.FlutterFragmentActivity; public class MainActivity extends FlutterFragmentActivity { } "@ Set-Content -Path $MainActivityJava -Value $MainActivityText -Encoding UTF8 Write-Host "" Write-Host "MainActivity Java creee :" Write-Host $MainActivityJava # 4) Patch AndroidManifest propre via XML. [xml]$xml = Get-Content $Manifest $androidNs = "http://schemas.android.com/apk/res/android" $manifestNode = $xml.manifest function Ensure-Permission($name) { $existing = $manifestNode.'uses-permission' | Where-Object { $_.GetAttribute("name", $androidNs) -eq $name } if ($null -eq $existing) { $perm = $xml.CreateElement("uses-permission") $attr = $xml.CreateAttribute("android", "name", $androidNs) $attr.Value = $name [void]$perm.Attributes.Append($attr) [void]$manifestNode.InsertBefore($perm, $manifestNode.FirstChild) Write-Host "Permission ajoutee : $name" } else { Write-Host "Permission deja presente : $name" } } Ensure-Permission "android.permission.INTERNET" Ensure-Permission "android.permission.USE_BIOMETRIC" $app = $manifestNode.application if ($null -eq $app) { Write-Host "[ERREUR] Balise introuvable." -ForegroundColor Red Read-Host "Appuie sur Entree pour fermer" exit 1 } $app.SetAttribute("label", $androidNs, "FIN65") $app.SetAttribute("icon", $androidNs, "@mipmap/ic_launcher") $app.SetAttribute("roundIcon", $androidNs, "@mipmap/ic_launcher_round") $app.SetAttribute("usesCleartextTraffic", $androidNs, "true") # Chercher l'activité launcher. $activities = @($app.activity) $launcherActivity = $null foreach ($a in $activities) { if ($null -eq $a) { continue } $hasLauncher = $false foreach ($f in @($a.'intent-filter')) { if ($null -eq $f) { continue } foreach ($cat in @($f.category)) { if ($cat.GetAttribute("name", $androidNs) -eq "android.intent.category.LAUNCHER") { $hasLauncher = $true } } } if ($hasLauncher) { $launcherActivity = $a break } } if ($null -eq $launcherActivity) { if ($activities.Count -gt 0 -and $null -ne $activities[0]) { $launcherActivity = $activities[0] } else { $launcherActivity = $xml.CreateElement("activity") [void]$app.PrependChild($launcherActivity) } } $launcherActivity.SetAttribute("name", $androidNs, "$PackageName.MainActivity") $launcherActivity.SetAttribute("exported", $androidNs, "true") $launcherActivity.SetAttribute("launchMode", $androidNs, "singleTop") $launcherActivity.SetAttribute("taskAffinity", $androidNs, "") $launcherActivity.SetAttribute("theme", $androidNs, "@style/LaunchTheme") $launcherActivity.SetAttribute("configChanges", $androidNs, "orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode") $launcherActivity.SetAttribute("hardwareAccelerated", $androidNs, "true") $launcherActivity.SetAttribute("windowSoftInputMode", $androidNs, "adjustResize") # S'assurer du meta-data NormalTheme. $hasNormalTheme = $false foreach ($md in @($launcherActivity.'meta-data')) { if ($null -ne $md -and $md.GetAttribute("name", $androidNs) -eq "io.flutter.embedding.android.NormalTheme") { $hasNormalTheme = $true } } if (!$hasNormalTheme) { $meta = $xml.CreateElement("meta-data") $meta.SetAttribute("name", $androidNs, "io.flutter.embedding.android.NormalTheme") $meta.SetAttribute("resource", $androidNs, "@style/NormalTheme") [void]$launcherActivity.PrependChild($meta) } # S'assurer du launcher intent-filter. $hasLauncherFilter = $false foreach ($f in @($launcherActivity.'intent-filter')) { if ($null -eq $f) { continue } foreach ($cat in @($f.category)) { if ($cat.GetAttribute("name", $androidNs) -eq "android.intent.category.LAUNCHER") { $hasLauncherFilter = $true } } } if (!$hasLauncherFilter) { $filter = $xml.CreateElement("intent-filter") $action = $xml.CreateElement("action") $action.SetAttribute("name", $androidNs, "android.intent.action.MAIN") [void]$filter.AppendChild($action) $category = $xml.CreateElement("category") $category.SetAttribute("name", $androidNs, "android.intent.category.LAUNCHER") [void]$filter.AppendChild($category) [void]$launcherActivity.AppendChild($filter) } # S'assurer du flutterEmbedding. $hasFlutterEmbedding = $false foreach ($md in @($app.'meta-data')) { if ($null -ne $md -and $md.GetAttribute("name", $androidNs) -eq "flutterEmbedding") { $hasFlutterEmbedding = $true } } if (!$hasFlutterEmbedding) { $md = $xml.CreateElement("meta-data") $md.SetAttribute("name", $androidNs, "flutterEmbedding") $md.SetAttribute("value", $androidNs, "2") [void]$app.AppendChild($md) } $xml.Save($Manifest) Write-Host "" Write-Host "AndroidManifest.xml mis a jour." # 5) Gradle : nettoyer bloc Kotlin erroné et garder minSdk 24. if (Test-Path $GradleKts) { $text = Get-Content $GradleKts -Raw $text = [regex]::Replace($text, '(?ms)^\s*kotlin\s*\{\s*compilerOptions\s*\{.*?\}\s*\}\s*$', '') $text = [regex]::Replace($text, 'minSdk\s*=\s*flutter\.minSdkVersion', 'minSdk = 24') $text = [regex]::Replace($text, 'minSdk\s*=\s*\d+', 'minSdk = 24') Set-Content -Path $GradleKts -Value $text -Encoding UTF8 Write-Host "build.gradle.kts verifie." } if (Test-Path $GradleGroovy) { $text = Get-Content $GradleGroovy -Raw $text = [regex]::Replace($text, '(?ms)^\s*kotlin\s*\{\s*compilerOptions\s*\{.*?\}\s*\}\s*$', '') $text = [regex]::Replace($text, 'minSdkVersion\s+flutter\.minSdkVersion', 'minSdkVersion 24') $text = [regex]::Replace($text, 'minSdkVersion\s+\d+', 'minSdkVersion 24') Set-Content -Path $GradleGroovy -Value $text -Encoding UTF8 Write-Host "build.gradle verifie." } Write-Host "" Write-Host "Verification des fichiers MainActivity restants :" Get-ChildItem $AndroidMain -Recurse -Include MainActivity.kt,MainActivity.java -ErrorAction SilentlyContinue | ForEach-Object { Write-Host " - $($_.FullName)" } Set-Location $MobileDir Write-Host "" Write-Host "Nettoyage Flutter..." flutter clean flutter pub get Write-Host "" Write-Host "Reparation MainActivity Java terminee." Write-Host "Relance maintenant :" Write-Host "flutter run" Write-Host "" Read-Host "Appuie sur Entree pour fermer"