目录
此篇可随意转载!Update 2020.10.27
前言
经过上一章的学习,大家对flutter plugin开发有了基本认知。但是大家要清醒的认识到自定义插件开发涉及基础知识较多,因此本节我帮助大家有针对性的补充涉及到的基础知识。
Flutter架构
我们从上往下看,找找我们需要补全的知识。
1. Framework/dart层
我们在这一层经常使用async和await来实现异步UI/数据流,比如上一章的这段代码:
Future<void> initPlatformState() async {
Map<String, dynamic> deviceData;
try {
if (Platform.isAndroid) {
deviceData = _readAndroidBuildData(await deviceInfoPlugin.androidInfo);
} else if (Platform.isIOS) {
deviceData = _readIosDeviceInfo(await deviceInfoPlugin.iosInfo);
}
} on PlatformException {
deviceData = <String, dynamic>{
'Error:': 'Failed to get platform version.'
};
}
if (!mounted) return;
setState(() {
_deviceData = deviceData;
});
}
注意: 这里的async、await是dart语法糖,符合ES6标准写法。可以跟Future,Promise配合使用。但是它在dart语言内部是用协程实现的,通过CPU中断–>保留上下文–>在新上下文中执行代码–>返回保留上下文 完成异步功能。重要的是:它并没有新建线程,这点和Java是很不同的。
2. Flutter Engine
上面我们知道了在flutter中做异步UI/数据流的一般方法。假如有个需求要定时和Android通讯,那应该怎么弄呢?
在Android和iOS中,Embedder层中会为每个app实例创建UI、GPU、IO 三个Runner。而所有实例共享Platform Runner。这些Runner的引用会被FlutterEngine对象保存起来。
我们的代码默认运行在DartVM 的Root isolate,它通过Engine内的引用跟UI、GPU、IO、platform四个底层Runner交互。当我们需要定时去跟系统通讯的时候,考虑到阻塞问题,不能直接在Root isolate中操作,应该在DartVM中建立自己的isolate。比如下面这个例子:
import 'dart:async';
import 'dart:isolate';
main(List<String> args) {
start();
print("start");
}
Isolate isolate;
int i = 1;
void start() async {
//接收消息的主Isolate的端口
final receive = ReceivePort();
isolate = await Isolate.spawn(runTimer, receive.sendPort);
receive.listen((data) {
print("Reveived : $data ; i :$i");
});
}
void runTimer(SendPort port) {
int counter = 0;
Timer.periodic(const Duration(seconds: 1), (_) {
counter++;
i++;
final msg = "Notification $counter";
print("Send :$msg ;i :$i");
port.send(msg);
});
}
3. Flutter的启动过程
flutter的启动过程主要有2大步骤(以目前新版1.12.13为例):
1.FlutterApplication启动,这一步对应AndroidManifest.xml里面的application标签。可以在Android Studio里面一步步跟踪它的启动过程。它的主要作用是加载flutter.so、加载Assets资源。
2. FlutterActivity启动,对应AndroidManifest.xml里面的activity标签。它主要作用是启动View,启动Flutter Engine,启动dart VM并关联底层Runner。
Flutter升级(1.12+)
注意:务必详细阅读此文档,因为你看到的教程可能在使用旧的实现。需要仔细看这篇升级的issue讨论,flutter开发者阐述了一些flutter升级的可能的问题和解决思路。
Flutter Null Safety升级
可以看到Null类型已经不属于其他类型了。所以,给一个List对象传递一个Null是会报类型错误的。看看引入了Null Safety约束后编码有什么不同:
class A {
String? firstName; //可空的成员变量
int getNameLen(String? lastName /*可空的参数*/) {
int firstLen = firstName?.length ?? 0;
int lastLen = lastName?.length ?? 0;
return firstLen + lastLen;
}
}
在变量声明,形参,访问的时候都需要带上”?”,表示这个变量是可以为空的。
如果要让变量不为空,要像如下声明:
class B {
List names=[];//定义时初始化
final List colors;//在构造方法中初始化
late List urls;//延时初始化
CommonModel(this.colors);
...
定义时要么直接初始化,要么在构造函数初始化,要么声明为“late”。比如flutter的初始化函数“initState
”。
解决Flutter依赖国外maven仓库问题
网上普遍说换掉google()、jcenter() 改为国内镜像仓库,如下:
repositories {
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/jcenter' }
maven { url 'https://maven.aliyun.com/nexus/content/groups/public' }
}
但是,如果你的项目用了第三方plugins,它们内部会依赖的国外的maven仓库。因此我们只能使用proxy去访问海外仓库,在项目根目录gradle.properties中增加以下配置:
org.gradle.jvmargs=-Xmx1536M -DsocksProxyHost=xx.xx.xx.xx -DsocksProxyPort=1080
systemProp.socks.proxyHost=xx.xx.xx.xx
systemProp.socks.proxyPort=1080
解决Gradle版本号问题
一共有2种方法
- 对齐android/build.gradle 和android/gradle/wrapper/gradle-wrapper.properties 中的gradle版本和插件版本号。
- 重新建一个项目,Android Studio 安装后它们的版本是默认对齐的。
- 最好升级到最新的版本,避免warning。
Flutter提速的本地修改
git: M packages/flutter_tools/gradle/flutter.gradle
git: M packages/flutter_tools/gradle/resolve_dependencies.gradle
git: M packages/flutter_tools/lib/src/http_host_validator.dart