#
.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 ""