笔记:Android页面嵌入flutter页面 如何通信

335 阅读1分钟

通信过程
代码结构:

代码结构

这个代码结构是如何生成的呢?

开发环境:AndroidStudio3.5

在旧版中试过,只会把module导进来,就是这个:

1、新建Android工程,在命令行界面进入工程上一级,然后运行命令:

flutter create -t module flutter_module3

2、修改Android工程settings.gradle文件

include ':app'
rootProject.name='My Application'
//加入下面配置
setBinding(new Binding([gradle: this]))
evaluate(new File(
        settingsDir.parentFile,
        'flutter_module3/.android/include_flutter.groovy'
))

3、修改app下的build.gradle文件

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.core:core-ktx:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
    // 加入下面配置
    implementation project(':flutter')
}

channel总共有三种类型:MethodChannel、EventChannel、BasicMessageChannel

BasicMessageChannel用法

Android可以给flutter发送消息并且接收flutter的返回值,flutter可以给Android发送消息,但是无法接收返回值(没有找到如何接受)

核心代码: Android端

final BasicMessageChannel messageChannel = new BasicMessageChannel<>(flutterView, CHANNEL, StringCodec.INSTANCE);
        messageChannel.
                setMessageHandler(new BasicMessageChannel.MessageHandler<String>() {

                    public void onMessage(String s, BasicMessageChannel.Reply<String> reply) {
                        //接收到flutter主动发送的消息了
                        tv2.setText(s);

                        //这是回传给flutter的,但是flutter无法接收
                        reply.reply("Android已经收到消息了");
                    }
                });


        tv.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View v) {
                messageChannel.send("这是Android给你发送的消息");

                messageChannel.send("这是Android给你发送的消息",new BasicMessageChannel.Reply(){

                    @Override
                    public void reply(Object o) {
                        tv3.setText(o.toString());
                    }
                });
            }
        });

flutter端:

class HomePageBasicMessageChannel extends StatefulWidget
{
  @override
  State<StatefulWidget> createState() {
    return HomePageBasicMessageChannelState();
  }

}

class HomePageBasicMessageChannelState extends State<HomePageBasicMessageChannel>
{
  static const BasicMessageChannel<String> platform = BasicMessageChannel<String>('samples.flutter.io/basic', StringCodec());
  String result;
  String result2;
  Future<String> _handlePlatformIncrement(String message) async {
    //这儿接收Android端发送的消息
    setState(() {
      result=message;
    });
    //这是回传给Android端的,Android可以接收
    return "flutter收到消息了,这是返给你的信息";
  }


  @override
  Widget build(BuildContext context) {
    platform.setMessageHandler(_handlePlatformIncrement);
    return Scaffold(

      body: Center(
        child: Column(
          children: <Widget>[
            Text("接收到Android端发过来的信息:${result}"),
            InkWell(
              child: Text("发送消息"),
              onTap: (){
                //这儿是主动给Android发送消息的代码
                platform.send("flutter主动发送的消息");
              },
            ),
            Text("flutter主动发送消息后,Android给的返回值:${result2}")
          ],
        ),
      ),
    );
  }

}

EventChannel使用

感觉更像是一个观察者模式的运用,当flutter想要监听的事件发生变化后(比如网络变化、电量变化),Android会主动发送事件给flutter,比如说flutter想要实时获取电量的变化,如果使用EventChannel的话就不需要去轮询了

核心代码:

Android端:

new EventChannel(flutterView, "samples.flutter.io/charging").setStreamHandler(
                new EventChannel.StreamHandler() {
                    // 接收电池广播的BroadcastReceiver。
                    private BroadcastReceiver chargingStateChangeReceiver;
                    @Override
                    // 这个onListen是Flutter端开始监听这个channel时的回调,第二个参数 EventSink是用来传数据的载体。
                    public void onListen(Object arguments, EventChannel.EventSink events) {
                        globaleEvents=events;
                        chargingStateChangeReceiver = createChargingStateChangeReceiver(events);
                        registerReceiver(
                                chargingStateChangeReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
                    }

                    @Override
                    public void onCancel(Object arguments) {
                        // 对面不再接收
                        unregisterReceiver(chargingStateChangeReceiver);
                        chargingStateChangeReceiver = null;
                    }
                }
        );

        tv2.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View v) {
                //手动模拟电量发生了变化
                if(globaleEvents!=null)
                {
                    globaleEvents.success("电量变化了啊:"+ new Random().nextInt(20));
                }
            }
        });
