public class FlutterJNI extends Object
Flutter's engine is built with C/C++. The Android Flutter embedding is responsible for coordinating Android OS events and app user interactions with the C/C++ engine. Such coordination requires messaging from an Android app in Java code to the C/C++ engine code. This communication requires a JNI (Java Native Interface) API to cross the Java/native boundary.
The entirety of Flutter's JNI API is codified in FlutterJNI
. There are multiple
reasons that all such calls are centralized in one class. First, JNI calls are inherently static
and contain no Java implementation, therefore there is little reason to associate calls with
different classes. Second, every JNI call must be registered in C/C++ code and this registration
becomes more complicated with every additional Java class that contains JNI calls. Third, most
Android developers are not familiar with native development or JNI intricacies, therefore it is
in the interest of future maintenance to reduce the API surface that includes JNI declarations.
Thus, all Flutter JNI calls are centralized in FlutterJNI
.
Despite the fact that individual JNI calls are inherently static, there is state that exists
within FlutterJNI
. Most calls within FlutterJNI
correspond to a specific
"platform view", of which there may be many. Therefore, each FlutterJNI
instance holds
onto a "native platform view ID" after attachToNative(boolean)
, which is shared with the
native C/C++ engine code. That ID is passed to every platform-view-specific native method. ID
management is handled within FlutterJNI
so that developers don't have to hold onto that
ID.
To connect part of an Android app to Flutter's C/C++ engine, instantiate a FlutterJNI
and then attach it to the native side:
// Instantiate FlutterJNI and attach to the native side.
FlutterJNI flutterJNI = new FlutterJNI();
flutterJNI.attachToNative();
// Use FlutterJNI as desired. flutterJNI.dispatchPointerDataPacket(...);
// Destroy the connection to the native side and cleanup.
flutterJNI.detachFromNativeAndReleaseResources();
To provide a visual, interactive surface for Flutter rendering and touch events, register a
RenderSurface
with #setRenderSurface(RenderSurface)
To receive callbacks for certain events that occur on the native side, register listeners:
#addEngineLifecycleListener(EngineLifecycleListener)
addIsDisplayingFlutterUiListener(FlutterUiDisplayListener)
setPlatformMessageHandler(PlatformMessageHandler)
To invoke a native method that is not associated with a platform view, invoke it statically:
bool enabled = FlutterJNI.nativeGetIsSoftwareRenderingEnabled();
Modifier and Type | Class and Description |
---|---|
static interface |
FlutterJNI.AccessibilityDelegate
Delegate responsible for creating and updating Android-side caches of Flutter's semantics tree
and custom accessibility actions.
|
static interface |
FlutterJNI.AsyncWaitForVsyncDelegate |
Constructor and Description |
---|
FlutterJNI() |
Modifier and Type | Method and Description |
---|---|
void |
addEngineLifecycleListener(FlutterEngine.EngineLifecycleListener engineLifecycleListener)
Adds the given
engineLifecycleListener to be notified of Flutter engine lifecycle
events, e.g., FlutterEngine.EngineLifecycleListener.onPreEngineRestart() . |
void |
addIsDisplayingFlutterUiListener(FlutterUiDisplayListener listener)
Adds a
FlutterUiDisplayListener , which receives a callback when Flutter's engine
notifies FlutterJNI that Flutter is painting pixels to the Surface that was
provided to Flutter. |
void |
attachToNative(boolean isBackgroundView)
Attaches this
FlutterJNI instance to Flutter's native engine, which allows for
communication between Android code and Flutter's platform agnostic engine. |
void |
detachFromNativeAndReleaseResources()
Detaches this
FlutterJNI instance from Flutter's native engine, which precludes any
further communication between Android code and Flutter's platform agnostic engine. |
void |
dispatchEmptyPlatformMessage(String channel,
int responseId)
Sends an empty reply (identified by
responseId ) from Android to Flutter over the given
channel . |
void |
dispatchPlatformMessage(String channel,
ByteBuffer message,
int position,
int responseId)
Sends a reply
message from Android to Flutter over the given channel . |
void |
dispatchPointerDataPacket(ByteBuffer buffer,
int position)
Sends a packet of pointer data to Flutter's engine.
|
void |
dispatchSemanticsAction(int id,
AccessibilityBridge.Action action)
Sends a semantics action to Flutter's engine, without any additional arguments.
|
void |
dispatchSemanticsAction(int id,
AccessibilityBridge.Action action,
Object args)
Sends a semantics action to Flutter's engine, with additional arguments.
|
void |
dispatchSemanticsAction(int id,
int action,
ByteBuffer args,
int argsPosition)
Sends a semantics action to Flutter's engine, given arguments that are already encoded for the
engine.
|
Bitmap |
getBitmap() |
static String |
getObservatoryUri() |
void |
invokePlatformMessageEmptyResponseCallback(int responseId) |
void |
invokePlatformMessageResponseCallback(int responseId,
ByteBuffer message,
int position) |
boolean |
isAttached()
Returns true if this instance of
FlutterJNI is connected to Flutter's native engine via
a Java Native Interface (JNI). |
void |
markTextureFrameAvailable(long textureId)
Call this method to inform Flutter that a texture previously registered with
registerTexture(long, SurfaceTexture) has a new frame available. |
boolean |
nativeGetIsSoftwareRenderingEnabled() |
static void |
nativeInit(Context context,
String[] args,
String bundlePath,
String appStoragePath,
String engineCachesPath) |
static FlutterCallbackInformation |
nativeLookupCallbackInformation(long handle) |
static void |
nativeOnVsync(long frameTimeNanos,
long frameTargetTimeNanos,
long cookie) |
static void |
nativeRecordStartTimestamp(long initTimeMillis) |
void |
onSurfaceChanged(int width,
int height)
Call this method when the
Surface changes that was previously registered with onSurfaceCreated(Surface) . |
void |
onSurfaceCreated(Surface surface)
Call this method when a
Surface has been created onto which you would like Flutter to
paint. |
void |
onSurfaceDestroyed()
Call this method when the
Surface is destroyed that was previously registered with
onSurfaceCreated(Surface) . |
void |
registerTexture(long textureId,
SurfaceTexture surfaceTexture)
Gives control of a
SurfaceTexture to Flutter so that Flutter can display that texture
within Flutter's UI. |
void |
removeEngineLifecycleListener(FlutterEngine.EngineLifecycleListener engineLifecycleListener)
Removes the given
engineLifecycleListener , which was previously added using addIsDisplayingFlutterUiListener(FlutterUiDisplayListener) . |
void |
removeIsDisplayingFlutterUiListener(FlutterUiDisplayListener listener)
Removes a
FlutterUiDisplayListener that was added with addIsDisplayingFlutterUiListener(FlutterUiDisplayListener) . |
void |
runBundleAndSnapshotFromLibrary(String bundlePath,
String entrypointFunctionName,
String pathToEntrypointFunction,
AssetManager assetManager)
Executes a Dart entrypoint.
|
void |
setAccessibilityDelegate(FlutterJNI.AccessibilityDelegate accessibilityDelegate)
Sets the
FlutterJNI.AccessibilityDelegate for the attached Flutter context. |
void |
setAccessibilityFeatures(int flags) |
static void |
setAsyncWaitForVsyncDelegate(FlutterJNI.AsyncWaitForVsyncDelegate delegate) |
void |
setPlatformMessageHandler(PlatformMessageHandler platformMessageHandler)
Sets the handler for all platform messages that come from the attached platform view to Java.
|
static void |
setRefreshRateFPS(float refreshRateFPS) |
void |
setSemanticsEnabled(boolean enabled)
Instructs Flutter to enable/disable its semantics tree, which is used by Flutter to support
accessibility and related behaviors.
|
void |
setViewportMetrics(float devicePixelRatio,
int physicalWidth,
int physicalHeight,
int physicalPaddingTop,
int physicalPaddingRight,
int physicalPaddingBottom,
int physicalPaddingLeft,
int physicalViewInsetTop,
int physicalViewInsetRight,
int physicalViewInsetBottom,
int physicalViewInsetLeft,
int systemGestureInsetTop,
int systemGestureInsetRight,
int systemGestureInsetBottom,
int systemGestureInsetLeft)
Call this method to notify Flutter of the current device viewport metrics that are applies to
the Flutter UI that is being rendered.
|
void |
unregisterTexture(long textureId)
Unregisters a texture that was registered with
registerTexture(long, SurfaceTexture) . |
public static void nativeInit(@NonNull Context context, @NonNull String[] args, @Nullable String bundlePath, @NonNull String appStoragePath, @NonNull String engineCachesPath)
public static void nativeRecordStartTimestamp(long initTimeMillis)
@UiThread public boolean nativeGetIsSoftwareRenderingEnabled()
@Nullable public static String getObservatoryUri()
public static void setRefreshRateFPS(float refreshRateFPS)
public static void setAsyncWaitForVsyncDelegate(@Nullable FlutterJNI.AsyncWaitForVsyncDelegate delegate)
public static void nativeOnVsync(long frameTimeNanos, long frameTargetTimeNanos, long cookie)
@NonNull public static FlutterCallbackInformation nativeLookupCallbackInformation(long handle)
public boolean isAttached()
FlutterJNI
is connected to Flutter's native engine via
a Java Native Interface (JNI).@UiThread public void attachToNative(boolean isBackgroundView)
FlutterJNI
instance to Flutter's native engine, which allows for
communication between Android code and Flutter's platform agnostic engine.
This method must not be invoked if FlutterJNI
is already attached to native.
@UiThread public void detachFromNativeAndReleaseResources()
FlutterJNI
instance from Flutter's native engine, which precludes any
further communication between Android code and Flutter's platform agnostic engine.
This method must not be invoked if FlutterJNI
is not already attached to native.
Invoking this method will result in the release of all native-side resources that were setup
during attachToNative(boolean)
, or accumulated thereafter.
It is permissable to re-attach this instance to native after detaching it from native.
@UiThread public void addIsDisplayingFlutterUiListener(@NonNull FlutterUiDisplayListener listener)
FlutterUiDisplayListener
, which receives a callback when Flutter's engine
notifies FlutterJNI
that Flutter is painting pixels to the Surface
that was
provided to Flutter.@UiThread public void removeIsDisplayingFlutterUiListener(@NonNull FlutterUiDisplayListener listener)
FlutterUiDisplayListener
that was added with addIsDisplayingFlutterUiListener(FlutterUiDisplayListener)
.@UiThread public void onSurfaceCreated(@NonNull Surface surface)
Surface
has been created onto which you would like Flutter to
paint.
See SurfaceHolder.Callback.surfaceCreated(SurfaceHolder)
for an example
of where this call might originate.
@UiThread public void onSurfaceChanged(int width, int height)
Surface
changes that was previously registered with onSurfaceCreated(Surface)
.
See SurfaceHolder.Callback.surfaceChanged(SurfaceHolder, int, int, int)
for an example of where this call might originate.
@UiThread public void onSurfaceDestroyed()
Surface
is destroyed that was previously registered with
onSurfaceCreated(Surface)
.
See SurfaceHolder.Callback.surfaceDestroyed(SurfaceHolder)
for an
example of where this call might originate.
@UiThread public void setViewportMetrics(float devicePixelRatio, int physicalWidth, int physicalHeight, int physicalPaddingTop, int physicalPaddingRight, int physicalPaddingBottom, int physicalPaddingLeft, int physicalViewInsetTop, int physicalViewInsetRight, int physicalViewInsetBottom, int physicalViewInsetLeft, int systemGestureInsetTop, int systemGestureInsetRight, int systemGestureInsetBottom, int systemGestureInsetLeft)
This method should be invoked with initial values upon attaching to native. Then, it should
be invoked any time those metrics change while FlutterJNI
is attached to native.
@UiThread public void dispatchPointerDataPacket(@NonNull ByteBuffer buffer, int position)
@UiThread public void setAccessibilityDelegate(@Nullable FlutterJNI.AccessibilityDelegate accessibilityDelegate)
FlutterJNI.AccessibilityDelegate
for the attached Flutter context.
The FlutterJNI.AccessibilityDelegate
is responsible for maintaining an Android-side cache of
Flutter's semantics tree and custom accessibility actions. This cache should be hooked up to
Android's accessibility system.
See AccessibilityBridge
for an example of an FlutterJNI.AccessibilityDelegate
and the
surrounding responsibilities.
public void dispatchSemanticsAction(int id, @NonNull AccessibilityBridge.Action action)
public void dispatchSemanticsAction(int id, @NonNull AccessibilityBridge.Action action, @Nullable Object args)
@UiThread public void dispatchSemanticsAction(int id, int action, @Nullable ByteBuffer args, int argsPosition)
To send a semantics action that has not already been encoded, see dispatchSemanticsAction(int, AccessibilityBridge.Action)
and dispatchSemanticsAction(int, AccessibilityBridge.Action, Object)
.
@UiThread public void setSemanticsEnabled(boolean enabled)
@UiThread public void setAccessibilityFeatures(int flags)
@UiThread public void registerTexture(long textureId, @NonNull SurfaceTexture surfaceTexture)
SurfaceTexture
to Flutter so that Flutter can display that texture
within Flutter's UI.@UiThread public void markTextureFrameAvailable(long textureId)
registerTexture(long, SurfaceTexture)
has a new frame available.
Invoking this method instructs Flutter to update its presentation of the given texture so that the new frame is displayed.
@UiThread public void unregisterTexture(long textureId)
registerTexture(long, SurfaceTexture)
.@UiThread public void runBundleAndSnapshotFromLibrary(@NonNull String bundlePath, @Nullable String entrypointFunctionName, @Nullable String pathToEntrypointFunction, @NonNull AssetManager assetManager)
This can only be done once per JNI attachment because a Dart isolate can only be entered once.
@UiThread public void setPlatformMessageHandler(@Nullable PlatformMessageHandler platformMessageHandler)
Communication between a specific Flutter context (Dart) and the host platform (Java) is
accomplished by passing messages. Messages can be sent from Java to Dart with the corresponding
FlutterJNI
methods:
FlutterJNI
is also the recipient of all platform messages sent from its attached
Flutter context. FlutterJNI
does not know what to do with these messages, so a handler
is exposed to allow these messages to be processed in whatever manner is desired:
setPlatformMessageHandler(PlatformMessageHandler)
If a message is received but no PlatformMessageHandler
is registered, that message
will be dropped (ignored). Therefore, when using FlutterJNI
to integrate a Flutter
context in an app, a PlatformMessageHandler
must be registered for 2-way Java/Dart
communication to operate correctly. Moreover, the handler must be implemented such that
fundamental platform messages are handled as expected. See FlutterNativeView
for an
example implementation.
@UiThread public void dispatchEmptyPlatformMessage(@NonNull String channel, int responseId)
responseId
) from Android to Flutter over the given
channel
.@UiThread public void dispatchPlatformMessage(@NonNull String channel, @Nullable ByteBuffer message, int position, int responseId)
message
from Android to Flutter over the given channel
.@UiThread public void invokePlatformMessageEmptyResponseCallback(int responseId)
@UiThread public void invokePlatformMessageResponseCallback(int responseId, @Nullable ByteBuffer message, int position)
@UiThread public void addEngineLifecycleListener(@NonNull FlutterEngine.EngineLifecycleListener engineLifecycleListener)
engineLifecycleListener
to be notified of Flutter engine lifecycle
events, e.g., FlutterEngine.EngineLifecycleListener.onPreEngineRestart()
.@UiThread public void removeEngineLifecycleListener(@NonNull FlutterEngine.EngineLifecycleListener engineLifecycleListener)
engineLifecycleListener
, which was previously added using addIsDisplayingFlutterUiListener(FlutterUiDisplayListener)
.@UiThread public Bitmap getBitmap()