Added React Native project structure with Android configuration, Tauri desktop app support, and build artifacts. Includes development tools, test configuration, and platform-specific resources. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
694 lines
27 KiB
Python
694 lines
27 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
Android Development Environment Setup Script for Windows
|
|
MyMemoApp - Full Android Development Environment Setup
|
|
Date: 2025-09-14
|
|
Run with Administrator privileges
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import subprocess
|
|
import shutil
|
|
import zipfile
|
|
import urllib.request
|
|
import winreg
|
|
import ctypes
|
|
from pathlib import Path
|
|
import json
|
|
import time
|
|
|
|
# Configuration
|
|
JAVA_VERSION = "17"
|
|
GRADLE_VERSION = "9.0.0"
|
|
ANDROID_SDK_VERSION = "13114758"
|
|
ANDROID_API_LEVEL = "34"
|
|
BUILD_TOOLS_VERSION = "34.0.0"
|
|
NDK_VERSIONS = ["25.1.8937393", "27.1.12297006"]
|
|
CMAKE_VERSIONS = ["3.22.1", "3.18.1"]
|
|
|
|
# Paths
|
|
JAVA_INSTALL_PATH = r"C:\Program Files\Java"
|
|
GRADLE_INSTALL_PATH = r"C:\Gradle"
|
|
ANDROID_SDK_PATH = r"C:\Android\sdk"
|
|
TEMP_DIR = Path(os.environ['TEMP']) / "android-setup"
|
|
|
|
# URLs
|
|
JAVA_17_URL = "https://aka.ms/download-jdk/microsoft-jdk-17.0.12-windows-x64.msi"
|
|
JAVA_21_URL = "https://aka.ms/download-jdk/microsoft-jdk-21.0.4-windows-x64.msi"
|
|
GRADLE_URL = f"https://services.gradle.org/distributions/gradle-{GRADLE_VERSION}-bin.zip"
|
|
ANDROID_SDK_URL = f"https://dl.google.com/android/repository/commandlinetools-win-{ANDROID_SDK_VERSION}_latest.zip"
|
|
|
|
class AndroidSetup:
|
|
def __init__(self):
|
|
self.errors = []
|
|
self.warnings = []
|
|
|
|
def print_header(self, text):
|
|
"""Print section header"""
|
|
print("\n" + "="*60)
|
|
print(f" {text}")
|
|
print("="*60)
|
|
|
|
def print_step(self, step_num, text):
|
|
"""Print step information"""
|
|
print(f"\n[Step {step_num}] {text}")
|
|
print("-" * 50)
|
|
|
|
def is_admin(self):
|
|
"""Check if running with administrator privileges"""
|
|
try:
|
|
return ctypes.windll.shell32.IsUserAnAdmin()
|
|
except:
|
|
return False
|
|
|
|
def run_command(self, cmd, shell=True, capture_output=True):
|
|
"""Run a command and return result"""
|
|
try:
|
|
# On Windows, use shell=True for better command resolution
|
|
if isinstance(cmd, list):
|
|
cmd = ' '.join(cmd)
|
|
result = subprocess.run(cmd, shell=shell, capture_output=capture_output, text=True)
|
|
return result.returncode == 0, result.stdout, result.stderr
|
|
except Exception as e:
|
|
return False, "", str(e)
|
|
|
|
def download_file(self, url, destination, description=""):
|
|
"""Download file with progress indicator"""
|
|
print(f"Downloading {description}...")
|
|
print(f"URL: {url}")
|
|
|
|
try:
|
|
def download_progress(block_num, block_size, total_size):
|
|
downloaded = block_num * block_size
|
|
percent = min(downloaded * 100 / total_size, 100)
|
|
progress_bar = '#' * int(percent // 2)
|
|
sys.stdout.write(f'\r[{progress_bar:<50}] {percent:.1f}%')
|
|
sys.stdout.flush()
|
|
|
|
urllib.request.urlretrieve(url, destination, reporthook=download_progress)
|
|
print() # New line after progress bar
|
|
return True
|
|
except Exception as e:
|
|
print(f"\nDownload failed: {e}")
|
|
return False
|
|
|
|
def extract_zip(self, zip_path, extract_to):
|
|
"""Extract zip file"""
|
|
print(f"Extracting {zip_path.name}...")
|
|
try:
|
|
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
|
zip_ref.extractall(extract_to)
|
|
return True
|
|
except Exception as e:
|
|
print(f"Extraction failed: {e}")
|
|
return False
|
|
|
|
def set_environment_variable(self, name, value, user=False):
|
|
"""Set Windows environment variable permanently"""
|
|
try:
|
|
# First, update current session
|
|
os.environ[name] = value
|
|
print(f" Updated {name} in current session")
|
|
|
|
success = False
|
|
|
|
# Method 1: Direct registry modification
|
|
try:
|
|
if user:
|
|
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER,
|
|
r"Environment",
|
|
0, winreg.KEY_ALL_ACCESS)
|
|
else:
|
|
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,
|
|
r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment",
|
|
0, winreg.KEY_ALL_ACCESS)
|
|
|
|
winreg.SetValueEx(key, name, 0, winreg.REG_EXPAND_SZ, value)
|
|
winreg.CloseKey(key)
|
|
print(f" ✓ Persisted {name} to system registry")
|
|
success = True
|
|
|
|
# Notify system of environment change (optional)
|
|
try:
|
|
import win32gui, win32con
|
|
win32gui.SendMessage(win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 'Environment')
|
|
except ImportError:
|
|
# pywin32 not installed, skip notification
|
|
pass
|
|
except Exception as e:
|
|
print(f" Warning: Registry method failed: {e}")
|
|
|
|
# Method 2: Use setx as backup
|
|
if not success:
|
|
try:
|
|
# Use setx to set system environment variable
|
|
cmd = f'setx {name} "{value}" /M'
|
|
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
|
if result.returncode == 0:
|
|
print(f" ✓ Set {name} using setx")
|
|
success = True
|
|
else:
|
|
print(f" Warning: setx failed: {result.stderr}")
|
|
except Exception as e:
|
|
print(f" Warning: setx method failed: {e}")
|
|
|
|
if not success:
|
|
print(f" ⚠ {name} will only work for current session")
|
|
print(f" Please set manually: {name}={value}")
|
|
|
|
return True
|
|
except Exception as e:
|
|
print(f" Error: Failed to set {name}: {e}")
|
|
return False
|
|
|
|
def add_to_path(self, new_path, user=False):
|
|
"""Add directory to PATH environment variable permanently"""
|
|
try:
|
|
# First, update current session
|
|
if new_path not in os.environ['PATH']:
|
|
os.environ['PATH'] = f"{os.environ['PATH']};{new_path}"
|
|
print(f" Added to current session PATH: {new_path}")
|
|
else:
|
|
print(f" Already in current session PATH: {new_path}")
|
|
|
|
# Persist to system PATH using both registry and setx
|
|
success = False
|
|
|
|
# Method 1: Direct registry modification
|
|
try:
|
|
if user:
|
|
key_path = r"Environment"
|
|
root_key = winreg.HKEY_CURRENT_USER
|
|
else:
|
|
key_path = r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
|
|
root_key = winreg.HKEY_LOCAL_MACHINE
|
|
|
|
key = winreg.OpenKey(root_key, key_path, 0, winreg.KEY_ALL_ACCESS)
|
|
|
|
try:
|
|
current_path, reg_type = winreg.QueryValueEx(key, "Path")
|
|
except:
|
|
current_path = ""
|
|
reg_type = winreg.REG_EXPAND_SZ
|
|
|
|
if new_path not in current_path:
|
|
# Clean up the path (remove duplicates and empty entries)
|
|
path_parts = [p.strip() for p in current_path.split(';') if p.strip()]
|
|
if new_path not in path_parts:
|
|
path_parts.append(new_path)
|
|
new_path_value = ';'.join(path_parts)
|
|
|
|
winreg.SetValueEx(key, "Path", 0, reg_type, new_path_value)
|
|
print(f" ✓ Persisted to system registry PATH")
|
|
success = True
|
|
else:
|
|
print(f" Already in system registry PATH")
|
|
success = True
|
|
|
|
winreg.CloseKey(key)
|
|
except Exception as e:
|
|
print(f" Warning: Registry method failed: {e}")
|
|
|
|
# Method 2: Use setx as backup (this has 1024 char limit but works well)
|
|
if not success:
|
|
try:
|
|
# Use setx to set system PATH
|
|
cmd = f'setx PATH "%PATH%;{new_path}" /M'
|
|
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
|
if result.returncode == 0:
|
|
print(f" ✓ Updated system PATH using setx")
|
|
success = True
|
|
else:
|
|
print(f" Warning: setx failed: {result.stderr}")
|
|
except Exception as e:
|
|
print(f" Warning: setx method failed: {e}")
|
|
|
|
if not success:
|
|
print(f" ⚠ PATH update will only work for current session")
|
|
print(f" Please add manually to system PATH: {new_path}")
|
|
|
|
return True
|
|
except Exception as e:
|
|
print(f" Error: Failed to update PATH: {e}")
|
|
return False
|
|
|
|
def check_nodejs(self):
|
|
"""Check Node.js installation"""
|
|
self.print_step(1, "Checking Node.js and npm")
|
|
|
|
# Check Node.js
|
|
success, stdout, _ = self.run_command("node --version")
|
|
if success:
|
|
print(f"✓ Node.js installed: {stdout.strip()}")
|
|
else:
|
|
print("✗ Node.js not installed")
|
|
print("Please download and install from: https://nodejs.org/")
|
|
return False
|
|
|
|
# Check npm - try different approaches
|
|
npm_found = False
|
|
npm_version = ""
|
|
|
|
# Try 1: Direct npm command
|
|
success, stdout, _ = self.run_command("npm --version")
|
|
if success:
|
|
npm_found = True
|
|
npm_version = stdout.strip()
|
|
else:
|
|
# Try 2: Use cmd /c for Windows
|
|
success, stdout, _ = self.run_command("cmd /c npm --version")
|
|
if success:
|
|
npm_found = True
|
|
npm_version = stdout.strip()
|
|
else:
|
|
# Try 3: Use full path if Node.js is in Program Files
|
|
node_path = shutil.which('node')
|
|
if node_path:
|
|
npm_path = Path(node_path).parent / "npm.cmd"
|
|
if npm_path.exists():
|
|
success, stdout, _ = self.run_command(f'"{npm_path}" --version')
|
|
if success:
|
|
npm_found = True
|
|
npm_version = stdout.strip()
|
|
|
|
if npm_found:
|
|
print(f"✓ npm installed: {npm_version}")
|
|
return True
|
|
else:
|
|
print("✗ npm not found")
|
|
print("Note: npm should be installed with Node.js")
|
|
print("Try running 'npm --version' manually to verify")
|
|
response = input("\nContinue anyway? (y/n): ")
|
|
return response.lower() == 'y'
|
|
|
|
def check_java(self):
|
|
"""Check and install Java if needed"""
|
|
self.print_step(2, "Checking Java")
|
|
|
|
success, stdout, _ = self.run_command("java --version")
|
|
if success:
|
|
print(f"✓ Java installed:\n{stdout}")
|
|
|
|
# Set JAVA_HOME if not set
|
|
if not os.environ.get('JAVA_HOME'):
|
|
# Try to find Java installation
|
|
java_path = shutil.which('java')
|
|
if java_path:
|
|
java_home = Path(java_path).parent.parent
|
|
self.set_environment_variable('JAVA_HOME', str(java_home))
|
|
print(f"✓ JAVA_HOME set to: {java_home}")
|
|
else:
|
|
print(f"✓ JAVA_HOME: {os.environ['JAVA_HOME']}")
|
|
return True
|
|
|
|
print("Java not found. Installing...")
|
|
|
|
# Create temp directory
|
|
TEMP_DIR.mkdir(exist_ok=True)
|
|
os.chdir(TEMP_DIR)
|
|
|
|
# Download Java
|
|
java_msi = TEMP_DIR / "openjdk-17.msi"
|
|
if not java_msi.exists():
|
|
if not self.download_file(JAVA_17_URL, java_msi, "OpenJDK 17"):
|
|
# Try Java 21 as fallback
|
|
java_msi = TEMP_DIR / "openjdk-21.msi"
|
|
if not self.download_file(JAVA_21_URL, java_msi, "OpenJDK 21"):
|
|
self.errors.append("Failed to download Java")
|
|
return False
|
|
|
|
# Install Java
|
|
print("Installing Java... (Please complete the installation wizard)")
|
|
subprocess.run(f'msiexec /i "{java_msi}"', shell=True)
|
|
|
|
print("\n⚠ Please complete Java installation manually, then press Enter to continue...")
|
|
input()
|
|
|
|
# Verify installation
|
|
success, stdout, _ = self.run_command("java --version")
|
|
if success:
|
|
print(f"✓ Java installed successfully")
|
|
return True
|
|
else:
|
|
self.warnings.append("Java installation may require system restart")
|
|
return False
|
|
|
|
def install_gradle(self):
|
|
"""Install Gradle"""
|
|
self.print_step(3, "Installing Gradle")
|
|
|
|
# Check if already installed
|
|
gradle_exe = Path(GRADLE_INSTALL_PATH) / f"gradle-{GRADLE_VERSION}" / "bin" / "gradle.bat"
|
|
if gradle_exe.exists():
|
|
print(f"✓ Gradle already installed at: {gradle_exe.parent.parent}")
|
|
self.add_to_path(str(gradle_exe.parent))
|
|
return True
|
|
|
|
success, stdout, _ = self.run_command("gradle --version")
|
|
if success:
|
|
print(f"✓ Gradle found in PATH")
|
|
return True
|
|
|
|
print("Installing Gradle...")
|
|
|
|
# Create temp directory
|
|
TEMP_DIR.mkdir(exist_ok=True)
|
|
os.chdir(TEMP_DIR)
|
|
|
|
# Download Gradle
|
|
gradle_zip = TEMP_DIR / f"gradle-{GRADLE_VERSION}-bin.zip"
|
|
if not gradle_zip.exists():
|
|
if not self.download_file(GRADLE_URL, gradle_zip, f"Gradle {GRADLE_VERSION}"):
|
|
self.errors.append("Failed to download Gradle")
|
|
return False
|
|
|
|
# Extract Gradle
|
|
if not self.extract_zip(gradle_zip, TEMP_DIR):
|
|
self.errors.append("Failed to extract Gradle")
|
|
return False
|
|
|
|
# Move to installation directory
|
|
gradle_src = TEMP_DIR / f"gradle-{GRADLE_VERSION}"
|
|
gradle_dst = Path(GRADLE_INSTALL_PATH) / f"gradle-{GRADLE_VERSION}"
|
|
|
|
print(f"Installing Gradle to {gradle_dst}...")
|
|
gradle_dst.parent.mkdir(exist_ok=True)
|
|
|
|
if gradle_dst.exists():
|
|
shutil.rmtree(gradle_dst)
|
|
shutil.move(str(gradle_src), str(gradle_dst))
|
|
|
|
# Add to PATH
|
|
gradle_bin = gradle_dst / "bin"
|
|
self.add_to_path(str(gradle_bin))
|
|
|
|
print(f"✓ Gradle {GRADLE_VERSION} installed successfully")
|
|
return True
|
|
|
|
def install_android_sdk(self):
|
|
"""Install Android SDK"""
|
|
self.print_step(4, "Installing Android SDK")
|
|
|
|
# Check if already installed
|
|
sdkmanager = Path(ANDROID_SDK_PATH) / "cmdline-tools" / "latest" / "bin" / "sdkmanager.bat"
|
|
if sdkmanager.exists():
|
|
print(f"✓ Android SDK already installed at: {ANDROID_SDK_PATH}")
|
|
else:
|
|
print("Installing Android SDK Command Line Tools...")
|
|
|
|
# Create temp directory
|
|
TEMP_DIR.mkdir(exist_ok=True)
|
|
os.chdir(TEMP_DIR)
|
|
|
|
# Download Android SDK
|
|
sdk_zip = TEMP_DIR / f"commandlinetools-win-{ANDROID_SDK_VERSION}_latest.zip"
|
|
if not sdk_zip.exists():
|
|
if not self.download_file(ANDROID_SDK_URL, sdk_zip, "Android SDK Command Line Tools"):
|
|
self.errors.append("Failed to download Android SDK")
|
|
return False
|
|
else:
|
|
print(f"Using existing SDK zip: {sdk_zip}")
|
|
|
|
# Extract SDK
|
|
if not self.extract_zip(sdk_zip, TEMP_DIR):
|
|
self.errors.append("Failed to extract Android SDK")
|
|
return False
|
|
|
|
# Setup SDK directory structure
|
|
print("Setting up SDK directory structure...")
|
|
sdk_path = Path(ANDROID_SDK_PATH)
|
|
sdk_path.mkdir(parents=True, exist_ok=True)
|
|
|
|
cmdline_tools = sdk_path / "cmdline-tools" / "latest"
|
|
cmdline_tools.parent.mkdir(exist_ok=True)
|
|
|
|
# Move cmdline-tools
|
|
print("Moving cmdline-tools to SDK directory...")
|
|
src_tools = TEMP_DIR / "cmdline-tools"
|
|
if cmdline_tools.exists():
|
|
print(f"Removing existing cmdline-tools at {cmdline_tools}")
|
|
shutil.rmtree(cmdline_tools)
|
|
shutil.move(str(src_tools), str(cmdline_tools))
|
|
|
|
print(f"✓ Android SDK installed to: {ANDROID_SDK_PATH}")
|
|
|
|
# Set environment variables
|
|
print("Setting environment variables...")
|
|
|
|
print(" Setting ANDROID_HOME...")
|
|
if not self.set_environment_variable('ANDROID_HOME', ANDROID_SDK_PATH):
|
|
self.warnings.append("Failed to set ANDROID_HOME")
|
|
|
|
print(" Adding cmdline-tools to PATH...")
|
|
if not self.add_to_path(str(Path(ANDROID_SDK_PATH) / "cmdline-tools" / "latest" / "bin")):
|
|
self.warnings.append("Failed to add cmdline-tools to PATH")
|
|
|
|
print(" Adding platform-tools to PATH...")
|
|
if not self.add_to_path(str(Path(ANDROID_SDK_PATH) / "platform-tools")):
|
|
self.warnings.append("Failed to add platform-tools to PATH")
|
|
|
|
print("✓ Environment variables configured")
|
|
return True
|
|
|
|
def install_sdk_components(self):
|
|
"""Install Android SDK components"""
|
|
self.print_step(5, "Installing Android SDK Components")
|
|
|
|
sdkmanager = Path(ANDROID_SDK_PATH) / "cmdline-tools" / "latest" / "bin" / "sdkmanager.bat"
|
|
|
|
if not sdkmanager.exists():
|
|
print("✗ sdkmanager not found")
|
|
return False
|
|
|
|
# Accept licenses
|
|
print("Accepting Android SDK licenses...")
|
|
license_cmd = f'echo y | "{sdkmanager}" --licenses'
|
|
subprocess.run(license_cmd, shell=True, capture_output=True)
|
|
|
|
# Install platform-tools first (contains adb)
|
|
print("Installing platform-tools (contains adb)...")
|
|
cmd = f'"{sdkmanager}" "platform-tools"'
|
|
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
|
if result.returncode == 0:
|
|
print("✓ platform-tools installed")
|
|
|
|
# Add adb to PATH immediately after platform-tools installation
|
|
platform_tools_path = Path(ANDROID_SDK_PATH) / "platform-tools"
|
|
if platform_tools_path.exists():
|
|
print("Adding adb (platform-tools) to PATH...")
|
|
self.add_to_path(str(platform_tools_path))
|
|
|
|
# Verify adb is accessible
|
|
adb_path = platform_tools_path / "adb.exe"
|
|
if adb_path.exists():
|
|
print(f"✓ adb found at: {adb_path}")
|
|
else:
|
|
print("⚠ adb.exe not found in platform-tools")
|
|
else:
|
|
print(f"⚠ Failed to install platform-tools: {result.stderr}")
|
|
|
|
# Install other components
|
|
components = [
|
|
f"platforms;android-{ANDROID_API_LEVEL}",
|
|
f"platforms;android-35",
|
|
f"platforms;android-33",
|
|
f"build-tools;{BUILD_TOOLS_VERSION}",
|
|
f"build-tools;35.0.0"
|
|
]
|
|
|
|
for component in components:
|
|
print(f"Installing {component}...")
|
|
cmd = f'"{sdkmanager}" "{component}"'
|
|
subprocess.run(cmd, shell=True, capture_output=True)
|
|
|
|
# Install NDK
|
|
for ndk_version in NDK_VERSIONS:
|
|
print(f"Installing NDK {ndk_version}...")
|
|
cmd = f'"{sdkmanager}" "ndk;{ndk_version}"'
|
|
subprocess.run(cmd, shell=True, capture_output=True)
|
|
|
|
# Install CMake
|
|
for cmake_version in CMAKE_VERSIONS:
|
|
print(f"Installing CMake {cmake_version}...")
|
|
cmd = f'"{sdkmanager}" "cmake;{cmake_version}"'
|
|
subprocess.run(cmd, shell=True, capture_output=True)
|
|
|
|
print("✓ Android SDK components installed")
|
|
return True
|
|
|
|
def create_local_properties(self):
|
|
"""Create local.properties files"""
|
|
self.print_step(6, "Creating local.properties files")
|
|
|
|
ndk_path = Path(ANDROID_SDK_PATH) / "ndk" / NDK_VERSIONS[-1]
|
|
|
|
# Create for platforms/android
|
|
android_dir = Path.cwd() / "platforms" / "android"
|
|
if android_dir.exists():
|
|
local_props = android_dir / "local.properties"
|
|
content = f"""# Android SDK path
|
|
sdk.dir={ANDROID_SDK_PATH.replace(chr(92), '/')}
|
|
|
|
# NDK path
|
|
ndk.dir={str(ndk_path).replace(chr(92), '/')}
|
|
"""
|
|
local_props.write_text(content)
|
|
print(f"✓ Created: {local_props}")
|
|
|
|
# Create for TestApp/android if exists
|
|
testapp_dir = Path.cwd() / "TestApp" / "android"
|
|
if testapp_dir.exists():
|
|
local_props = testapp_dir / "local.properties"
|
|
local_props.write_text(content)
|
|
print(f"✓ Created: {local_props}")
|
|
|
|
return True
|
|
|
|
def create_gradle_properties(self):
|
|
"""Create gradle.properties file"""
|
|
self.print_step(7, "Creating gradle.properties")
|
|
|
|
android_dir = Path.cwd() / "platforms" / "android"
|
|
if android_dir.exists():
|
|
gradle_props = android_dir / "gradle.properties"
|
|
content = """# Gradle settings
|
|
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
|
org.gradle.parallel=true
|
|
org.gradle.daemon=true
|
|
org.gradle.configureondemand=true
|
|
|
|
# Android settings
|
|
android.useAndroidX=true
|
|
android.enableJetifier=true
|
|
|
|
# React Native settings
|
|
reactNativeArchitectures=armeabi-v7a,arm64-v8a
|
|
|
|
# Build optimization
|
|
org.gradle.caching=true
|
|
"""
|
|
gradle_props.write_text(content)
|
|
print(f"✓ Created: {gradle_props}")
|
|
|
|
return True
|
|
|
|
def verify_installation(self):
|
|
"""Verify all installations"""
|
|
self.print_step(8, "Verifying Installation")
|
|
|
|
checks = [
|
|
("Java", "java --version"),
|
|
("Gradle", "gradle --version"),
|
|
("ADB", "adb --version"),
|
|
]
|
|
|
|
all_good = True
|
|
for name, cmd in checks:
|
|
success, stdout, _ = self.run_command(cmd)
|
|
if success:
|
|
print(f"✓ {name}: OK")
|
|
if name == "ADB":
|
|
# Show adb version
|
|
print(f" {stdout.strip().split()[0]}")
|
|
else:
|
|
if name == "ADB":
|
|
# Try with full path
|
|
adb_path = Path(ANDROID_SDK_PATH) / "platform-tools" / "adb.exe"
|
|
if adb_path.exists():
|
|
print(f"✓ {name}: Found at {adb_path}")
|
|
print(f" (Add {adb_path.parent} to PATH manually or restart)")
|
|
self.warnings.append("adb found but not in PATH - restart required")
|
|
else:
|
|
print(f"✗ {name}: Not found")
|
|
self.warnings.append(f"{name} not installed")
|
|
all_good = False
|
|
else:
|
|
print(f"✗ {name}: Not found (may need restart)")
|
|
self.warnings.append(f"{name} verification failed - may need system restart")
|
|
all_good = False
|
|
|
|
# Also check ANDROID_HOME
|
|
android_home = os.environ.get('ANDROID_HOME')
|
|
if android_home:
|
|
print(f"✓ ANDROID_HOME: {android_home}")
|
|
else:
|
|
print("✗ ANDROID_HOME: Not set")
|
|
self.warnings.append("ANDROID_HOME not set - restart required")
|
|
|
|
return all_good
|
|
|
|
def run(self):
|
|
"""Main setup process"""
|
|
self.print_header("Android Development Environment Setup")
|
|
|
|
# Check admin privileges
|
|
if not self.is_admin():
|
|
print("\n⚠ WARNING: Not running as administrator!")
|
|
print("Some operations may fail. Run as administrator for best results.")
|
|
response = input("\nContinue anyway? (y/n): ")
|
|
if response.lower() != 'y':
|
|
return
|
|
|
|
# Check Node.js
|
|
if not self.check_nodejs():
|
|
self.errors.append("Node.js is required. Please install it first.")
|
|
return
|
|
|
|
# Check/Install Java
|
|
if not self.check_java():
|
|
self.warnings.append("Java installation incomplete")
|
|
|
|
# Install Gradle
|
|
if not self.install_gradle():
|
|
self.warnings.append("Gradle installation incomplete")
|
|
|
|
# Install Android SDK
|
|
if not self.install_android_sdk():
|
|
self.errors.append("Android SDK installation failed")
|
|
return
|
|
|
|
# Install SDK components
|
|
if not self.install_sdk_components():
|
|
self.warnings.append("Some SDK components may not be installed")
|
|
|
|
# Create configuration files
|
|
os.chdir(Path(__file__).parent) # Return to script directory
|
|
self.create_local_properties()
|
|
self.create_gradle_properties()
|
|
|
|
# Verify installation
|
|
self.verify_installation()
|
|
|
|
# Print summary
|
|
self.print_header("Setup Complete!")
|
|
|
|
if self.errors:
|
|
print("\n❌ Errors:")
|
|
for error in self.errors:
|
|
print(f" - {error}")
|
|
|
|
if self.warnings:
|
|
print("\n⚠ Warnings:")
|
|
for warning in self.warnings:
|
|
print(f" - {warning}")
|
|
|
|
print("\n✅ Next Steps:")
|
|
print("1. Restart your command prompt or system")
|
|
print("2. Run: npm install")
|
|
print("3. Run: npm run android")
|
|
print("\nFor troubleshooting, run: npx react-native doctor")
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
setup = AndroidSetup()
|
|
setup.run()
|
|
except KeyboardInterrupt:
|
|
print("\n\nSetup cancelled by user")
|
|
except Exception as e:
|
|
print(f"\n❌ Setup failed: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
|
|
input("\nPress Enter to exit...") |