Flutterシリーズのプラットフォームチャネルの使用に関する詳細な説明

PS:多くの場合、既知の影響の80%は、考えられる原因の20%に起因します。

以前の記事では、ナビゲーターコンポーネント、Flexレイアウト、画像の読み込み、ウィジェットのライフサイクル、ハイブリッド開発など、Flutter開発の基本を紹介しました。記事は次のとおりです。

以下に、Flutterハイブリッド開発でのプラットフォームチャネルの使用について紹介します。主な内容は次のとおりです。

  1. プラットフォームチャネルの紹介
  2. プラットフォームのデータ型の比較
  3. BasicMessageChannel
  4. MethodChannel
  5. 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リソースファイルを使用する場合を実現します。重要なプロセスは次のとおりです。次のように:

  1. Flutter側は、画像リソースに対応するバイナリデータを取得します。ここではBinaryCodecが使用され、データ形式はByteDataです。
  2. BasicMessageChannelを使用して、画像に対応するデータを送信します。
  3. 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。次のように、同じチャネル識別子を使用する必要があります。

  1. 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);
    });
  }
}
  1. 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プラットフォームチャンネルの使用です公式アカウントの返信キーワード[チャンネル]でソースコードを入手できます

おすすめ

転載: blog.csdn.net/jzman/article/details/114242678