Explicación detallada del uso del Platform Channel de la serie Flutter

PD: En muchas situaciones, el 80% de los efectos conocidos se derivan del 20% de las posibles causas.

Los artículos anteriores introdujeron los conceptos básicos del desarrollo de Flutter, como los componentes de Navigator, el diseño Flex, la carga de imágenes, el ciclo de vida del widget y el desarrollo híbrido. Los artículos son los siguientes:

A continuación se presenta el uso de Platform Channel en el desarrollo híbrido de Flutter. Los contenidos principales son los siguientes:

  1. Introducción al canal de la plataforma
  2. Comparación del tipo de datos de la plataforma
  3. BasicMessageChannel
  4. MethodChannel
  5. EventChannel

Introducción al canal de la plataforma

El canal de plataforma es un canal de mensajes asíncrono. El mensaje se codificará en un mensaje binario antes de enviarse, y el mensaje binario recibido se decodificará en un valor de Dart. El tipo de mensaje que transmite solo puede ser el valor admitido por el decodificador correspondiente, y todas las decodificaciones son Todos los dispositivos admiten mensajes vacíos, y la arquitectura de comunicación entre Native y Flutter se muestra en la siguiente figura:

En Flutter se definen tres tipos diferentes de PlatformChannel, los tres principales son los siguientes:

  • BasicMessageChannel: utilizado para la transmisión de datos;
  • MethodChannel: se utiliza para transferir llamadas a métodos;
  • EventChannel: utilizado para entregar eventos;

Su método de construcción necesita especificar un identificador de canal, decodificador y BinaryMessenger. BinaryMessenger es una herramienta de comunicación entre Flutter y la plataforma, utilizada para transferir datos binarios, configurar el procesador de mensajes correspondiente, etc.

Hay dos códecs: MethodCodec y MessageCodec. El primero corresponde al método y el segundo corresponde al mensaje. BasicMessageChannel usa MessageCodec, y MethodChannel y EventChannel usan MethodCodec.

Comparación del tipo de datos de la plataforma

Platform Channel proporciona diferentes mecanismos de decodificación de mensajes. Por ejemplo, StandardMessageCodec proporciona decodificación básica de tipos de datos, JSONMessageCodec admite decodificación Json, etc., que se convierten automáticamente cuando se comunican entre plataformas. Los tipos de datos de cada plataforma se comparan de la siguiente manera:

BasicMessageChannel

BasicMessageChannel se utiliza principalmente para la transferencia de datos, incluidos datos binarios. Con la ayuda de BasicMessageChannel, se pueden realizar las funciones de MethodChannel y EventChannel. Aquí, BasicMessageChannel se utiliza para realizar el caso de utilizar archivos de recursos de Flutter en proyectos de Android. El proceso clave es como sigue:

  1. El lado Flutter obtiene los datos binarios correspondientes al recurso de imagen. Aquí se usa BinaryCodec, y el formato de datos es ByteData;
  2. Utilice BasicMessageChannel para enviar los datos correspondientes a la imagen;
  3. Use ByteBuffer en el lado de Android para recibir, conviértalo en ByteArray y luego analícelo en Bitmap y muéstrelo.

El código clave en el lado de Flutter es el siguiente:

// 创建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);
}

El código clave en el lado de Android es el siguiente:

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)

Además, BasicMessageChannel combinado con BinaryCodec admite la transferencia de grandes bloques de datos de memoria.

MethodChannel

MethodChannel se utiliza principalmente para transferir métodos. Los métodos naturales y los métodos Dart se pueden pasar de forma natural. Es decir, puedes llamar a los métodos nativos de Android en Flutter a través de MethodChannel y llamar a los métodos Dart en Android. Todas las llamadas mutuas se llaman a través del método invokeMethod de MethodChannel. Se debe utilizar el mismo identificador de canal, de la siguiente manera:

  1. Flutter llama a métodos de Android

Usemos MethodChannel para realizar el salto de Flutter a la interfaz nativa MainActivity de Android. El lado de Android es el siguiente:

/**
 * @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()
            }
        }
    }
}

Como arriba, también puedes usar el objeto MethodChannel.Result para devolver el resultado de la ejecución a Flutter. El lado de Flutter es el siguiente:

/// 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 llama al método Dart

A continuación, llame al método Dart getName en Flutter a través de MethodChannel, el código de Android es el siguiente:

/**
 * @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)
        }
    }
}

El lado Flutter es el siguiente:

/// 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 se usa principalmente para llamadas unidireccionales de Flutter al nativo. Su uso es similar al de la transmisión en Android. La interfaz nativa es responsable de enviar el evento. Flutter puede registrarse y escucharlo. Sin mencionar, solo mire el código . El código de Android es el siguiente:

/// 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!!)
}

El lado Flutter es el siguiente:

/// 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),
        ));
  }
}

Lo anterior es el uso del canal de la plataforma Flutter. Puedes obtener el código fuente en la palabra clave de respuesta [Canal] de la cuenta oficial .

Supongo que te gusta

Origin blog.csdn.net/jzman/article/details/114242678
Recomendado
Clasificación