Initial React Native Android project setup with multiplatform desktop support.

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>
This commit is contained in:
2025-09-14 23:24:05 +09:00
commit 463c6ebd87
392 changed files with 14831 additions and 0 deletions

694
setup_android.py Normal file
View File

@@ -0,0 +1,694 @@
#!/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...")