原生通信系列
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
前面都是固定格式,最后面那个是插件名,根据你自己的需要来修改
和开发 package 的时候不同,开发 plugin 需要打开 example/android
目录
使用快捷的方式,或自己通过 Android Studio 的 open 打开项目
默认生成了一个 java 文件,可以称之为插件的主文件
乱画的…随便看看就好
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 再来
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 端文档
可选参数是 dart 中的一个语法特点,方法的签名中通过[]包裹的为匿名可选参数,通过{}包裹的为命名可选参数
而 channel 中的这个方法的完整实现如下
查看文档
不同于传统的同步方法调用,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
时创建的
有一个默认类型为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
调用后就会 返回版本号
这个类也是在两端都有的一个类, 通常来说就是作为发送端负责编码, 作为接受端负责解码
作为一个内置类,其中做了一些"自动"的转码过程,将原生类型映射为 dart 类型 或者反过来映射
查看文档
这里代表了基础的映射关系 也就是说 你在 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