在此之前先推荐看大佬的:填坑指导
iOS需要注意:
1、flutter2.0要求cocoapods 升级到1.9.0
详情看这篇博客https://blog.csdn.net/sinat_31177681/article/details/51363495
2、原来flutter项目中的podfile文件是旧版本的ccocoapods了,删除podfile和对应的.lock,然后flutter项目重新运行使用它自动生成的podfile文件
3、安装CocoaPods
卸载cocoapods:sudo gem uninstall cocoapods
查看cocoapods版本:pod --version
指定版本安装:
sudo gem install -n /usr/local/bin cocoapods -v 1.9.3(新MacOS系统升级)
不指定版本安装
sudo gem install -n /usr/local/bin cocoapods
说明:老项目sdk1.17.0===>升级到2.0.1,当前所有操作基于win平台
(一)项目正式开始:
1. 直接在SDK的安装目录运行命令
//第一步
git reset --hard c5a4b4029c0798f37c4a39b479d7cb75daa7b05c
//第二步
flutter doctor
到此为止环境已经准备妥当,正式进入项目修改。
2. 修改pubspec.yarm插件依赖
所有的插件都要适配到空安全,插件是否支持均会有对应说明Null safety,适配过程不确定版本的话,可以使用dio: any,适配完事后再在pubspec.lock文件中查看具体的版本修改过来,实在有部分插件没有支持的,参考下面
dependency_overrides:
intl: ^0.17.0
部分插件在适配空安全的版本放弃维护了,得自行更新或寻找替代,如:flutter_swiper变为flutter_swiper_null_safety,插件更新后要注意项目中的用法是否需要更新
2.1 部分插件解决方案
2.1.1:以前采用的是provide插件共享全局数据,现在变化为provider,用法改变,点击参考,以防文章丢失,我重复一遍:
- provide 入口
void main() {
//顶层依赖
var counter = Counter();
var providers = Provider();
providers
..(Provider.value(counter))
runApp(ProviderNode(child: MyApp(), providers: providers));
}
- provider 入口
class MyApp extends StatelessWidget {
var counter = Counter();
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
//这里是关键注册通知
ChangeNotifierProvider(builder: (_) => counter),
],
child:Text('xxx')
);
}
}
使用:
- provide
Provide.value(context) .increment(调一下里面的方法。。这里也可以传参数进去只需要在 Counter 里面的 increment 里面写两个接受参数的就好);
- provider
Provider.of(context, listen: false).increment(这里也可以传参数);
比如:
#注释掉的是我们”provide“ 的写法,这里主要是从我们建立的model里面取Id,因为Id是变化的。
var formData = {
"categoryId": Provider.of(context).categoryId,
//Provide.value(context).categoryId,
"categorySubId": categorySubId,
"page": 1
};
- provide
return Provide(builder: (context, child, data) {
data.//也能点出我们设置好值
}
- provider
final counter = Provider.of(context);
return Container(
counter.//点出我们在model里面设置的值了
);
// 在使用 provider的时候我们要注意了一定要设置listen的Bool值就是这样
await Provider.of(context, listen: false).getGoodsInfo(goodsId);
2.1.2:dio版本升级到4.0.0最新版后,部分用法改变
- 原来
final Dio _dio = new Dio(options)
..interceptors.add(
InterceptorsWrapper(onRequest: (RequestOptions options) {
// 在请求被发送之前做一些事情
options.headers['access-token'] = 'token';
options.headers['last-stamp'] = '123';
return options;
}, onResponse: (Response response) async {
// 在返回响应数据之前做一些预处理
Fetch.onResponse(response);
return response;
}, onError: (DioError e) {
// 当请求失败时做一些预处理
Fetch.onError(e);
return e;
}),
)
..interceptors.add(LogInterceptor(
request: false,
requestHeader: true,
responseHeader: true,
responseBody: true,
requestBody: true));
class Fetch{
static void onResponse(response) async {
if (response.request.method == 'POST') {
// 做一些操作
}
}
}
- 现在
final Dio _dio = new Dio(options)
..interceptors.add(
InterceptorsWrapper(onRequest: (RequestOptions options,requestInterceptorHandler) {
// 在请求被发送之前做一些事情
options.headers['access-token'] = 'token';
options.headers['last-stamp'] = '123';
return requestInterceptorHandler.next(options);
}, onResponse: (Response response,responseInterceptorHandler) async {
// 在返回响应数据之前做一些预处理
Fetch.onResponse(response);
return responseInterceptorHandler.next(response);
}, onError: (DioError e,errorInterceptorHandler) {
// 当请求失败时做一些预处理
Fetch.onError(e);
return errorInterceptorHandler.next(e);
}),
)
..interceptors.add(LogInterceptor(
request: false,
requestHeader: true,
responseHeader: true,
responseBody: true,
requestBody: true));
class Fetch{
static void onResponse(response) async {
if (response.requestOptions.method == 'POST') {
// 做一些操作
}
}
}
2.2 部分报错
2.2.1
解决方案:打开android目录下的app文件夹下的AndroidManifest.xml文件,在activity标签的下面增加如下代码:
2.2.2
Missing concrete implementations of 'CupertinoLocalizations.tabSemanticsLabel', 'getter CupertinoLocalizations.modalBarrierDismissLabel', 'getter CupertinoLocalizations.searchTextFieldPlaceholderLabel', 'getter CupertinoLocalizations.timerPickerHourLabels', and 2 more.
Try implementing the missing methods, or make the class abstract.
解决方案:
// 当前类下添加覆盖方法
@override
String get modalBarrierDismissLabel => throw UnimplementedError();
@override
String get searchTextFieldPlaceholderLabel => throw UnimplementedError();
@override
String tabSemanticsLabel({int tabIndex, int tabCount}) {
throw UnimplementedError();
}
@override
List get timerPickerHourLabels => throw UnimplementedError();
@override
List get timerPickerMinuteLabels => throw UnimplementedError();
@override
List get timerPickerSecondLabels => throw UnimplementedError();
2.2.3
The argument type 'Duration' can't be assigned to the parameter type 'Future
'
解决方案:
future: entity.videoDuration,
更换为 Future.delayed(Duration(seconds: 0)),
2.2.4
The method 'inheritFromWidgetOfExactType' isn't defined for the type 'BuildContext'.
Try correcting the name to the name of an existing method, or defining a method named 'inheritFromWidgetOfExactType'
解决方案:
context.inheritFromWidgetOfExactType(ConfigProvider);
更换为 static ConfigProvider of(BuildContext context) =>
context.dependOnInheritedWidgetOfExactType(aspect:ConfigProvider);
2.2.5
The named parameter 'resizeToAvoidBottomPadding' isn't defined.
Try correcting the name to an existing named parameter's name, or defining a named parameter with the name 'resizeToAvoidBottomPadding'
解决方案:
resizeToAvoidBottomPadding: false,
更换为 resizeToAvoidBottomInset: false,
2.2.6
pin_input_text_field新版用法:
The named parameter 'enteredColor' isn't defined.
Try correcting the name to an existing named parameter's name, or defining a named parameter with the name 'enteredColor'
解决方案:
PinDecoration _pinDecoration = UnderlineDecoration(
lineHeight: 1.0,
enteredColor: Color(0xffe5e5e5),
color: Color(0xffe5e5e5));
)
更换enteredColor、color为:
colorBuilder:FixedColorBuilder(Color(0xffe5e5e5)
2.2.7
The method 'PinEditingController' isn't defined for the type '_CodeLoginState'.
Try correcting the name to the name of an existing method, or defining a method named 'PinEditingController'
解决方案:
//原来定义的方式
PinEditingController _pinEditingController = PinEditingController(
pinLength: _pinLength,
autoDispose: false,
);
更换为
TextEditingController _pinEditingController = TextEditingController(text: '');
使用的地方将pinEditingController换为controller,将inputFormatter换为inputFormatters
2.2.8
SliverOverlapAbsorber 组件child 属性移除,换新属性;
The named parameter 'child' isn't defined.
Try correcting the name to an existing named parameter's name, or defining a named parameter with the name 'child'
解决方案:child 换为sliver
2.2.8.1
uses-sdk:minSdkVersion 17 cannot be smaller than version 18 declared in library
解决方案:项目目录下: android--app-build.gradle --minSdkVersion改为:18 或者19
2.2.8.2
Publishable packages can't have path dependencies.
Try adding a 'publish_to: none' entry to mark the package as not for publishing or remove the path dependency
解决方案:在pubspec.yarm管理里面添加:publish_to
description: 测试demo
publish_to: none
2.2.8.3
The getter 'initialized' isn't defined for the type 'VideoPlayerValue'.
解决方案:video_player升级后字段发生了变化,initialized字段更换为:isInitialized(_controller.value.isInitialized)
2.2.8.4
Undefined name 'AudioPlayerState'.Try correcting the name to one that is defined, or defining the name
解决方案:
AudioPlayerState _playerState = AudioPlayerState.STOPPED
// video_player升级后字段变化, 变更为
PlayerState _playerState = PlayerState.STOPPED
2.2.8.5
FlutterEngine GeneratedPluginRegistrant.registerWith(this);
解决方案:
//方案一:在AndroidManifest.xml添加
//方案二
将GeneratedPluginRegistrant.registerWith(new FlutterEngine(this));或GeneratedPluginRegistrant.registerWith(this);
//替换为
GeneratedPluginRegister.registerGeneratedPlugins(FlutterEngine(this));
或GeneratedPluginRegistrant.registerWith(FlutterEngine(this))
//方案三:注释掉:
//import io.flutter.app.FlutterActivity;
// GeneratedPluginRegistrant.registerWith(this);
// MethodChannel methodChannel = new MethodChannel(getFlutterView(), CHANNEL);
改为:
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.android.FlutterActivity;
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "com.baidu.app";
private MethodChannel mMethodChannel; //
String multibarcode = ""; // 批量扫描码
MyCodeReceiver receiver = new MyCodeReceiver();
//新添加
@Override
public void configureFlutterEngine(FlutterEngine flutterEngine){
GeneratedPluginRegistrant.registerWith(flutterEngine);
}
//改变
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// GeneratedPluginRegistrant.registerWith(this);
// MethodChannel methodChannel = new MethodChannel(getFlutterView(), CHANNEL);
MethodChannel methodChannel = new MethodChannel(getFlutterEngine().getDartExecutor().getBinaryMessenger(), CHANNEL);
methodChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
}
}
}
}
2.2.8.6
Invalid
Podfile
file: no implicit conversion of nil into String.
解决方案: 方案一:删除ios目录下的Podfile.lock 文件然后重新运行 pod install命令
方案二:删除ios目录下的Podfile.lock与Podfile文件 重新运行flutter run或flutter build ios
方案三:删除ios目录,重新运行flutter create .命令,注意有"."这个符号不要忘记
2.2.8.7
Using `ARCHS` setting to build architectures of target `Pods-Runner`: (``)
这个报错一般对应的就是下面的报错,注意看后面的报错信息,看是哪个插件报错。
Specs satisfying the
photo_manager (from
.symlinks/plugins/photo_manager/ios)
dependency were fo
解决方案:把Podfile的版本注释打开,改为platform :ios, '9.0' 或者是更高的版本
2.3 部分警告
全局替换
1.将new List() 替换为[];
2.TextField的inputFormatters:[WhitelistingTextInputFormatter.digitsOnly] 替换为[FilteringTextInputFormatter.digitsOnly]
3.TextField的inputFormatters:[WhitelistingTextInputFormatter(RegExp("[a-z|A-Z|0-9]"))]替换为FilteringTextInputFormatter.allow(RegExp("[a-z|A-Z|0-9]"))
4.Stack组件中overflow: Overflow.visible改为 clipBehavior: Clip.none;overflow: Overflow.clip改为clipBehavior:Clip.hardEdge
5.ListWheelScrollView组件中clipToSize = false改为clipBehavior: Clip.none,clipToSize = true改为 Clip.hardEdge
6.TextField中maxLengthEnforced: true改为maxLengthEnforcement:MaxLengthEnforcement.enforced
7.FlatButton、RaisedButton、OutlineButton的变化:官方参考
颜色的属性发生了变化,由原来的Color 变为了MaterialStateProperty
例如
ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.resolveWith(
(Set states) {
//此处根据按钮不同的状态可设置不同颜色
if (states.contains(MaterialState.pressed))
return Colors.red.withOpacity(1);
return null; // 默认的背景颜色.
},
),
),
child: Text('取消'),
onPressed: () => print('object'),
)
- 之前:FlatButton
FlatButton(
hoverColor: Colors.cyan,
focusColor: Colors.pink,
color:Colors.green,//按钮的颜色
splashColor:Colors.yellow,//点击按钮时水波纹的颜色(会闪一下的那个颜色)
highlightColor: Colors.red,//点击(长按)按钮后按钮的颜色
textColor: new Color(0xff75b9ff), //文字颜色
child: new Text('取消'),
onPressed: () {
print('xxxx');
},
),
- 现在:TextButton
//官方版(推荐)
TextButton(
style: ButtonStyle(
// 分别对应上面的focusColor、hoverColor、splashColor
overlayColor: MaterialStateProperty.resolveWith(
(Set states) {
if (states.contains(MaterialState.focused))
return Colors.pink;
if (states.contains(MaterialState.hovered))
return Colors.cyan;
if (states.contains(MaterialState.pressed))
return Colors.yellow;
return null; // Defer to the widget's default.
}),
),
onPressed: () { },
child: Text('TextButton with custom overlay colors'),
)
//自己版
TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.resolveWith(
(Set states) {
if (states.contains(MaterialState.pressed))
return Colors.red.withOpacity(1);
return Colors.green;
}),
foregroundColor:
MaterialStateProperty.all(Color(0xff75b9ff)),
),
onPressed: () => print('object'),
child: Text('取消'))
// 简单版
TextButton(
style: TextButton.styleFrom(
primary: Colors.blue,//文字颜色
backgroundColor:Colors.green,//背景色
onSurface: Colors.red,// 禁用时候效果
),
onPressed: null,
child: Text('TextButton'),
)
- 之前:RaisedButton
RaisedButton(
padding: EdgeInsets.symmetric( vertical: 20, ),
textColor: Colors.white,
color: Color(0xff006db8),
highlightColor: Color(0xff067bcb),
highlightElevation: 5,
shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10)),
child: Text( '保存', style: TextStyle( fontSize: 10,)),
onPressed: () => print('ss'),
),
- 现在:ElevatedButton
ElevatedButton(
// style: ElevatedButton.styleFrom(
// onPrimary: Colors.white, //文字色
// primary: Color(0xff006db8),//背景色
// padding: EdgeInsets.symmetric(vertical: 20),//文字与按钮的间距
// minimumSize: Size(88, 36),//按钮最小宽高
// RoundedRectangleBorder( borderRadius: BorderRadius.circular(10))
// elevation:5 //按钮阴影
// ),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.resolveWith(
(Set states) {
if (states.contains(MaterialState.pressed))
return Color( 0xff067bcb); //采用这种和overlayColor 效果于原来splashColor稍微有点点区别
return Color(0xff006db8); // 默认的背景颜色.
},
),
foregroundColor:MaterialStateProperty.all(Color(0xffffffff)),
padding: MaterialStateProperty.all(EdgeInsets.symmetric(vertical: 20)),
minimumSize: MaterialStateProperty.all(Size(88, 36)),
elevation: MaterialStateProperty.all(5)),
shape: MaterialStateProperty.all(RoundedRectangleBorder( borderRadius:BorderRadius.circular(10))),
child: Text( '保存', style: TextStyle(fontSize: 10, ),),
onPressed: () => print('ss'),
),
8.出现如下警告
The