<# .SYNOPSIS RR3 Community Server Browser Installer .DESCRIPTION Adds a complete server browser UI to Real Racing 3 APK, allowing users to manage multiple community servers without reinstalling the APK. .PARAMETER ApkPath Path to the input RR3 APK file .PARAMETER OutputPath Path for the modified output APK (default: realracing3-community.apk) .PARAMETER AddServerBrowser Enable the server browser feature (default: $true) .PARAMETER DefaultServerUrl Optional: Pre-configure a default server URL .PARAMETER DefaultServerName Optional: Name for the default server (default: "Community Server") .EXAMPLE .\RR3-Server-Browser-Installer.ps1 -ApkPath "realracing3.apk" .EXAMPLE .\RR3-Server-Browser-Installer.ps1 -ApkPath "realracing3.apk" -DefaultServerUrl "http://localhost:5001" -DefaultServerName "My Local Server" #> param( [Parameter(Mandatory=$true)] [string]$ApkPath, [string]$OutputPath = "realracing3-community.apk", [switch]$AddServerBrowser = $true, [string]$DefaultServerUrl = "", [string]$DefaultServerName = "Community Server" ) # Color output functions function Write-Success { param($Message) Write-Host "✅ $Message" -ForegroundColor Green } function Write-Info { param($Message) Write-Host "ℹ️ $Message" -ForegroundColor Cyan } function Write-Warning { param($Message) Write-Host "⚠️ $Message" -ForegroundColor Yellow } function Write-Error-Custom { param($Message) Write-Host "❌ $Message" -ForegroundColor Red } function Write-Step { param($Message) Write-Host "`n🔧 $Message..." -ForegroundColor Yellow } # Check prerequisites Write-Step "Checking Prerequisites" if (-not (Test-Path $ApkPath)) { Write-Error-Custom "APK file not found: $ApkPath" exit 1 } # Check for apktool try { $null = & apktool --version 2>&1 Write-Success "apktool found" } catch { Write-Error-Custom "apktool not found. Install from: https://apktool.org" exit 1 } # Check for uber-apk-signer (or jarsigner) $hasSigner = $false try { $null = & uber-apk-signer --version 2>&1 $hasSigner = $true Write-Success "uber-apk-signer found" } catch { Write-Warning "uber-apk-signer not found. Will use manual signing." } # Setup workspace $workDir = "rr3-apk-workspace" Write-Step "Setting Up Workspace" if (Test-Path $workDir) { Write-Info "Cleaning existing workspace..." Remove-Item -Recurse -Force $workDir } New-Item -ItemType Directory -Path $workDir | Out-Null Write-Success "Workspace created: $workDir" # Decompile APK Write-Step "Decompiling APK" Write-Info "This may take a few minutes..." $decompileResult = & apktool d $ApkPath -o "$workDir/decompiled" -f 2>&1 if ($LASTEXITCODE -ne 0) { Write-Error-Custom "Failed to decompile APK" Write-Host $decompileResult exit 1 } Write-Success "APK decompiled successfully" # Add Server Browser if ($AddServerBrowser) { Write-Step "Installing Server Browser System" # 1. Copy HTML assets Write-Info "Copying HTML UI assets..." $assetsDir = "$workDir/decompiled/assets" New-Item -ItemType Directory -Path $assetsDir -Force | Out-Null if (-not (Test-Path "assets/community_servers_list.html")) { Write-Error-Custom "HTML assets not found. Make sure you're running from the rr3-apk directory." exit 1 } Copy-Item "assets/community_servers_list.html" "$assetsDir/" Copy-Item "assets/community_server_edit.html" "$assetsDir/" Write-Success "HTML assets installed" # 2. Create smali directory structure Write-Info "Creating smali directory structure..." $smaliDir = "$workDir/decompiled/smali/com/community" New-Item -ItemType Directory -Path $smaliDir -Force | Out-Null Write-Success "Smali directories created" # 3. Note for manual smali addition Write-Warning "MANUAL STEP REQUIRED:" Write-Info "Smali files need to be created manually or extracted from a reference APK." Write-Info "Required files in smali-patches/ directory:" Write-Info " - CommunityServerManager.smali" Write-Info " - CommunityServersActivity.smali" Write-Info " - ServerEditActivity.smali" Write-Info "" Write-Info "Copy these to: $smaliDir" if (Test-Path "smali-patches") { Write-Info "Found smali-patches directory, copying files..." Copy-Item "smali-patches\*.smali" "$smaliDir\" -ErrorAction SilentlyContinue Write-Success "Smali files copied (if available)" } # 4. Update AndroidManifest.xml Write-Info "Updating AndroidManifest.xml..." $manifestPath = "$workDir/decompiled/AndroidManifest.xml" $manifest = Get-Content $manifestPath -Raw # Check if activities already exist if ($manifest -notmatch "CommunityServersActivity") { $activities = @" "@ $manifest = $manifest -replace '()', "$activities`$1" Set-Content $manifestPath $manifest -NoNewline Write-Success "AndroidManifest.xml updated" } else { Write-Warning "Activities already registered in manifest" } # 5. Add default server if specified if ($DefaultServerUrl) { Write-Info "Adding default server configuration..." $serverJson = @" [ { "id": "default-$(New-Guid)", "name": "$DefaultServerName", "url": "$DefaultServerUrl", "addedDate": "$(Get-Date -Format 'o')", "lastUsed": null, "isFavorite": true } ] "@ $configFile = "$assetsDir/default_servers.json" Set-Content $configFile $serverJson Write-Success "Default server added: $DefaultServerName -> $DefaultServerUrl" } Write-Success "Server Browser System installed!" } # Rebuild APK Write-Step "Rebuilding APK" Write-Info "This may take a few minutes..." $buildResult = & apktool b "$workDir/decompiled" -o "$workDir/unsigned.apk" 2>&1 if ($LASTEXITCODE -ne 0) { Write-Error-Custom "Failed to rebuild APK" Write-Host $buildResult exit 1 } Write-Success "APK rebuilt successfully" # Sign APK Write-Step "Signing APK" if ($hasSigner) { Write-Info "Using uber-apk-signer..." $signResult = & uber-apk-signer -a "$workDir/unsigned.apk" -o $workDir 2>&1 if ($LASTEXITCODE -eq 0) { # Find signed APK $signedApk = Get-ChildItem "$workDir\*-aligned-signed.apk" | Select-Object -First 1 if ($signedApk) { Move-Item $signedApk.FullName $OutputPath -Force Write-Success "APK signed successfully" } else { Write-Error-Custom "Signed APK not found" exit 1 } } else { Write-Error-Custom "Failed to sign APK" Write-Host $signResult exit 1 } } else { Write-Warning "No signing tool available" Write-Info "Copying unsigned APK to: $OutputPath" Copy-Item "$workDir/unsigned.apk" $OutputPath -Force Write-Info "You'll need to sign the APK manually before installing" Write-Info "Use: jarsigner, apksigner, or uber-apk-signer" } # Cleanup Write-Step "Cleaning Up" Write-Info "Removing workspace..." Remove-Item -Recurse -Force $workDir Write-Success "Workspace cleaned" # Summary Write-Host "" Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan Write-Host " 🏁 APK MODIFICATION COMPLETE!" -ForegroundColor Green Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan Write-Host "" Write-Host "Output APK: " -NoNewline Write-Host $OutputPath -ForegroundColor Yellow Write-Host "" if ($AddServerBrowser) { Write-Host "✅ Server Browser UI installed" -ForegroundColor Green if ($DefaultServerUrl) { Write-Host "✅ Default server pre-configured: $DefaultServerUrl" -ForegroundColor Green } Write-Host "" Write-Host "To access Server Browser:" -ForegroundColor Cyan Write-Host " 1. Install the APK on your device" -ForegroundColor White Write-Host " 2. Launch game and look for 'Community Servers' option" -ForegroundColor White Write-Host " 3. Or use ADB: adb shell am start -n com.ea.games.r3_row/com.community.CommunityServersActivity" -ForegroundColor White } Write-Host "" Write-Host "Next Steps:" -ForegroundColor Cyan Write-Host " 1. Install: adb install $OutputPath" -ForegroundColor White Write-Host " 2. Launch the game" -ForegroundColor White Write-Host " 3. Access Server Browser from main menu" -ForegroundColor White Write-Host "" Write-Host "Documentation: docs/SERVER_BROWSER_GUIDE.md" -ForegroundColor Cyan Write-Host "" Write-Host "═══════════════════════════════════════════════════════════" -ForegroundColor Cyan Write-Host ""