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<Counter>.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<Counter>(context) .increment(调一下里面的方法。。这里也可以传参数进去只需要在 Counter 里面的 increment 里面写两个接受参数的就好);
  • provider
Provider.of<Counter>(context, listen: false).increment(这里也可以传参数);

比如:

#注释掉的是我们”provide“ 的写法,这里主要是从我们建立的model里面取Id,因为Id是变化的。
var formData = {
      "categoryId": Provider.of<ChildCategory>(context).categoryId, 
                  //Provide.value<ChildCategory>(context).categoryId,
      "categorySubId": categorySubId,
      "page": 1
    };
  • provide
return Provide<CategoryGoodsListProvide>(builder: (context, child, data) {
data.//也能点出我们设置好值
}
  • provider
final counter = Provider.of<Counter>(context);
    return Container(
      counter.//点出我们在model里面设置的值了
 );
// 在使用 provider的时候我们要注意了一定要设置listen的Bool值就是这样
await Provider.of<DetailsInfoProvide>(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标签的下面增加如下代码:

<meta-data
           android:name="flutterEmbedding"
           android:value="2"/>

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<String> get timerPickerHourLabels => throw UnimplementedError();

  @override
  List<String> get timerPickerMinuteLabels => throw UnimplementedError();

  @override
  List<String> get timerPickerSecondLabels => throw UnimplementedError();

2.2.3

The argument type 'Duration' can't be assigned to the parameter type 'Future<Duration>'

解决方案:

      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添加
<meta-data android:name="flutterEmbedding" android:value="2"/>

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

ElevatedButton(
     style: ButtonStyle(
     backgroundColor: MaterialStateProperty.resolveWith<Color>(
       (Set<MaterialState> 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<Color>(
      (Set<MaterialState> 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<Color>(
                          (Set<MaterialState> states) {
                        if (states.contains(MaterialState.pressed))
                          return Colors.red.withOpacity(1);
                        return Colors.green; 
                      }),
                      foregroundColor:
                          MaterialStateProperty.all<Color>(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<Color>(
        (Set<MaterialState> states) {
              if (states.contains(MaterialState.pressed))
                   return Color( 0xff067bcb); //采用这种和overlayColor 效果于原来splashColor稍微有点点区别
                          return Color(0xff006db8); // 默认的背景颜色.
                        },
                      ),
  foregroundColor:MaterialStateProperty.all<Color>(Color(0xffffffff)),
  padding: MaterialStateProperty.all<EdgeInsetsGeometry>(EdgeInsets.symmetric(vertical: 20)),
  minimumSize: MaterialStateProperty.all<Size>(Size(88, 36)),
  elevation: MaterialStateProperty.all(5)),
  shape: MaterialStateProperty.all<OutlinedBorder>(RoundedRectangleBorder( borderRadius:BorderRadius.circular(10))),
  child: Text( '保存', style: TextStyle(fontSize: 10, ),),
  onPressed: () => print('ss'),
),

8.出现如下警告

The <style> element is not implemented in this library.
Style elements are not supported by this library and the requested SVG may not render as intended.
If possible, ensure the SVG uses inline styles and/or attributes (which are supported), or use a
preprocessing utility such as svgcleaner to inline the styles for you.
解决方案:flutter_svg插件升级到新版后,以前的svg图片不能使用,需要下载https://github.com/RazrFalcon/svgcleaner-gui/releases
下载后直接运行,import导入svg图片,然后点击run处理即可,用新的svg图片替换原来的svg图

9.showSnackBar报错误

'showSnackBar' is deprecated and shouldn't be used. Use ScaffoldMessenger.showSnackBar

解决方案:Scaffold换为ScaffoldMessenger
10.textSelectionColor弃用

Use TextSelectionThemeData.selectionColor instead

解决方案:

// textSelectionColor: Color(0xff2294E2)
//更换为下面用法
textSelectionTheme:TextSelectionThemeData(selectionColor:Color(0xff2294E2))

11.charts_flutter升级后属性报错

The constructor returns type 'AxisSpec<dynamic>' that isn't of expected type 'NumericAxisSpec'

解决方案:

 primaryMeasureAxis: charts.AxisSpec(showAxisLine: true),
//更换为
 primaryMeasureAxis: new charts.NumericAxisSpec(showAxisLine: true),                  

12.flutter 真机调试无法访问网络,dio报错

Insecure HTTP is not allowed by platform

解决方案:
android:

// android/app/src/main 文件夹
<application
    ...
    android:networkSecurityConfig="@xml/network_security_config"
    android:usesCleartextTraffic="true"
    ...   >
在android/app/src/main/res/xml/network_security_config.xml 写下
 <?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">common.baidu.net</domain>
        <domain includeSubdomains="true">common.baidu.cn</domain>
        <domain includeSubdomains="true">common.baidu.com</domain>
        <domain includeSubdomains="true">video.baidu.com</domain>
    </domain-config>
     <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
            <certificates src="system" />
        </trust-anchors>
    </base-config>
</network-security-config>

ios:

//info.plist下添加
<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
      <true/>
</dict>

问题12完整参考

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容