flutter项目升级2.0过程填坑记录

在此之前先推荐看大佬的:填坑指导
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

报错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, 这是未了解决不同状态(pressed、hovered、focused、disabled)下按钮颜色的变化
例如

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