Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ It includes bindings for SDL3, OpenAL, Clipboard and OpenGL ES via ANGLE on Meta
- `:angle-ios`: native build of Google ANGLE for iOS
- `:libjglios-gradle-plugin`: `org.ngengine.libjglios`, a Gradle plugin to build iOS apps

## Device classification

`LibJGLIOSDeviceBridge.isMobileDevice()` identifies phone and iPad device families
through UIKit. It returns false for other interface idioms and for iOS apps
running on Mac. The native call marshals UIKit access to the main thread, so a
caller on another thread requires the application's main run loop to be running.
This describes the device family, not whether a gamepad is connected.

Consumers need matching Java and native core artifacts containing this method.

## Usage

Consumer projects apply:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ public final class LibJGLIOSDeviceBridge {
private LibJGLIOSDeviceBridge() {
}

/** Returns true for the phone and tablet device families, not TV or Mac. */
public static native boolean isMobileDevice();

public static native boolean isRumbleSupported();

public static native void rumble(float amountHigh, float amountLow, float duration);
Expand Down
19 changes: 19 additions & 0 deletions core-ios/src/main/native/libjglios_ios_launcher_jni.mm
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,25 @@ void libjglios_show_error_alert(const char* title, const char* message) {
return JNI_TRUE;
}

extern "C" JNIEXPORT jboolean JNICALL
Java_org_ngengine_libjglios_core_LibJGLIOSDeviceBridge_isMobileDevice(JNIEnv*, jclass) {
__block bool mobile = false;
void (^classify)(void) = ^{
UIUserInterfaceIdiom idiom = UIDevice.currentDevice.userInterfaceIdiom;
mobile = idiom == UIUserInterfaceIdiomPhone || idiom == UIUserInterfaceIdiomPad;
if (@available(iOS 14.0, *)) {
// iPhone/iPad apps running on Apple Silicon Macs can retain their original idiom.
mobile = mobile && !NSProcessInfo.processInfo.iOSAppOnMac;
}
};
if ([NSThread isMainThread]) {
classify();
} else {
dispatch_sync(dispatch_get_main_queue(), classify);
}
return mobile ? JNI_TRUE : JNI_FALSE;
}

extern "C" JNIEXPORT jboolean JNICALL
Java_org_ngengine_libjglios_core_LibJGLIOSDeviceBridge_isRumbleSupported(JNIEnv*, jclass) {
return libjglios_device_rumble_supported() ? JNI_TRUE : JNI_FALSE;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.ngengine.libjglios.core;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class LibJGLIOSDeviceBridgeTest {
@Test
void exposesNativeMobileClassification() throws Exception {
Method method = LibJGLIOSDeviceBridge.class.getDeclaredMethod("isMobileDevice");
assertEquals(boolean.class, method.getReturnType());
assertTrue(Modifier.isPublic(method.getModifiers()));
assertTrue(Modifier.isStatic(method.getModifiers()));
assertTrue(Modifier.isNative(method.getModifiers()));
}
}
Loading