Flutter-填平菜鸟和高手之间的沟壑
准备写作中...
1、Flutter-skia-影像,Flutter skia-图形渲染层、应用渲染层
2、方法通道使用示例,用于演示如何使用方法通道实现与原生代码的交互
需求:提示用户跳转到应用市场去评分
在实际业务中,提示用户跳转到应用市场(iOS 为 App Store、Android 则为各类手机应用市场)去评分是一个高频需求,考虑到 Flutter 并未提供这样的接口,而跳转方式在 Android 和 iOS 上各不相同,因此我们需要分别在 Android 和 iOS 上实现这样的功能,并暴露给 Dart 相关的接口。
我们先来看看作为客户端的 Flutter,怎样实现一次方法调用请求,实际上与调用一个 Dart 对象的方法完全一样。
(1)首先,我们需要确定一个唯一的字符串标识符,来构造一个命名通道;
(2)然后,在这个通道之上,Flutter 通过指定方法名“openAppMarket”来发起一次方法调用请求。
(3)最后,因为方法调用过程是异步的,需要用非阻塞(或者注册回调)方式来等待原生代码给予响应。
3、把发起方法调用请求的语句用 try-catch 包装起来,处理异常
需要注意的是,与网络调用类似,方法调用请求有可能会失败(比如,Flutter 发起了原生代码不支持的 API 调用,或是调用过程出错等),因此我们需要把发起方法调用请求的语句用 try-catch 包装起来。
//声明MethodChannel
const platform = MethodChannel('samples.chenhang/utils');
//处理按钮点击
handleButtonClick() async {
int result;
//异常捕获
try {
//异步等待方法通道的调用结果
result = await platform.invokeMethod('openAppMarket');
} catch (e) {
result = -1;
}
print("Result:$result");
}
4、分别在 Android 和 iOS 两个平台上完成对应的接口实现,在原生代码中完成方法调用的响应
调用方的实现搞定了,接下来就需要在原生代码宿主中完成方法调用的响应实现了。由于我们需要适配 Android 和 iOS 两个平台,所以我们分别需要在两个平台上完成对应的接口实现。
首先,我们来看看 Android 端的实现方式。
(1)在上一小结最后我提到,在 Android 平台,方法调用的处理和响应是在 Flutter 应用的入口,也就是在 MainActivity 中的 FlutterView 里实现的,因此我们需要打开 Flutter 的 Android 宿主 App,找到 MainActivity.java 文件,并在其中添加相关的逻辑。
A、用 AS 打开 Flutter 项目 flutter_app_top_tab_03
B、然后,在 Flutter 项目 flutter_app_top_tab_03 中,右击该项目的 android 子项目选择用 Android 打开。如果直接在 Flutter 项目中编写安卓代码,会有许多红线报错,也没有安卓命令提示、无法用 Ctrl + Alt + L 进行代码格式化
(2)调用方与响应方都是通过命名通道进行信息交互的,所以我们需要在 onCreate 方法中,创建一个与调用方 Flutter 所使用的通道名称一样的 MethodChannel,并在其中设置方法处理回调,响应 openAppMarket 方法,打开应用市场的 Intent。
(3)同样地,考虑到打开应用市场的过程可能会出错,我们也需要增加 try-catch 来捕获可能的异常:
r:FlutterProjectFlutterProject3526_native_methodandroidappsrcmainjavacomexample
ative_methodMainActivity.java
文件内容:
package com.hangchen.native_method;
import android.os.Bundle;
import io.flutter.app.FlutterActivity;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.GeneratedPluginRegistrant;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
new MethodChannel(getFlutterView(), "samples.chenhang/navigation").setMethodCallHandler(
new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
// Note: this method is invoked on the main thread.
if(call.method.equals("openAppStore")) {
try {
Uri uri = Uri.parse("market://details?id=com.tencent.mm");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} catch (Exception e) {
result.error("UNAVAILABLE", "没有安装应用市场", null);
}
}
else {
result.notImplemented();
}
}
});
}
}
5、在 Flutter 应用中通过调用 openAppMarket 方法,实现打开应用市场的功能,
需要注意的是,在 Flutter 使用方法通道进行方法调用和原生代码返回处理结果的过程中,存在传输信息的序列化和反序列化。
接下来,我们就可以在 Flutter 应用里,通过调用 openAppMarket 方法,实现打开不同操作系统提供的应用市场功能了。
需要注意的是,在原生代码处理完毕后将处理结果返回给 Flutter 时,我们在 Dart、Android 和 iOS 分别用了三种数据类型:
Android 端返回的是 java.lang.Integer、
iOS 端返回的是 NSNumber、
Dart 端接收到返回结果时又变成了 int 类型。
这是为什么呢?这是因为在使用方法通道进行方法调用时,由于涉及到跨系统数据交互,Flutter 会使用 StandardMessageCodec 对通道中传输的信息进行类似 JSON 的二进制序列化,以标准化数据传输行为。这样在我们发送或者接收数据时,这些数据就会根据各自系统预定的规则自动进行序列化和反序列化。
看到这里,你是不是对这样类似网络调用的方法通道技术有了更深刻的印象呢。对于上面提到的例子,类型为 java.lang.Integer 或 NSNumber 的返回值,先是被序列化成了一段二进制格式的数据在通道中传输,然后当该数据传递到 Flutter 后,又被反序列化成了 Dart 语言中的 int 类型的数据。
关于 Android、iOS 和 Dart 平台间的常见数据类型转换,我总结成了下面一张表格,帮助你理解与记忆。你只要记住,像 null、布尔、整型、字符串、数组和字典这些基本类型,是可以在各个平台之间以平台定义的规则去混用的,就可以了。