GameSession
GameSession owns the native session (sessionId) and bridges it to the Activity and views. It implements Closeable and must be closed explicitly.
Minimal lifecycle
Section titled “Minimal lifecycle”// in the surfaceCreated callbacksession = 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.
The three Surface callbacks
Section titled “The three Surface callbacks”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.
Touch and script channels
Section titled “Touch and script channels”surfaceView.setOnTouchListener((v, ev) -> session.dispatchTouchEvent(ev));
// host → JSsession.evaluateJavaScript("console.log('hello from host')");
// JS → host: migo.sendToHost(type, payload) arrives heresession.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.
State broadcasts: OnStateChangeListener
Section titled “State broadcasts: OnStateChangeListener”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.
Four methods directly tied to native
Section titled “Four methods directly tied to native”| 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 |
Handler setters (10 domains + Listener)
Section titled “Handler setters (10 domains + Listener)”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 hooksNot 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.