← Volver al listado de tecnologías
Configuración del Entorno para iOS y Android
Configuración del Entorno para iOS y Android
El desarrollo móvil con Defold requiere configuraciones específicas para cada plataforma. Esta guía te llevará paso a paso por la configuración completa del entorno para iOS y Android.
Prerrequisitos Generales
Herramientas Básicas
# Verificar instalación de Defold
defold --version
# Verificar Java Development Kit (Android)
java -version
javac -version
# Verificar Android SDK
adb version
Estructura del Proyecto Móvil
proyecto_movil/
├── game.project
├── main/
│ ├── main.collection
│ └── main.script
├── assets/
│ ├── textures/
│ │ ├── ui_atlas.atlas
│ │ └── game_atlas.atlas
│ └── sounds/
├── gui/
│ ├── main_menu.gui
│ └── game_hud.gui
├── extensions/
│ ├── ads/
│ ├── iap/
│ └── analytics/
└── bundles/
├── ios/
└── android/
Configuración para Android
1. Instalación de Android SDK
Descarga e Instalación
# Descargar Android Command Line Tools
wget https://dl.google.com/android/repository/commandlinetools-linux-latest.zip
# Extraer en directorio específico
mkdir -p ~/Android/Sdk/cmdline-tools
unzip commandlinetools-linux-latest.zip -d ~/Android/Sdk/cmdline-tools
mv ~/Android/Sdk/cmdline-tools/cmdline-tools ~/Android/Sdk/cmdline-tools/latest
# Configurar variables de entorno
export ANDROID_HOME=~/Android/Sdk
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin
export PATH=$PATH:$ANDROID_HOME/platform-tools
Instalación de Componentes
# Actualizar SDK Manager
sdkmanager --update
# Instalar plataformas Android
sdkmanager "platforms;android-34"
sdkmanager "platforms;android-33"
sdkmanager "platforms;android-32"
# Instalar build tools
sdkmanager "build-tools;34.0.0"
sdkmanager "build-tools;33.0.1"
# Instalar herramientas adicionales
sdkmanager "platform-tools"
sdkmanager "emulator"
# Verificar instalación
sdkmanager --list
2. Configuración del Proyecto Android
game.project - Configuración Android
[project]
title = Mi Juego Móvil
version = 1.0
dependencies =
[bootstrap]
main_collection = /main/main.collectionc
[render]
default_render = /builtins/render/default.renderc
[android]
version_code = 1
minimum_sdk_version = 21
target_sdk_version = 34
package = com.miestudio.mijuego
gcm_sender_id =
manifest = /bundles/android/AndroidManifest.xml
iap_provider = GooglePlay
input_method = HiddenInputField
immersive_mode = false
debuggable = false
[display]
width = 1080
height = 1920
high_dpi = true
[physics]
type = 2D
gravity_y = -1000
debug = false
debug_alpha = 0.9
world_count = 4
gravity_x = 0
gravity_z = 0
scale = 0.02
allow_dynamic_transforms = true
debug_scale = 30
max_collisions = 64
max_contacts = 128
contact_impulse_limit = 0
ray_cast_limit = 64
trigger_overlap_limit = 16
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="{{android.package}}"
android:versionCode="{{android.version_code}}"
android:versionName="{{project.version}}"
android:installLocation="auto">
<!-- Permisos básicos -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<!-- Permisos para almacenamiento -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- Configuración de hardware -->
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
<uses-feature android:name="android.hardware.gamepad" android:required="false" />
<!-- Soporte para pantallas -->
<supports-screens
android:xlargeScreens="true"
android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true"
android:anyDensity="true" />
<application
android:label="{{project.title}}"
android:hasCode="true"
android:debuggable="{{android.debuggable}}"
android:icon="@mipmap/icon"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
<activity
android:name="com.dynamo.android.DefoldActivity"
android:label="{{project.title}}"
android:configChanges="orientation|keyboardHidden|screenSize"
android:exported="true"
android:screenOrientation="portrait"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- AdMob App ID -->
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy"/>
</application>
</manifest>
3. Script de Configuración Android
-- android_config.script
function init(self)
-- Configurar orientación
if defold then
msg.post(".", "set_update_frequency", { frequency = 60 })
end
-- Configurar controles táctiles
self.touch_enabled = true
-- Configurar sistema de archivos
self.save_path = sys.get_save_file("main", "save_data")
print("Android configuration initialized")
end
function on_message(self, message_id, message, sender)
if message_id == hash("window_callback") then
if message.event == window.WINDOW_EVENT_FOCUS_LOST then
-- Pausar el juego
msg.post("main:/controller", "pause_game")
elseif message.event == window.WINDOW_EVENT_FOCUS_GAINED then
-- Reanudar el juego
msg.post("main:/controller", "resume_game")
end
end
end
function on_input(self, action_id, action)
if action_id == hash("touch") then
if action.pressed then
-- Manejar inicio de toque
local touch_pos = vmath.vector3(action.x, action.y, 0)
msg.post("main:/controller", "touch_start", { position = touch_pos })
elseif action.released then
-- Manejar fin de toque
msg.post("main:/controller", "touch_end")
end
end
end
Configuración para iOS
1. Configuración del Entorno iOS
Xcode y Herramientas de Desarrollo
# Verificar instalación de Xcode
xcode-select --print-path
# Instalar herramientas de línea de comandos
xcode-select --install
# Verificar simuladores disponibles
xcrun simctl list devices
2. Configuración del Proyecto iOS
game.project - Configuración iOS
[ios]
app_icon_120x120 = /bundles/ios/AppIcon120x120.png
app_icon_180x180 = /bundles/ios/AppIcon180x180.png
app_icon_76x76 = /bundles/ios/AppIcon76x76.png
app_icon_152x152 = /bundles/ios/AppIcon152x152.png
app_icon_57x57 = /bundles/ios/AppIcon57x57.png
app_icon_114x114 = /bundles/ios/AppIcon114x114.png
app_icon_72x72 = /bundles/ios/AppIcon72x72.png
app_icon_144x144 = /bundles/ios/AppIcon144x144.png
launch_screen = /bundles/ios/LaunchScreen.storyboard
pre_renderered_icons = false
bundle_identifier = com.miestudio.mijuego
bundle_version = 1
infoplist = /bundles/ios/Info.plist
default_language = en
localizations = en,es
Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>{{project.title}}</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>{{ios.bundle_identifier}}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>{{project.version}}</string>
<key>CFBundleVersion</key>
<string>{{ios.bundle_version}}</string>
<!-- Orientaciones soportadas -->
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<!-- Configuración de pantalla -->
<key>UIRequiresFullScreen</key>
<true/>
<key>UIStatusBarHidden</key>
<true/>
<!-- Game Center -->
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>gamekit</string>
</array>
<!-- AdMob App ID -->
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy</string>
<!-- App Transport Security -->
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
</dict>
</plist>
3. LaunchScreen.storyboard
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="LaunchIcon" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
<rect key="frame" x="146.66666666666666" y="376" width="100" height="100"/>
<constraints>
<constraint firstAttribute="width" constant="100" id="5cQ-KE-LBc"/>
<constraint firstAttribute="height" constant="100" id="LfW-cd-eeE"/>
</constraints>
</imageView>
</subviews>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" levelPriority="1000" id="5cH-0I-8fX"/>
<constraint firstItem="YRO-k0-Ey4" centerY="6Tk-OE-BBY" id="Kzf-to-9mD"/>
<constraint firstItem="YRO-k0-Ey4" centerX="6Tk-OE-BBY" id="xeU-3F-WtF"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchIcon" width="100" height="100"/>
</resources>
</document>
Configuración Universal (iOS y Android)
1. Script de Detección de Plataforma
-- platform_detector.lua
local M = {}
function M.get_platform()
local sys_info = sys.get_sys_info()
return sys_info.system_name
end
function M.is_mobile()
local platform = M.get_platform()
return platform == "iPhone OS" or platform == "Android"
end
function M.is_ios()
return M.get_platform() == "iPhone OS"
end
function M.is_android()
return M.get_platform() == "Android"
end
function M.get_device_info()
local sys_info = sys.get_sys_info()
return {
platform = sys_info.system_name,
version = sys_info.system_version,
language = sys_info.language,
device_model = sys_info.device_model,
manufacturer = sys_info.manufacturer
}
end
return M
2. Configuración de Input Universal
-- mobile_input.script
local platform = require "main.platform_detector"
function init(self)
-- Configurar input según la plataforma
if platform.is_mobile() then
msg.post(".", "acquire_input_focus")
-- Configurar multitouch
self.touches = {}
self.max_touches = 10
-- Configurar gestos
self.gesture_threshold = 100
self.swipe_threshold = 50
print("Mobile input initialized for: " .. platform.get_platform())
end
end
function on_input(self, action_id, action)
if not platform.is_mobile() then
return false
end
if action_id == hash("touch") then
local touch_id = action.id or 1
if action.pressed then
-- Nuevo toque
self.touches[touch_id] = {
start_pos = vmath.vector3(action.x, action.y, 0),
current_pos = vmath.vector3(action.x, action.y, 0),
start_time = socket.gettime()
}
msg.post("main:/controller", "touch_pressed", {
touch_id = touch_id,
position = self.touches[touch_id].start_pos
})
elseif action.released then
-- Fin del toque
if self.touches[touch_id] then
local touch_data = self.touches[touch_id]
local duration = socket.gettime() - touch_data.start_time
local distance = vmath.length(action.x - touch_data.start_pos.x, action.y - touch_data.start_pos.y)
-- Detectar tipo de gesto
if duration < 0.3 and distance < 30 then
-- Tap
msg.post("main:/controller", "tap", {
position = touch_data.start_pos
})
elseif distance > self.swipe_threshold then
-- Swipe
local direction = vmath.normalize(vmath.vector3(
action.x - touch_data.start_pos.x,
action.y - touch_data.start_pos.y,
0
))
msg.post("main:/controller", "swipe", {
direction = direction,
distance = distance
})
end
msg.post("main:/controller", "touch_released", {
touch_id = touch_id
})
self.touches[touch_id] = nil
end
else
-- Movimiento del toque
if self.touches[touch_id] then
self.touches[touch_id].current_pos = vmath.vector3(action.x, action.y, 0)
msg.post("main:/controller", "touch_moved", {
touch_id = touch_id,
position = self.touches[touch_id].current_pos
})
end
end
return true
end
return false
end
Build y Testing
1. Script de Build Automatizado
#!/bin/bash
# build_mobile.sh
PROJECT_PATH="."
BUILD_SERVER="https://build.defold.com"
echo "Building for mobile platforms..."
# Build para Android
echo "Building Android APK..."
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"platform": "android",
"architectures": ["armv7-android", "arm64-android"]
}' \
"$BUILD_SERVER/build" > android_build.json
# Build para iOS
echo "Building iOS..."
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"platform": "ios",
"architectures": ["arm64-ios", "x86_64-ios"]
}' \
"$BUILD_SERVER/build" > ios_build.json
echo "Mobile builds completed!"
2. Testing en Dispositivos
-- test_mobile.script
local platform = require "main.platform_detector"
function init(self)
if platform.is_mobile() then
-- Test de rendimiento
self.fps_counter = 0
self.fps_timer = 0
-- Test de memoria
self.memory_check_timer = 0
-- Test de input
self.touch_test_active = false
print("Mobile testing initialized")
end
end
function update(self, dt)
if not platform.is_mobile() then
return
end
-- Monitorear FPS
self.fps_counter = self.fps_counter + 1
self.fps_timer = self.fps_timer + dt
if self.fps_timer >= 1.0 then
local fps = self.fps_counter / self.fps_timer
print("FPS: " .. math.floor(fps))
if fps < 30 then
print("WARNING: Low FPS detected!")
end
self.fps_counter = 0
self.fps_timer = 0
end
-- Monitorear memoria cada 5 segundos
self.memory_check_timer = self.memory_check_timer + dt
if self.memory_check_timer >= 5.0 then
local mem_info = profiler.get_memory_usage()
print("Memory usage: " .. mem_info.total .. " bytes")
self.memory_check_timer = 0
end
end
Troubleshooting Común
Problemas de Android
- Error de SDK: Verificar variables de entorno ANDROID_HOME
- Certificados: Generar keystore para release builds
- Permisos: Verificar AndroidManifest.xml
Problemas de iOS
- Provisioning Profile: Configurar certificados de desarrollo
- Code Signing: Verificar identidad de firma
- Simulador: Usar simuladores de iOS para testing
Problemas Generales
- Rendimiento: Optimizar assets y texturas
- Compatibilidad: Probar en múltiples dispositivos
- Memoria: Monitorear uso de memoria constantemente
Este setup te proporciona una base sólida para el desarrollo móvil multiplataforma con Defold Engine.