El ecosistema de Apple está en plena transformación. Para un iOS Developer en la actualidad, el dominio de la sintaxis de Swift ya no es suficiente; la integración de la Inteligencia Artificial Generativa se ha convertido en el nuevo estándar de oro.
Google ha lanzado Gemini, su modelo más capaz y flexible hasta la fecha. Aunque muchos interactúan con él a través de la web, la verdadera potencia para un desarrollador reside en su API y en la capacidad de automatizar tareas.
En este tutorial, no solo aprenderemos a integrar Gemini en una app; vamos a ir un paso más allá. Aprenderemos a crear nuestra propia Gemini CLI (Command Line Interface) utilizando programación Swift puro en Xcode, y luego portaremos esa lógica para crear aplicaciones multiplataforma en SwiftUI para iOS, macOS y watchOS.
Prepárate para transformar tu flujo de trabajo en Xcode.
Parte 1: Entendiendo la Arquitectura Gemini en el Ecosistema Apple
Antes de escribir una sola línea de código, es vital entender qué estamos construyendo. No vamos a usar una herramienta cerrada; vamos a usar el SDK oficial de Google Generative AI para Swift.
El flujo de trabajo que implementaremos tiene dos vertientes:
- Herramienta de Línea de Comandos (CLI): Un ejecutable de macOS escrito en Swift que nos permitirá consultar a Gemini directamente desde nuestra terminal. Ideal para scripts, automatización o generación rápida de código.
- Aplicación SwiftUI Multiplataforma: Una interfaz gráfica que consume la misma lógica para funcionar en iPhone, Mac y Apple Watch.
Requisitos Previos
- Xcode 15+: Necesario para soportar las últimas características de concurrencia de Swift.
- Swift 5.9+: Para el uso de macros y
async/awaitavanzado. - API Key de Google AI: Debes generarla en Google AI Studio.
Parte 2: Construyendo tu propia “Gemini CLI” con Swift
Como iOS Developer, a menudo olvidamos que Swift es un lenguaje de propósito general excelente para scripts y herramientas de sistema. Vamos a crear una herramienta llamada gemini-swift.
Paso 1: Configuración del Proyecto en Xcode
- Abre Xcode.
- Selecciona Create New Project.
- Ve a la pestaña macOS y selecciona Command Line Tool.
- Nombra el proyecto
GeminiCLI. - Asegúrate de que el lenguaje sea Swift.
Paso 2: Importando el SDK
Para interactuar con el modelo, usaremos el Swift Package Manager (SPM).
- Ve a la configuración del proyecto (el icono azul en la raíz).
- Selecciona la pestaña “Package Dependencies”.
- Añade el paquete:
https://github.com/google/google-generative-ai-sdk-swift. - Añádelo a tu target
GeminiCLI.
Paso 3: ArgumentParser (Opcional pero recomendado)
Para que nuestra CLI sea profesional, necesitamos procesar argumentos (como -m "mensaje"). Apple ofrece una librería excelente para esto. Añade también este paquete vía SPM: https://github.com/apple/swift-argument-parser.
Paso 4: El Código Fuente de la CLI
Abre el archivo main.swift. Vamos a reemplazar el código por una estructura robusta que acepte un prompt y devuelva la respuesta de la IA.
import Foundation
import ArgumentParser
import GoogleGenerativeAI
@main
struct GeminiTool: AsyncParsableCommand {
// Configuración de la herramienta
static var configuration = CommandConfiguration(
commandName: "gemini",
abstract: "Una herramienta CLI para interactuar con Google Gemini en Swift."
)
// Argumento de entrada: El prompt
@Argument(help: "El texto que quieres enviar a la IA.")
var prompt: String
// Flag opcional para ser creativo
@Flag(name: .shortAndLong, help: "Activa el modo creativo.")
var creative: Bool = false
func run() async throws {
// 1. Configuración de seguridad (NUNCA hardcodear API Keys en producción real)
// Lo ideal es leerla de una variable de entorno
guard let apiKey = ProcessInfo.processInfo.environment["GEMINI_API_KEY"] else {
print("Error: Por favor configura la variable de entorno GEMINI_API_KEY.")
return
}
// 2. Inicialización del modelo
let model = GenerativeModel(name: "gemini-pro", apiKey: apiKey)
print("🤖 Consultando a Gemini...")
do {
// 3. Generación de contenido
let response = try await model.generateContent(prompt)
if let text = response.text {
print("\n--- RESPUESTA ---\n")
print(text)
print("\n-----------------\n")
} else {
print("Gemini no devolvió texto.")
}
} catch {
print("Error: \(error.localizedDescription)")
}
}
}
Paso 5: Ejecutando tu Gemini CLI
Para probar esto, necesitas editar el esquema en Xcode para pasar argumentos o compilarlo y ejecutarlo en terminal.
- Compila con
Cmd + B. - Localiza el binario en la carpeta
DerivedData. - En tu terminal:
export GEMINI_API_KEY="tu_api_key_aqui"
./GeminiCLI "Escribe un poema sobre la programación Swift"
¡Felicidades! Acabas de crear tu propia interfaz de línea de comandos de IA usando programación Swift. Esto demuestra que Swift no es solo para apps visuales.
Parte 3: De la Terminal a la UI: Integración en SwiftUI
Ahora que dominamos la lógica base, vamos a llevar esto a una aplicación real. Un iOS Developer moderno debe saber estructurar este código para que sea reutilizable en iOS, macOS y watchOS.
Arquitectura: MVVM y Clean Architecture
No pegaremos el código en la Vista. Crearemos una capa de servicio.
1. El Servicio de IA (GeminiService.swift)
Este archivo será el corazón de nuestra lógica, agnóstico de la interfaz (UI).
import Foundation
import GoogleGenerativeAI
enum GeminiError: Error {
case noAPIKey
case networkError(String)
}
actor GeminiService {
private var model: GenerativeModel?
init() {
// En una app real, usa un archivo .plist seguro o Keychain
if let path = Bundle.main.path(forResource: "GenerativeAI-Info", ofType: "plist"),
let plist = NSDictionary(contentsOfFile: path),
let key = plist["API_KEY"] as? String {
self.model = GenerativeModel(name: "gemini-pro", apiKey: key)
}
}
func sendMessage(_ text: String) async throws -> String {
guard let model = model else { throw GeminiError.noAPIKey }
do {
let response = try await model.generateContent(text)
return response.text ?? "Sin respuesta"
} catch {
throw GeminiError.networkError(error.localizedDescription)
}
}
// Función para Streaming (Efecto máquina de escribir)
func sendMessageStream(_ text: String) -> AsyncThrowingStream<String, Error> {
return AsyncThrowingStream { continuation in
guard let model = model else {
continuation.finish(throwing: GeminiError.noAPIKey)
return
}
Task {
do {
for try await chunk in model.generateContentStream(text) {
if let text = chunk.text {
continuation.yield(text)
}
}
continuation.finish()
} catch {
continuation.finish(throwing: error)
}
}
}
}
}
2. El ViewModel (ChatViewModel.swift)
El ViewModel conecta nuestro servicio con SwiftUI. Usaremos el framework @Observable (disponible desde iOS 17) para una sintaxis más limpia, o ObservableObject para compatibilidad anterior.
import SwiftUI
@MainActor
class ChatViewModel: ObservableObject {
@Published var responseText: String = ""
@Published var isLoading: Bool = false
@Published var userInput: String = ""
private let service = GeminiService()
func sendQuery() {
guard !userInput.isEmpty else { return }
isLoading = true
responseText = "" // Limpiar respuesta anterior
let query = userInput
userInput = "" // Limpiar input
Task {
do {
// Usamos streaming para mejor UX
let stream = await service.sendMessageStream(query)
for try await chunk in stream {
responseText += chunk
}
} catch {
responseText = "Error: \(error.localizedDescription)"
}
isLoading = false
}
}
}
Parte 4: Interfaz de Usuario Multiplataforma en SwiftUI
La ventaja de SwiftUI y Xcode es que podemos diseñar una vista que funcione en iPhone, Mac y Apple Watch con cambios mínimos.
Vista Principal (ContentView.swift)
import SwiftUI
struct ContentView: View {
@StateObject private var viewModel = ChatViewModel()
@FocusState private var isInputFocused: Bool
var body: some View {
NavigationStack {
VStack(spacing: 20) {
// Área de Resultados
ScrollView {
VStack(alignment: .leading) {
if viewModel.responseText.isEmpty && !viewModel.isLoading {
ContentUnavailableView(
"Pregunta a Gemini",
systemImage: "sparkles",
description: Text("Escribe algo para comenzar la magia.")
)
.opacity(0.7)
} else {
Text(viewModel.responseText)
.font(.body)
.padding()
.textSelection(.enabled) // Importante para macOS
}
}
.frame(maxWidth: .infinity, alignment: .leading)
}
.background(Color.gray.opacity(0.1))
.cornerRadius(12)
// Área de Input
HStack {
TextField("Escribe tu prompt...", text: $viewModel.userInput)
.textFieldStyle(.roundedBorder)
.focused($isInputFocused)
.disabled(viewModel.isLoading)
.onSubmit {
viewModel.sendQuery()
}
if viewModel.isLoading {
ProgressView()
.scaleEffect(0.8)
} else {
Button(action: {
viewModel.sendQuery()
}) {
Image(systemName: "arrow.up.circle.fill")
.font(.title2)
}
.disabled(viewModel.userInput.isEmpty)
}
}
.padding()
}
.padding()
.navigationTitle("Gemini Swift")
#if os(macOS)
.frame(minWidth: 400, minHeight: 500)
#endif
}
}
}
Adaptación para watchOS
Para el Apple Watch, el espacio es crítico. En Xcode, dentro de tu target de Watch App, puedes reutilizar el ChatViewModel pero simplificar la vista.
// WatchContentView.swift
import SwiftUI
struct WatchContentView: View {
@StateObject private var viewModel = ChatViewModel()
var body: some View {
VStack {
ScrollView {
Text(viewModel.responseText)
}
// Usar TextField en watchOS activa dictado o teclado QWERTY automáticamente
TextField("Preguntar...", text: $viewModel.userInput)
.onSubmit {
viewModel.sendQuery()
}
}
}
}
Parte 5: Avanzado – Multimodalidad e Imágenes
Un verdadero experto en Gemini CLI en Xcode sabe que Gemini no es solo texto. Es multimodal. Podemos enviarle imágenes.
Para esto, necesitamos actualizar nuestro servicio para usar gemini-pro-vision (o las versiones más recientes como gemini-1.5-flash).
// Actualización en GeminiService.swift
func analyzeImage(_ image: UIImage, prompt: String) async throws -> String {
// Configurar modelo de visión
let visionModel = GenerativeModel(name: "gemini-1.5-flash", apiKey: "API_KEY")
// Convertir UIImage a formato compatible
// Nota: En macOS sería NSImage
let response = try await visionModel.generateContent(prompt, image)
return response.text ?? ""
}
En la UI, simplemente añadiríamos un PhotosPicker (disponible en SwiftUI) para seleccionar la imagen y pasarla a esta función.
Conclusión: El Futuro del Desarrollo en Swift
Hemos recorrido un camino largo. Empezamos en la terminal, creando una herramienta de línea de comandos (Gemini CLI) usando programación Swift puro, demostrando la versatilidad del lenguaje. Luego, tomamos ese núcleo lógico y lo envolvimos en una arquitectura MVVM moderna con SwiftUI y Xcode, desplegando en iOS, macOS y watchOS.
Para un iOS Developer, integrar IA no es el futuro, es el presente. Herramientas como Gemini nos permiten crear aplicaciones que entienden, ven y generan contenido, elevando la experiencia de usuario a niveles imposibles de alcanzar con la programación tradicional.
¿Qué sigue?
- Implementa el historial de chat para que Gemini recuerde el contexto.
- Usa
SwiftDatapara guardar las conversaciones localmente. - Experimenta con “Function Calling” de Gemini para que la IA pueda ejecutar código real dentro de tu app (como encender la linterna o poner una alarma).
Si tienes cualquier duda sobre este artículo, contacta conmigo y estaré encantado de ayudarte . Puedes contactar conmigo en mi perfil de X o en mi perfil de Instagram










