# Integración nativa (PlatformUtils, JNI, crossfly-lib)

> Cómo el código Java neutro alcanza el SO — el punto único PlatformUtils y el patrón de fallback.

Source: https://crossfly.dev/es/docs/platforms/native-integration — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Integración nativa 🤖🍎🖥️

Cómo el código Java **neutro** (en `core`) alcanza recursos del SO que varían por plataforma.

## `PlatformUtils` — el punto único de abstracción
`PlatformUtils.instance` es la fachada de plataforma. **Cada launcher instala su implementación**
(el web instala `PlatformUtilsWeb`). Métodos clave:
```java
IWebView wv = PlatformUtils.instance.createWebView();   // null donde no hay webview (web)
PlatformUtils.instance.view(url);                        // abre URL externa
PlatformUtils.instance.dial(numero);                     // marca
```

## La biblioteca nativa `crossfly-lib`
Cargada en el arranque por `SharedLibraryLoader.load("crossfly-lib")` dentro de `Main.create()` —
**en todos los destinos, excepto WebGL**:
```java
if (Gdx.app.getType() != Application.ApplicationType.WebGL)
   new SharedLibraryLoader().load("crossfly-lib");
```
Por eso, todo lo que depende de ella (ej.: `NativeImage` vía JNI) **no existe en la web** — allí vale la
implementación Java pura (`JavaImageOps`) o el *stub*.

## El patrón "recurso nativo con fallback"
Siempre **comprueba** antes de usar un recurso que puede no existir:
```java
if (PlatformUtils.instance.createWebView() != null) {
   WebContainer c = new WebContainer();     // Android/iOS/Desktop
   painel.add(LAY_FILL, c);
   c.show(url);
} else {
   PlatformUtils.instance.view(url);        // Web: abre externamente
}
```
Lo mismo vale para los retornos `null` de cámara/mapa y para `Device.platform`:
```java
if (Device.platform.isDesktop()) { /* ruta desktop */ }
```

## Escribir una implementación nativa propia
Los servicios concretos (webview, GPS, etc.) viven **fuera de `core`**, en cada launcher. Para un recurso
nuevo, define la interfaz en `core` e impleméntala por launcher, instalándola en `PlatformUtils`/campo
de servicio en el arranque. La abstracción de imagen sigue este modelo: `ImageOps` → `JavaImageOps` (JVM) vs
`NativeImage` (JNI).

## Buenas prácticas
- **Nunca** asumas que un recurso de dispositivo existe — comprueba `!= null`/`Device.platform`.
- Coloca el código específico del SO **en el launcher**, no en `core`.

## Errores comunes
- Llamar a un recurso nativo sin fallback (se rompe en la web).
- Esperar `crossfly-lib`/JNI en la web (no se carga en WebGL).

## Ver también
- [Web (TeaVM)](/docs/platforms/web-teavm) · [WebContainer](/docs/ui/widgets/webcontainer)
