# Native integration (PlatformUtils, JNI, crossfly-lib)

> How neutral Java code reaches the OS — the single PlatformUtils point and the fallback pattern.

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

# Native integration 🤖🍎🖥️

How the **neutral** Java code (in `core`) reaches OS features that vary by platform.

## `PlatformUtils` — the single abstraction point
`PlatformUtils.instance` is the platform façade. **Each launcher installs its implementation**
(the web installs `PlatformUtilsWeb`). Key methods:
```java
IWebView wv = PlatformUtils.instance.createWebView();   // null where there is no webview (web)
PlatformUtils.instance.view(url);                        // opens external URL
PlatformUtils.instance.dial(numero);                     // dials
```

## The `crossfly-lib` native library
Loaded at startup by `SharedLibraryLoader.load("crossfly-lib")` inside `Main.create()` —
**on all targets, except WebGL**:
```java
if (Gdx.app.getType() != Application.ApplicationType.WebGL)
   new SharedLibraryLoader().load("crossfly-lib");
```
For this reason, everything that depends on it (e.g., `NativeImage` via JNI) **does not exist on the web** — there the
pure Java implementation (`JavaImageOps`) or the *stub* applies.

## The "native feature with fallback" pattern
Always **check** before using a feature that may not exist:
```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: opens externally
}
```
The same applies to `null` returns from camera/map and to `Device.platform`:
```java
if (Device.platform.isDesktop()) { /* desktop path */ }
```

## Writing your own native implementation
Concrete services (webview, GPS, etc.) live **outside `core`**, in each launcher. For a new
feature, define the interface in `core` and implement it per launcher, installing it in `PlatformUtils`/a
service field at startup. The image abstraction follows this model: `ImageOps` → `JavaImageOps` (JVM) vs
`NativeImage` (JNI).

## Best practices
- **Never** assume a device feature exists — check `!= null`/`Device.platform`.
- Place OS-specific code **in the launcher**, not in `core`.

## Common mistakes
- Calling a native feature without a fallback (breaks on the web).
- Expecting `crossfly-lib`/JNI on the web (it is not loaded on WebGL).

## See also
- [Web (TeaVM)](/docs/platforms/web-teavm) · [WebContainer](/docs/ui/widgets/webcontainer)