/**
     * 这是监听系统电量发生变化的广播
     * @param events
     * @return
     */
    private BroadcastReceiver createChargingStateChangeReceiver(final EventChannel.EventSink events) {
        return new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);

                if (status == BatteryManager.BATTERY_STATUS_UNKNOWN) {
                    events.error("UNAVAILABLE", "Charging status unavailable", null);
                } else {
                    boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
                            status == BatteryManager.BATTERY_STATUS_FULL;
                    // 把电池状态发给Flutter
                    events.success(isCharging ? "charging" : "discharging");
                }
            }
        };
    }

flutter 端:

class HomePageEventState extends State<HomePageEvent>
{
  static const EventChannel eventChannel = const EventChannel('samples.flutter.io/charging');

  String _chargingStatus;
  @override
  void initState() {
    super.initState();
    eventChannel.receiveBroadcastStream().listen(_onEvent, onError: _onError);
  }

  //这儿是接收Android端发送来的消息
  void _onEvent(Object event) {
    setState(() {
//      _chargingStatus =
//      "Battery status: ${event == 'charging' ? '' : 'dis'}charging.";
    _chargingStatus=event.toString();
    });
  }

  void _onError(Object error) {
    setState(() {
      _chargingStatus = 'Battery status: unknown.';
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text("${_chargingStatus}"),
      ),
    );
  }

}

MethodChannel

MethodChannel更像是用来互相调用对方的方法,Android调用flutter的方法时,可以传入参数,flutter调用Android的方法时,没有找到传参的地方,Android端和flutter端使用的方法都是相近的

核心代码: Android端

final MethodChannel channel=new MethodChannel(flutterView, CHANNEL);
        channel.setMethodCallHandler(
                new MethodChannel.MethodCallHandler() {
                    @Override
                    public void onMethodCall(MethodCall call, MethodChannel.Result result) {
                        // 在这个回调里处理从Flutter来的调用

                        if (call.method.equals("getBatteryLevel")) {
                            int batteryLevel = getBatteryLevel();

                            if (batteryLevel != -1) {
                                result.success(batteryLevel);
                            } else {
                                result.error("UNAVAILABLE", "Battery level not available.", null);
                            }
                        } else {
                            result.notImplemented();
                        }



                    }
                });


        tv.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View v) {
                //这三个参数不要写错,无语,arguments应该可以携带参数
                channel.invokeMethod("getName","abc",new MethodChannel.Result(){

                    @Override
                    public void success(Object o) {

                        Toast.makeText(MainActivity.this,o.toString(),Toast.LENGTH_LONG).show();
                    }

                    @Override
                    public void error(String s, String s1, Object o) {

                    }

                    @Override
                    public void notImplemented() {

                    }
                });
            }
        });
private int getBatteryLevel() {
        int batteryLevel = -1;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            BatteryManager batteryManager = (BatteryManager) getSystemService(BATTERY_SERVICE);
            batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
        } else {
            Intent intent = new ContextWrapper(getApplicationContext()).
                    registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
            batteryLevel = (intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100) /
                    intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
        }

        return batteryLevel;
    }

flutter端:

class _MyHomePageState extends State<HomePage>
{
  MethodChannel  platform = const MethodChannel('samples.flutter.io/battery');
  
  String _batteryLevel = 'Unknown battery level.';

  Future<Null> _getBatteryLevel() async {
    String batteryLevel;
    try {
      final int result = await platform.invokeMethod('getBatteryLevel');
      batteryLevel = 'Battery level at $result % .';
    } on PlatformException catch (e) {
      batteryLevel = "Failed to get battery level: '${e.message}'.";
    }

    setState(() {
      _batteryLevel = batteryLevel;
    });
  }

  Future<dynamic> platformCallHandler(MethodCall call) async {
    //call.method是获取方法名,call.arguments是获取方法参数
    switch (call.method) {
      case "getName":
        return "Hello from Flutter:${call.arguments}";
        break;
    }
  }



  @override
  Widget build(BuildContext context) {
    //为了使原生也可以调用到flutter中的方法
    platform.setMethodCallHandler(platformCallHandler);
    // TODO: implement build
    return Scaffold(
      body: Center(
        child:Column(
          children: <Widget>[
            Text("电量:${_batteryLevel}"),

            IconButton(
                icon: Icon(Icons.ac_unit), onPressed: (){
              _getBatteryLevel();
            },
              tooltip: "获取电量",

            )

          ],
        )

      ),
    );
  }

}