Skip to content

GameSession

GameSession owns the native session (sessionId) and bridges it to the Activity and views. It implements Closeable and must be closed explicitly.

// in the surfaceCreated callback
session = runtime.createSession(activity, surface, config, gameId);
session.startGame("game.js"); // game.js lives under session.getPaths().getCodeDir()
// Activity
@Override protected void onPause() { if (session != null) session.pause(); }
@Override protected void onResume() { if (session != null) session.resume(); }
@Override protected void onDestroy(){
if (session != null) { session.close(); session = null; }
}

After close(), methods guarded by ensureNotDestroyed throw MigoException (code -2000 ERR_SESSION_DESTROYED, extending RuntimeException); pause() and resume() are safe no-ops, and dispatchTouchEvent returns false. Until the session is closed, native memory, the JS context, and platform channels are not released.

These correspond to the three SurfaceHolder callbacks:

surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
public void surfaceCreated(SurfaceHolder h) { /* createSession */ }
public void surfaceChanged(SurfaceHolder h, int fmt, int w, int h) {
session.updateSurface(h.getSurface(), w, h);
}
public void surfaceDestroyed(SurfaceHolder h) {
session.onSurfaceDestroyed(); // the engine takes the surface-lost path; JS onHide fires here
}
});

Forgetting onSurfaceDestroyed is the most common source of deadlocks: the engine does not know the Surface is gone, and GPU resources remain attached to the destroyed object.

surfaceView.setOnTouchListener((v, ev) -> session.dispatchTouchEvent(ev));
// host → JS
session.evaluateJavaScript("console.log('hello from host')");
// JS → host: migo.sendToHost(type, payload) arrives here
session.setMessageHandler((type, payload) -> { /* JSON String, may be null */ });

evaluateJavaScript returns immediately; the script is queued asynchronously on the host thread. To receive a reply, pair migo.sendToHost with MessageHandler.

setOnStateChangeListener(listener) receives the engine’s loading / running / error state transitions — use it to drive the loading UI; do not estimate state with SystemClock. GameSessionListener (a separate interface) provides finer-grained loadingStart/loadingEnd hooks.

Method Semantics
updateSurface(surface, w, h) Called from surfaceChanged; w/h are physical pixels (Surface buffer dimensions), so pass the original values from the system callback directly
onSurfaceDestroyed() Does not destroy the session; marks the Surface invalid and corresponds to the JS onHide path
setDebugEnabled(boolean) Toggles DebugOverlay at runtime
getPaths() Provides GamePaths.getCodeDir() and others; the location for game.js

Install these before opening the package; see the detailed contract in Host capabilities overview:

session.setMessageHandler(...); setAuthHandler(...);
session.setPermissionHandler(...); setAdHandler(...);
session.setSettingHandler(...); setShareHandler(...);
session.setNavigationHandler(...); setPaymentHandler(...);
session.setSubpackageHandler(...); setGameLogHandler(...);
session.setListener(GameSessionListener); // loading-level hooks

Not setting a handler means the fallback in the overview table applies. After installing one, do not swap it mid-session — in-flight requests already hold the sink for the old handler.