PS:多くの場合、既知の影響の80%は、考えられる原因の20%に起因します。
以前の記事では、ナビゲーターコンポーネント、Flexレイアウト、画像の読み込み、ウィジェットのライフサイクル、ハイブリッド開発など、Flutter開発の基本を紹介しました。記事は次のとおりです。
- Flutterシリーズのナビゲーターの使用に関する詳細な説明
- Flutterシリーズのフレックスレイアウトの詳細な説明
- Flutterシリーズでの画像読み込みの詳細な説明
- Flutterシリーズのウィジェットライフサイクル
- 混合開発Android記事のFlutterシリーズ
- Flutterシリーズのプラットフォームチャネルの使用に関する詳細な説明
以下に、Flutterハイブリッド開発でのプラットフォームチャネルの使用について紹介します。主な内容は次のとおりです。
- プラットフォームチャネルの紹介
- プラットフォームのデータ型の比較
- BasicMessageChannel
- MethodChannel
- EventChannel
プラットフォームチャネルの紹介
プラットフォームチャネルは非同期メッセージチャネルです。メッセージは送信前にバイナリメッセージにエンコードされ、受信したバイナリメッセージはダーツ値にデコードされます。送信するメッセージタイプは、対応するデコーダーでサポートされている値のみです。すべてのデコードは空のメッセージをサポートし、ネイティブとフラッター間の通信アーキテクチャを次の図に示します。
Flutterでは3つの異なるタイプのPlatformChannelが定義されています。主な3つは次のとおりです。
- BasicMessageChannel:データ送信に使用されます。
- MethodChannel:メソッド呼び出しを転送するために使用されます。
- EventChannel:イベントの配信に使用されます。
その構築方法は、チャネル識別子、デコーダー、およびBinaryMessengerを指定する必要があります。BinaryMessengerは、Flutterとプラットフォーム間の通信ツールであり、バイナリデータの転送、対応するメッセージプロセッサの設定などに使用されます。
MethodCodecとMessageCodecの2つのコーデックがあります。前者はメソッドに対応し、後者はメッセージに対応します。BasicMessageChannelはMessageCodecを使用し、MethodChannelとEventChannelはMethodCodecを使用します。
プラットフォームのデータ型の比較
プラットフォームチャネルは、さまざまなメッセージデコードメカニズムを提供します。たとえば、StandardMessageCodecは基本的なデータ型のデコードを提供し、JSONMessageCodecはプラットフォーム間で通信するときに自動的に変換されるJsonデコードなどをサポートします。各プラットフォームのデータ型は次のように比較されます。
BasicMessageChannel
BasicMessageChannelは、主にバイナリデータを含むデータ転送に使用されます。BasicMessageChannelを使用すると、MethodChannelとEventChannelの機能を実現できます。ここでは、BasicMessageChannelを使用して、AndroidプロジェクトでFlutterリソースファイルを使用する場合を実現します。重要なプロセスは次のとおりです。次のように:
- Flutter側は、画像リソースに対応するバイナリデータを取得します。ここではBinaryCodecが使用され、データ形式はByteDataです。
- BasicMessageChannelを使用して、画像に対応するデータを送信します。
- Android側でByteBufferを使用して受信し、ByteArrayに変換してから、ビットマップに解析して表示します。
Flutter側のキーコードは次のとおりです。
// 创建BasicMessageChannel
_basicMessageChannel = BasicMessageChannel<ByteData>("com.manu.image", BinaryCodec());
// 获取assets中的图片对应的ByteData数据
rootBundle.load('images/miao.jpg').then((value) => {
_sendStringMessage(value)
});
// 发送图片数据
_sendStringMessage(ByteData byteData) async {
await _basicMessageChannel.send(byteData);
}
Android側のキーコードは次のとおりです。
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
Log.i(tag, "configureFlutterEngine")
// 设置消息处理器
BasicMessageChannel<ByteBuffer>(
flutterEngine.dartExecutor, "com.manu.image", BinaryCodec.INSTANCE
).setMessageHandler {
message, reply ->
Log.i(tag, "configureFlutterEngine > message:$message")
// 数据转换:ByteBuffer->ByteArray
val byteBuffer = message as ByteBuffer
imageByteArray = ByteArray(byteBuffer.capacity())
byteBuffer.get(imageByteArray)
}
// 用于设置Flutter跳转Android的方法处理器
MethodChannel(flutterEngine.dartExecutor, channel).setMethodCallHandler {
call, result ->
Log.i(tag, "configureFlutterEngine > method:${
call.method}")
if ("startBasicMessageChannelActivity" == call.method) {
// 携带图片数据
BasicMessageChannelActivity.startBasicMessageChannelActivity(this,imageByteArray)
}
}
}
// 显示来自Flutter assets中的图片
val imageByteArray = intent.getByteArrayExtra("key_image")
val bitmap = BitmapFactory.decodeByteArray(imageByteArray,0,imageByteArray.size)
imageView.setImageBitmap(bitmap)
さらに、BinaryCodecと組み合わせたBasicMessageChannelは、大容量メモリデータブロックの転送をサポートします。
MethodChannel
MethodChannelは主にメソッドの転送に使用されます。NaturalメソッドとDartメソッドは自然に渡すことができます。つまり、MethodChannelを介してFlutterでAndroidネイティブメソッドを呼び出し、AndroidでDartメソッドを呼び出すことができます。相互呼び出しはすべてのinvokeMethodメソッドを介して呼び出されます。 MethodChannel。次のように、同じチャネル識別子を使用する必要があります。
- FlutterはAndroidメソッドを呼び出します
MethodChannelを使用して、FlutterからAndroidのネイティブインターフェイスMainActivityへのジャンプを実現しましょう。Android側は次のとおりです。
/**
* @desc FlutterActivity
* @author jzman
*/
val tag = AgentActivity::class.java.simpleName;
class AgentActivity : FlutterActivity() {
val tag = AgentActivity::class.java.simpleName;
private val channel = "com.manu.startMainActivity"
private var platform: MethodChannel? = null;
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
Log.d(tag,"configureFlutterEngine")
platform = MethodChannel(flutterEngine.dartExecutor, channel)
// 设置方法处理器
platform!!.setMethodCallHandler(StartMethodCallHandler(this@AgentActivity))
}
companion object{
/**
* 重新创建NewEngineIntentBuilder才能保证生效
*/
fun withNewEngine(): MNewEngineIntentBuilder? {
return MNewEngineIntentBuilder(AgentActivity::class.java)
}
}
/**
* 自定义NewEngineIntentBuilder
*/
class MNewEngineIntentBuilder(activityClass: Class<out FlutterActivity?>?) :
NewEngineIntentBuilder(activityClass!!)
/**
* 实现MethodCallHandler
*/
class StartMethodCallHandler(activity:Activity) : MethodChannel.MethodCallHandler{
private val context:Activity = activity
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
if ("startMainActivity" == call.method) {
Log.i(tag,"arguments:"+call.arguments)
startMainActivity(context)
// 向Flutter回调执行结果
result.success("success")
} else {
result.notImplemented()
}
}
}
}
上記のように、MethodChannel.Resultオブジェクトを使用して、実行結果をFlutterにコールバックすることもできます。Flutter側は次のとおりです。
/// State
class _PageState extends State<PageWidget> {
MethodChannel platform;
@override
void initState() {
super.initState();
platform = new MethodChannel('com.manu.startMainActivity');
}
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
margin: EdgeInsets.fromLTRB(8, 8, 8, 0),
child: RaisedButton(
onPressed: () {
_startMainActivity();
},
child: Text("Flutter to Android"),
),
);
}
/// 跳转到原生Activity
void _startMainActivity() {
platform.invokeMethod('startMainActivity', 'flutter message').then((value) {
// 接收返回的数据
print("value:$value");
}).catchError((e) {
print(e.message);
});
}
}
- AndroidはDartメソッドを呼び出します
次に、MethodChannelを介してFlutterでDartメソッドgetNameを呼び出します。Androidコードは次のとおりです。
/**
* @desc MainActivity
* @author jzman
*/
class MainActivity : FlutterActivity() {
private val tag = MainActivity::class.java.simpleName;
private val channel = "com.manu.startMainActivity"
private var methodChannel: MethodChannel? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btnGetDart.setOnClickListener {
getDartMethod()
}
}
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
Log.i(tag,"configureFlutterEngine")
methodChannel = MethodChannel(flutterEngine.dartExecutor,channel)
}
private fun getDartMethod(){
methodChannel?.invokeMethod("getName",null, object :MethodChannel.Result{
override fun success(result: Any?) {
Log.i(tag,"success: "+result.toString())
Toast.makeText(this@MainActivity,result.toString(),Toast.LENGTH_LONG).show()
}
override fun error(errorCode: String,errorMessage: String?,errorDetails: Any?) {
Log.i(tag,"error")
}
override fun notImplemented() {
Log.i(tag,"notImplemented")
}
})
}
companion object{
fun startMainActivity(context: Context) {
val intent = Intent(context, MainActivity::class.java)
context.startActivity(intent)
}
}
}
フラッター側は次のとおりです。
/// State
class _PageState extends State<PageWidget> {
MethodChannel platform;
@override
void initState() {
super.initState();
platform = new MethodChannel('com.manu.startMainActivity');
// 监听Android调用Flutter方法
platform.setMethodCallHandler(platformCallHandler);
}
@override
Widget build(BuildContext context) {
return Container();
}
/// FLutter Method
Future<dynamic> platformCallHandler(MethodCall call) async{
switch(call.method){
case "getName":
return "name from flutter";
break;
}
}
}
EventChannel
EventChannelは、主にFlutterからネイティブへの一方向の通話に使用されます。その使用法はAndroidでのブロードキャストに似ています。ネイティブのインターフェースは、イベントの送信を担当します。Flutterは、イベントを登録してリッスンできます。言うまでもなく、コードを見てください。 。Androidコードは次のとおりです。
/// Android
class MFlutterFragment : FlutterFragment() {
// 这里用Fragment,Activity也一样
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
Log.d(tag,"configureFlutterEngine")
EventChannel(flutterEngine.dartExecutor,"com.manu.event").setStreamHandler(object:
EventChannel.StreamHandler{
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
Log.i(tag,"configureFlutterEngine > onListen")
// EventSink发送事件通知
events?.success("event message")
}
override fun onCancel(arguments: Any?) {
Log.i(tag,"configureFlutterEngine > onCancel")
}
})
}
companion object{
fun withNewEngine(): NewEngineFragmentBuilder? {
return MNewEngineIntentBuilder(
MFlutterFragment::class.java
)
}
}
class MNewEngineIntentBuilder(activityClass: Class<out FlutterFragment?>?) :
NewEngineFragmentBuilder(activityClass!!)
}
フラッター側は次のとおりです。
/// State
class EventState extends State<EventChannelPage> {
EventChannel _eventChannel;
String _stringMessage;
StreamSubscription _streamSubscription;
@override
void initState() {
super.initState();
_eventChannel = EventChannel("com.manu.event");
// 监听Event事件
_streamSubscription =
_eventChannel.receiveBroadcastStream().listen((event) {
setState(() {
_stringMessage = event;
});
}, onError: (error) {
print("event error$error");
});
}
@override
void dispose() {
super.dispose();
if (_streamSubscription != null) {
_streamSubscription.cancel();
_streamSubscription = null;
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("EventChannel"),
centerTitle: true,
),
body: Center(
child: Text(_stringMessage == null ? "default" : _stringMessage),
));
}
}
上記はFlutterプラットフォームチャンネルの使用です。公式アカウントの返信キーワード[チャンネル]でソースコードを入手できます。