通過上文分析,我們知道FlutterViewHandlePlatformMessage()實際上是通過JNI的方式最終調用了FlutterJNI.java中的handlePlatformMessage()方法,該方法接受三個來自Native層的參數:
- channel: String類型,表示Channel名稱.
- message: 字節數組,表示方法調用中的數據,如方法名和參數.
- replyId: int類型,在將此次調用的響應數據從Java層寫回到Native層時用到
public class FlutterJNI {
private PlatformMessageHandler platformMessageHandler;
@UiThread
public void setPlatformMessageHandler(@Nullable PlatformMessageHandler platformMessageHandler) {
this.platformMessageHandler = platformMessageHandler;
}
// Called by native.
@SuppressWarnings("unused")
private void handlePlatformMessage(final String channel, byte[] message, final int replyId) {
if (platformMessageHandler != null) {
platformMessageHandler.handleMessageFromDart(channel, message, replyId);
}
}
}
FlutterJNI類定義了Java層和Flutter C/C++引擎之間的相關接口.此類目前處于實驗性質,隨著后續的發展可能會被不斷的重構和優化,不保證一直存在,不建議開發者調用該類.
為了建立Android應用和Flutter C/C++引擎的連接,需要創建FlutterJNI實例,然后將其attach到Native,常見的使用方法如下:
// 1.創建FlutterJNI實例
FlutterJNI flutterJNI = new FlutterJNI();
// 2.建立和Native層的連接
flutterJNI.attachToNative();
......
// 3.斷開和Native層的連接,并釋放資源
flutterJNI.detachFromNativeAndReleaseResources();
FlutterJNI中handlePlatformMessage()
,在該方法中首先判斷platformMessageHandler是否為null,不為null,則調用其handleMessageFromDart()
方法.其中platformMessageHandler需要通過FlutterJNI中的setPlatformMessageHandler()
方法來設置.在FlutterNativeView中調用的。
public class FlutterNativeView implements BinaryMessenger {
private final Map<String, BinaryMessageHandler> mMessageHandlers;
private int mNextReplyId = 1;
private final Map<Integer, BinaryReply> mPendingReplies = new HashMap<>();
private final FlutterPluginRegistry mPluginRegistry;
private FlutterView mFlutterView;
private FlutterJNI mFlutterJNI;
private final Context mContext;
private boolean applicationIsRunning;
public FlutterNativeView(Context context, boolean isBackgroundView) {
mContext = context;
mPluginRegistry = new FlutterPluginRegistry(this, context);
// 創建FlutterJNI實例
mFlutterJNI = new FlutterJNI();
mFlutterJNI.setRenderSurface(new RenderSurfaceImpl());
// 將PlatformMessageHandlerImpl實例賦值給FlutterJNI中的platformMessageHandler屬性
mFlutterJNI.setPlatformMessageHandler(new PlatformMessageHandlerImpl());
mFlutterJNI.addEngineLifecycleListener(new EngineLifecycleListenerImpl());
attach(this, isBackgroundView);
assertAttached();
mMessageHandlers = new HashMap<>();
}
.......
}
在FlutterNativeView的構造函數中,首先創建FlutterJNI實例mFlutterJNI,然后調用setPlatformMessageHandler()
并把PlatformMessageHandlerImpl實例作為參數傳入.因此在FlutterJNI的handlePlatformMessage()
方法中,最終調用PlatformMessageHandlerImpl實例的handleMessageFromDart()
來處理來自Flutter中的消息.
public class FlutterNativeView implements BinaryMessenger {
private final Map<String, BinaryMessageHandler> mMessageHandlers;
......
private final class PlatformMessageHandlerImpl implements PlatformMessageHandler {
// Called by native to send us a platform message.
public void handleMessageFromDart(final String channel, byte[] message, final int replyId) {
// 1.根據channel名稱獲取對應的BinaryMessageHandler對象.每個Channel對應一個Handler對象
BinaryMessageHandler handler = mMessageHandlers.get(channel);
if (handler != null) {
try {
// 2.將字節數組對象封裝為ByteBuffer對象
final ByteBuffer buffer = (message == null ? null : ByteBuffer.wrap(message));
// 3.調用handler對象的onMessage()方法來分發消息
handler.onMessage(buffer, new BinaryReply() {
private final AtomicBoolean done = new AtomicBoolean(false);
@Override
public void reply(ByteBuffer reply) {
// 4.根據reply的情況,調用FlutterJNI中invokePlatformMessageXXX()方法將響應數據發送給Flutter層
if (reply == null) {
mFlutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
} else {
mFlutterJNI.invokePlatformMessageResponseCallback(replyId, reply, reply.position());
}
}
});
} catch (Exception exception) {
mFlutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
}
return;
}
mFlutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
}
}
以Channel名稱作為key,以BinaryMessageHandler類型為value.在handleMessageFromDart()
方法中,首先根據Channel名稱從mMessageHandlers取出對應的二進制消息處理器BinaryMessageHandler,然后將字節數組message封裝為ByteBuffer對象,然后調用BinaryMessageHandler實例的onMessage()
方法處理ByteBuffer,并進行響應.
BinaryReply是一個接口,主要用來將ByteBuffer類型的響應數據reply從Java層寫回到Flutter層.根據reply是否為null,調用FlutterJNI實例不同的方法.
BinaryMessageHandler是如何添加到mMessageHandler中:
public class FlutterNativeView implements BinaryMessenger {
private final Map<String, BinaryMessageHandler> mMessageHandlers;
......
@Override
public void setMessageHandler(String channel, BinaryMessageHandler handler) {
if (handler == null) {
mMessageHandlers.remove(channel);
} else {
mMessageHandlers.put(channel, handler);
}
}
.......
}
public class MainActivity extends FlutterActivity {
// 1.定義Channel的名稱,該名稱作為Channel的唯一標識符
private static final String CHANNEL = "samples.flutter.io/battery";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 2.創建MethodChannel對象channel
MethodChannel channel = new MethodChannel(getFlutterView(), CHANNEL);
// 3.調用MethodChannel實例的setMethodCallHandler()方法為當前channel設置Handler
channel.setMethodCallHandler(
new MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, Result result) {
// TODO
}
});
}
}
接下來是 MethodChannel 定義
public final class MethodChannel {
// 二進制信使
private final BinaryMessenger messenger;
// Channel名稱
private final String name;
// 方法編碼
private final MethodCodec codec;
public MethodChannel(BinaryMessenger messenger, String name) {
this(messenger, name, StandardMethodCodec.INSTANCE);
}
public MethodChannel(BinaryMessenger messenger, String name, MethodCodec codec) {
assert messenger != null;
assert name != null;
assert codec != null;
this.messenger = messenger;
this.name = name;
this.codec = codec;
}
......
public void setMethodCallHandler(final @Nullable MethodCallHandler handler) {
messenger.setMessageHandler(name,
handler == null ? null : new IncomingMethodCallHandler(handler));
}
......
private final class IncomingMethodCallHandler implements BinaryMessageHandler {
private final MethodCallHandler handler;
IncomingMethodCallHandler(MethodCallHandler handler) {
this.handler = handler;
}
@Override
public void onMessage(ByteBuffer message, final BinaryReply reply) {
// 1.使用codec對來自Flutter方法調用數據進行解碼,并將其封裝為MethodCall對象.
// MethodCall中包含兩部分數據:method表示要調用的方法;arguments表示方法所需參數
final MethodCall call = codec.decodeMethodCall(message);
try {
// 2.調用自定義MethodCallHandler中的onMethodCall方法繼續處理方法調用
handler.onMethodCall(call, new Result() {
@Override
public void success(Object result) {
// 調用成功時,需要回傳數據給Flutter層時,使用codec對回傳數據result
// 進行編碼
reply.reply(codec.encodeSuccessEnvelope(result));
}
@Override
public void error(String errorCode, String errorMessage, Object errorDetails) {
// 調用失敗時,需要回傳錯誤數據給Flutter層時,使用codec對errorCode,
// errorMessage,errorDetails進行編碼
reply.reply(codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails));
}
@Override
public void notImplemented() {
// 方法沒有實現時,調用該方法后,flutter將會受到相應的錯誤消息
reply.reply(null);
}
});
} catch (RuntimeException e) {
Log.e(TAG + name, "Failed to handle method call", e);
reply.reply(codec.encodeErrorEnvelope("error", e.getMessage(), null));
}
}
}
}
在上述代碼中,首先使用codec對來自Flutter層的二進制數據進行解碼,并將其封裝為MethodCall對象,然后調用MethodCallHandler.onMethodCall()
方法.
Java->Native
public class FlutterJNI {
private Long nativePlatformViewId;
......
@UiThread
public void invokePlatformMessageResponseCallback(int responseId, ByteBuffer message, int position) {
// 1.檢查FlutterJNI是否已經attach到Native層,如若沒有則拋出異常
ensureAttachedToNative();
// 2.繼續調用nativeInvokePlatformMessageResponseCallback()
nativeInvokePlatformMessageResponseCallback(
nativePlatformViewId,
responseId,
message,
position
);
}
private native void nativeInvokePlatformMessageResponseCallback(
long nativePlatformViewId,
int responseId,
ByteBuffer message,
int position
);
......
private void ensureAttachedToNative() {
// FlutterJNI attach到Native層后,會返回一個long類型的值用來初始化nativePlatformViewId
if (nativePlatformViewId == null) {
throw new RuntimeException("Cannot execute operation because FlutterJNI is not attached to native.");
}
}
}
當數據需要寫回時,數據首先通過codec被編碼成ByteBuffer類型,然后調用reply的reply()
方法.在reply()
方法中,對于非null類型的ByteBuffer,會調用FlutterJNI中的invokePlatformMessageResponseCallback()
.
在上述invokePlatformMessageResponseCallback()
方法中,首先檢查當前FlutterJNI實例是否已經attach到Native層,然后調用Native方法nativeInvokePlatformMessageResponseCallback()
向JNI層寫入數據
void PlatformViewAndroid::InvokePlatformMessageResponseCallback(
JNIEnv* env,
jint response_id,
jobject java_response_data,
jint java_response_position) {
if (!response_id)
return;
// 1.通過response_id從pending_responses_中取出response
auto it = pending_responses_.find(response_id);
if (it == pending_responses_.end())
return;
// 2.GetDirectBufferAddress函數返回一個指向被傳入的ByteBuffer對象的地址指針
uint8_t* response_data =
static_cast<uint8_t*>(env->GetDirectBufferAddress(java_response_data));
std::vector<uint8_t> response = std::vector<uint8_t>(
response_data, response_data + java_response_position);
auto message_response = std::move(it->second);
// 3.從pending_responses_中移除該response
pending_responses_.erase(it);
// 4.調用response的Complete()方法將二進制結果返回
message_response->Complete(
std::make_unique<fml::DataMapping>(std::move(response)));
}
Native -> Dart
void PlatformMessageResponseDart::Complete(std::unique_ptr<fml::Mapping> data) {
if (callback_.is_empty())
return;
FML_DCHECK(!is_complete_);
is_complete_ = true;
ui_task_runner_->PostTask(fml::MakeCopyable(
[callback = std::move(callback_), data = std::move(data)]() mutable {
std::shared_ptr<tonic::DartState> dart_state =
callback.dart_state().lock();
if (!dart_state)
return;
tonic::DartState::Scope scope(dart_state);
// 將Native層的二進制數據data轉為Dart中的二進制數據byte_buffer
Dart_Handle byte_buffer = WrapByteData(std::move(data));
tonic::DartInvoke(callback.Release(), {byte_buffer});
}));
}