libJGLIOS is an iOS-only support library for running Java applications through SDL3, OpenAL, ANGLE/Metal, OpenGL ES, and GraalVM Native Image.
:sdl3-ios: bindings for the SDL3:gles-ios: bindings for OpenGL ES:openal-ios: bindings for OpenAL:core-ios: bridge for lifecycle, runble and setup:libjglios-gradle-plugin:org.ngengine.libjglios, a Gradle plugin to build iOS apps
Consumer projects apply:
plugins {
id 'org.ngengine.libjglios' version '<version>'
}
dependencies {
implementation 'org.ngengine:libjglios-core-ios:<version>'
implementation 'org.ngengine:libjglios-angle-ios:<version>'
implementation 'org.ngengine:libjglios-sdl3-ios:<version>'
implementation 'org.ngengine:libjglios-gles-ios:<version>'
implementation 'org.ngengine:libjglios-openal-ios:<version>'
}
libJGLIOS {
mainClass = 'com.example.Main'
bundleId = 'com.example.game'
appName = 'ExampleGame'
// minIosVersion = '15.0'
// simulatorDevice = 'iPhone 16'
// buildType = 'release'
// orientation = 'landscape'
}mainClass, bundleId, and appName are required.
Useful app tasks:
runIosDebugApp- builds and runs the debug app on a connected iOS device, or on the simulator when no device is selected.buildIosSimulatorApp- builds a runnable simulator app.buildIosDebugApp- builds a development-signed.appfor a real iOS device.buildIosApp- builds a release-signed.ipafor App Store upload.
Device signing uses Xcode automatic signing by default. Before running on a real device, make sure your Apple ID is added in Xcode Settings > Accounts. For release IPAs, make sure that account has the Apple signing assets needed for distribution.
./gradlew runIosDebugAppIf iOS refuses to launch a newly-installed debug app, trust the developer profile on the device in Settings > General > VPN & Device Management.
Signing and device overrides:
| CLI property | Environment variable | Use |
|---|---|---|
-PiosTeamId=ABCDE12345 |
IOS_TEAM_ID |
Select the Apple Developer team when Xcode cannot choose one automatically. |
-PiosXcodeTeamId=ABCDE12345 |
IOS_XCODE_TEAM_ID |
Same as iosTeamId; kept for explicit Xcode naming. |
-PiosXcodeProvisioningAutoCreate=false |
IOS_XCODE_PROVISIONING_AUTO_CREATE |
Disable Xcode automatic signing/provisioning. |
-PiosBundleIdAutoCreate=false |
IOS_BUNDLE_ID_AUTO_CREATE |
Do not let Xcode create the configured bundle ID. |
-PiosDebugSigningIdentity=<identity-or-sha1> |
IOS_DEBUG_SIGNING_IDENTITY |
Force the debug signing certificate. |
-PiosDebugProvisioningProfile=/path/profile.mobileprovision |
IOS_DEBUG_PROVISIONING_PROFILE |
Force the debug provisioning profile. |
-PiosDebugCodesignEntitlements=/path/Entitlements.plist |
IOS_DEBUG_CODESIGN_ENTITLEMENTS |
Force debug entitlements. |
-PiosReleaseSigningIdentity=<identity-or-sha1> |
IOS_RELEASE_SIGNING_IDENTITY |
Force the release signing certificate. |
-PiosReleaseProvisioningProfile=/path/profile.mobileprovision |
IOS_RELEASE_PROVISIONING_PROFILE |
Force the release provisioning profile. |
-PiosReleaseCodesignEntitlements=/path/Entitlements.plist |
IOS_RELEASE_CODESIGN_ENTITLEMENTS |
Force release entitlements. |
-PiosAppTarget=device |
IOS_APP_TARGET |
Choose device or simulator. |
-PiosDevice=<udid-or-name> |
IOS_DEVICE |
Select a specific connected device. |
If the project has a generateNativeImageMetadata task, libJGLIOS runs it
before the iOS native-image build. This lets apps or engine plugins generate
their own META-INF/native-image reachability metadata without libJGLIOS
owning that discovery logic.
- macOS with Xcode command line tools.
- JDK 21 or newer
./gradlew clean build
./gradlew publishToMavenLocalCustom JNI or native code for the iOS backend should be built as an Apple
xcframework and carried on the app runtime classpath. libJGLIOS links those
frameworks while building the iOS app; the app should not rely on loading
native libraries at runtime.
Build the framework with Xcode, Apple command line tools, or a Gradle task. It should include:
ios-arm64for devices.ios-arm64-simulatororios-arm64_x86_64-simulatorfor simulators.
Put the framework under lib/ios in a dependency jar or in the app's own
resources:
lib/ios/MyGameNative.xcframework
lib/ios/MyGameNative.xcframework.json
The metadata file is optional. For a static JNI framework, this is the usual shape:
{
"name": "MyGameNative",
"embed": false,
"forceLoad": true
}Add systemFrameworks to that file when the native code needs extra Apple
frameworks.
For a local app project:
tasks.named('processResources') {
from('native/MyGameNative.xcframework') {
into 'lib/ios/MyGameNative.xcframework'
}
from('native/MyGameNative.xcframework.json') {
into 'lib/ios'
}
}Then build or run the app normally:
./gradlew runIosDebugApp -PiosAppTarget=simulator
./gradlew buildIosSimulatorApp
./gradlew buildIosAppDuring the app build, libJGLIOS scans the runtime classpath for
lib/ios/**/*.xcframework, selects the right device or simulator slice, links
the frameworks, adds configured Apple system frameworks, and embeds frameworks
whose metadata has embed: true. Dynamic frameworks usually need
embed: true; static frameworks usually use embed: false and
forceLoad: true.
libJGLIOS itself is licensed under the BSD-3 Clause License, however it includes the following third-party components, binaries and code with their own licenses:
- SDL3, zlib license
- ANGLE, BSD-style license
- libGDX MetalANGLEKit build scripts and patches, BSD-style license
- Godot-kotlin-jvm by utopia-rise, graalvm linking and build scripts, MIT license