可將 Dark 的 function 傳入 Java,以 Callback 的方式讓 Java 執行之。
Version
Flutter 3.24
Dart 3.5
Create Project
$ flutter create --template=plugin -a java --platforms=android callback_plugin
- 使用
flutter create
建立 Flutter 專案 --template
:指定以plugin
樣板建立專案-a java
:以 Java 為 Android 的語言--platforms=android
:只建立 Android 的 plugincallback_plugin
:專案名稱
Java Class
android/src/main/java/com.example.callback_plugin/TaskProcessor.java
package com.example.callback_plugin;
import android.os.Handler;
import android.os.Looper;
public class TaskProcessor {
public interface TaskCallback {
void onComplete(String result);
void onError(String error);
}
public void startTask(TaskCallback callback) {
new Thread(() -> {
try {
// 模擬非同步任務
Thread.sleep(2000); // 假設任務耗時2秒
// 模擬任務成功
String result = "Task completed successfully!";
// 在主線程回調結果
new Handler(Looper.getMainLooper()).post(() -> callback.onComplete(result));
} catch (InterruptedException e) {
// 模擬任務失敗
new Handler(Looper.getMainLooper()).post(() -> callback.onError("Task was interrupted"));
}
}).start();
}
}
- 一般 Java class 處理相關邏輯
Line 13
public void startTask(TaskCallback callback) {
Thread.sleep(2000);
String result = "Task completed successfully!";
}
startTask()
為 Java 普通的 method,但其參數為 callbackresult
:Java 要傳給 Dart 的資料
Line 8
public interface TaskCallback {
void onComplete(String result);
void onError(String error);
}
- 定義 callback 的 interface
- 當 Java 執行
完成
時呼叫onComplete()
,並將成功資料
傳給 Dart - 當 Java 執行
失敗
時,呼叫onError()
,並將錯誤資料
傳給 Dart
Line 23
new Handler(Looper.getMainLooper()).post(() -> callback.onComplete(result));
- 在 main thread 呼叫
onComplete()
,並將成功資料
傳給 Dart
Line 27
new Handler(Looper.getMainLooper()).post(() -> callback.onError("Task was interrupted"));
- 在 main thread 呼叫
onError()
,並將錯誤資料
傳給 Dart
Java Plugin Wrapper
android/src/main/java/com.example.callback_plugin/CallbackPlugin.java
package com.example.callback_plugin;
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
public class CallbackPlugin implements FlutterPlugin, MethodCallHandler {
private MethodChannel channel;
private TaskProcessor taskProcessor;
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "callback_plugin");
channel.setMethodCallHandler(this);
taskProcessor = new TaskProcessor();
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
channel.setMethodCallHandler(null);
channel = null;
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
if (call.method.equals("startTask")) {
taskProcessor.startTask(new TaskProcessor.TaskCallback() {
@Override
public void onComplete(String result) {
channel.invokeMethod("onTaskComplete", result);
}
@Override
public void onError(String error) {
channel.invokeMethod("onTaskError", error);
}
});
result.success(null);
} else {
result.notImplemented();
}
}
}
- Java 的 plugin wrapper
Line 10
public class CallbackPlugin implements FlutterPlugin, MethodCallHandler {
}
- 定義
CallbackPlugin
class,實現以下兩個 interface FlutterPlugin
:實作 plugin,onAttachedToEngine()
:加入 FlutterEngine 時被觸發onDetachedFromEngine()
:離開 FlutterEngine 時被觸發
MethodCallHandler
:處理來自於 Dart 的呼叫onMethodCall()
,當 plugin 的 method 被呼叫時,會觸發onMethodCall()
Line 11
private MethodChannel channel;
private TaskProcessor taskProcessor;
- channel:定義 MethodChannel
- taskProcessor:定義原本的 Java Class
Line 14
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "callback_plugin");
channel.setMethodCallHandler(this);
taskProcessor = new TaskProcessor();
}
- 實現
FlutterPlugin
interface - 加入 FlutterEngine 時被觸發
- 建立 MethodChannel 與自己的 Java class
Line 21
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
channel.setMethodCallHandler(null);
channel = null;
}
- 實現
FlutterPlugin
interface - 離開 FlutterEngine 時被觸發
- 釋放 MethodChannel
Line 27
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
}
- 實現
MethodCallHandler
interface - 所有 Dart 對 Java 的呼叫都會進入
onMethodCall()
,由call.method
判斷是哪一個 method 被呼叫
Line 30
taskProcessor.startTask(new TaskProcessor.TaskCallback() {
@Override
public void onComplete(String result) {
channel.invokeMethod("onTaskComplete", result);
}
@Override
public void onError(String error) {
channel.invokeMethod("onTaskError", error);
}
});
- 呼叫自己 Java class 的
startTask()
- 建立
TaskProcessor.TaskCallback
的 anonymous objectonComplete()
:當 Java 執行成功,透過 MethodChannel 呼叫 plugin 的onTaskComplete()
onError()
:當 Java 執行失敗,透過 MethodChannel 呼叫 plugin 的onTaskError()
Dart Plugin Wrapper
lib/callback_plugin.dart
import 'package:flutter/services.dart';
class CallbackPlugin {
static const MethodChannel _channel = MethodChannel('callback_plugin');
static Future<void> startTask({
required Function(String result) onComplete,
required Function(String error) onError,
}) async {
_channel.setMethodCallHandler((MethodCall call) async {
if (call.method == 'onTaskComplete') {
onComplete(call.arguments);
} else if (call.method == 'onTaskError') {
onError(call.arguments);
}
});
// 呼叫 Android 方法
await _channel.invokeMethod('startTask');
}
}
- Dart 的 plugin wrapper
Line 4
static const MethodChannel _channel = MethodChannel('callback_plugin');
- 定義 MethodChannel
Line 6
static Future<void> startTask({
required Function(String result) onComplete,
required Function(String error) onError,
}) async {
}
startTask()
:定義 plugin 的 method,建議與原 Java class 的 method 相同- 參數為 callback,與 Java 的
TaskCallback
interface 相同,只是改成 Dart 語法 - ChannelMethod 會以非同步形式呈現,因此在 plugin 的 method 都會回傳 Future 與 async
Line 10
_channel.setMethodCallHandler((MethodCall call) async {
if (call.method == 'onTaskComplete') {
onComplete(call.arguments);
} else if (call.method == 'onTaskError') {
onError(call.arguments);
}
});
- 設定呼叫 plugin 時的處理方式
onTaskComplete
:當呼叫 plugin 的onTaskComplete()
時,呼叫 Dart 傳進的onComplete()
,並傳入 Java 傳來的成功資料
onTaskError
:當呼叫 plugin 的onTaskError()
時,呼叫 Dart 傳進的onError()
,並傳入 Java 傳來的錯誤資料
Flutter Dart
example/lib/main.dart
import 'package:callback_plugin/callback_plugin.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Dart to Java Callback Example')),
body: Center(
child: ElevatedButton(
onPressed: () {
CallbackPlugin.startTask(
onComplete: (result) {
print("Received from Java: $result");
},
onError: (error) {
print("Error from Java: $error");
},
);
},
child: const Text('Start Task'),
),
),
),
);
}
}
- Flutter 使用 plugin 呼叫 Java,並傳入 callback
Line 1
import 'package:callback_plugin/callback_plugin.dart';
- 引用 Dart 的 plugin
Line 17
ElevatedButton(
onPressed: () {
CallbackPlugin.startTask(
onComplete: (result) {
print("Received from Java: $result");
},
onError: (error) {
print("Error from Java: $error");
},
);
},
child: const Text('Start Task'),
)
- 在按下 button 後呼叫
CallbackPlugin.startTask()
,並傳入onComplete()
與onError()
兩個 callback result
與error
為 Java 所回傳的資料
Start Task
置中顯示,按下可在 Dart 呼叫 Java
- 收到 Java 所傳回的
成功資料
Conclusion
- 若要將原本 Java class 包成 plugin 給 Dart 使用,有以下 SOP
- 新增 Java 的 plugin wrapper class
- 新增 Dart 的 plugin wrapper class
- Dart 使用 plugin 呼叫 Java