Flutter 原生通信 (一) - flutter调用Android

原生通信系列

1. Flutter 调用 Android
2. Android 通知 Flutter
3. Flutter 调用 iOS
4. iOS 通知 Flutter

项目地址


在 flutter 开发中一定会有需要和原生通信的情况

第一篇介绍的是 flutter 调用 Android

这篇是给刚刚入门或者刚刚接触原生调用的朋友们使用的,老鸟们或者英文强的朋友还是直接看官方文档比较好

创建项目

一般来说建议使用一个 plugin 作为一个单独的项目来将业务逻辑独立出去

我这里使用命令行创建,事实上一律建议使用命令行创建,因为信息更加可见一些

flutter create --template plugin  battle_power
cd battle_power

前面都是固定格式,最后面那个是插件名,根据你自己的需要来修改

创建好的截图如下
Flutter 原生通信 (一) - flutter调用Android_第1张图片

和开发 package 的时候不同,开发 plugin 需要打开 example/android 目录

Flutter 原生通信 (一) - flutter调用Android_第2张图片

使用快捷的方式,或自己通过 Android Studio 的 open 打开项目

Flutter 原生通信 (一) - flutter调用Android_第3张图片
等待完成

Flutter 原生通信 (一) - flutter调用Android_第4张图片
接着就可以开始开发了,

默认生成了一个 java 文件,可以称之为插件的主文件

流程图

Flutter 原生通信 (一) - flutter调用Android_第5张图片

乱画的…随便看看就好

android 端

package com.example.battlepower;

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;
import io.flutter.plugin.common.PluginRegistry.Registrar;

/** BattlePowerPlugin */
public class BattlePowerPlugin implements MethodCallHandler {
  /** Plugin registration. */
  public static void registerWith(Registrar registrar) {
    final MethodChannel channel = new MethodChannel(registrar.messenger(), "battle_power"); //这里对应dart端的 MethodChannel
    channel.setMethodCallHandler(new BattlePowerPlugin());
  }

  @Override
  public void onMethodCall(MethodCall call, Result result) {
    if (call.method.equals("getPlatformVersion")) { // 对应dart端 invoceMethod
      result.success("Android " + android.os.Build.VERSION.RELEASE);
    } else {
      result.notImplemented();
    }
  }
}

当然如果你对于 kotlin 比较喜欢也可以使用 kotlin 进行插件开发

如果你不会 Java/Kotlin ,甚至不会原生开发,只能说你进入了一个全新的领域,希望你一切都好吧…,建议你先系统的学习下 android 再来

dart 端

import 'dart:async';

import 'package:flutter/services.dart';

class BattlePower {
  static const MethodChannel _channel =
      const MethodChannel('battle_power');

  static Future get platformVersion async {
    final String version = await _channel.invokeMethod('getPlatformVersion');
    return version;
  }
}

dart 端和 java 端是一一对应的

交互

调用

由 dart 端使用_channel.invokeMethod调用,这个方法的参数是方法名和一个可选参数

返回值是一个Future 因为 java 端的调用是不可预知的,所以是异步的

换句话说,无论结果是对是错你在 java 端都需要有返回值,否则 dart 端会挂起

查看 java 端文档

Flutter 原生通信 (一) - flutter调用Android_第6张图片

可选参数

可选参数是 dart 中的一个语法特点,方法的签名中通过[]包裹的为匿名可选参数,通过{}包裹的为命名可选参数

而 channel 中的这个方法的完整实现如下

结果返回

查看文档

Flutter 原生通信 (一) - flutter调用Android_第7张图片

不同于传统的同步方法调用,java 端需要使用result.success(object)来返回一个结果给 dart

使用result.notImplemented();来表示未定义的方法,dart 端会接收到一个异常

返回一个错误result.error(String code,String msg,Throwable throwable)

调用过程分析

  Future invokeMethod(String method, [dynamic arguments]) async {
    assert(method != null);
    final dynamic result = await BinaryMessages.send(
      name,
      codec.encodeMethodCall(MethodCall(method, arguments)),
    );
    if (result == null)
      throw MissingPluginException('No implementation found for method $method on channel $name');
    return codec.decodeEnvelope(result);
  }

method 是必填参数, 这个和 java 端的监听一一对应

第二个是一个可选一个参数,这个参数可传递任意参数,但只能有一个,然后会通过内部的 codec 进行编码后传递给 native 端,这个 codec 对象是创建MethodChannel时创建的
Flutter 原生通信 (一) - flutter调用Android_第8张图片
有一个默认类型为StandardMethodCodec,这个类型后面会解析,先略过


  public static void registerWith(Registrar registrar) {
    final MethodChannel channel = new MethodChannel(registrar.messenger(), "battle_power");
    channel.setMethodCallHandler(new BattlePowerPlugin());
  }

在 java 端使用这类代码来注册插件


  @Override
  public void onMethodCall(MethodCall call, Result result) {
    if (call.method.equals("getPlatformVersion")) {
      result.success("Android " + android.os.Build.VERSION.RELEASE);
    } else {
      result.notImplemented();
    }
  }

这里的代码是用来监听回调的,当 dart 调用invokeMethod这里会被触发

比如getPlatformVersion是一个没有传参数的方法, 直接返回了 Android os 对应的版本号

这样 dart 在 java 端result.success调用后就会 返回版本号

StandardMethodCodec 解析

这个类也是在两端都有的一个类, 通常来说就是作为发送端负责编码, 作为接受端负责解码

作为一个内置类,其中做了一些"自动"的转码过程,将原生类型映射为 dart 类型 或者反过来映射

查看文档

Flutter 原生通信 (一) - flutter调用Android_第9张图片

这里代表了基础的映射关系 也就是说 你在 invokeMethod 时,参数会被映射为右边的原生类型
如果这里没有的类型就是不支持的类型,建议不要使用,否则会抛出无法解码的异常

当然有正向映射,也会有对应的反向映射,也就是说, 你在 java 中作为结果返回的类型在 dart 端也会被映射为 dart 对应类型

当然这个编解码器也可以自定义,基于二进制扩展即可,不过这个不属于基础的应用篇,暂时先不做

自定义

前面是自动生成的方法和签名

现在自己添加一个带参数的方法

dart

  static Future requestNativeAdd(int x, int y) async {
    int result = await _channel.invokeMethod('add', {"x": x, "y": y});
    return result;
  }

java

    @Override
    public void onMethodCall(MethodCall call, Result result) {
        switch (call.method) {
            case "getPlatformVersion":
                result.success("Android " + android.os.Build.VERSION.RELEASE);
                break;
            case "add":
                Integer x = call.argument("x");
                Integer y = call.argument("y");
                if (x != null && y != null) {
                    result.success(x + y);
                } else {
                    result.error("1", "不能为空", null);
                }
                break;
            default:
                result.notImplemented();
                break;
        }
    }

方法很简单,传入一个 x 一个 y,然后 java 端加完返回回来

这样一个简单的自定义就完成了


你以为就这样结束了?

请看第二篇 android 通知 flutter

你可能感兴趣的:(flutter)