flutter 开发中遇到的常见问题(持续更新...,最后更新时间20211110)

Flutter与原生交互侧滑

原生跳转flutter,如果原生不做处理,flutter内部页面支持侧滑,但从flutter到原生不支持侧滑。

监听flutter首页,当首页出现时,原生ViewController打开侧滑代理事件;跳转到flutter二级页面关闭原生侧滑事件。

具体实现:

@interface BLFlutterViewController : FBFlutterViewContainer
@end

@implementation BLFlutterViewController
- (void)setIsSideslip:(BOOL)isSideslip{
    _isSideslip = isSideslip;

    RTRootNavigationController * navi = self.rt_navigationController;

    if (isSideslip) {
        navi.interactivePopGestureRecognizer.delaysTouchesBegan = YES;
        navi.interactivePopGestureRecognizer.delegate = self;
        navi.interactivePopGestureRecognizer.enabled = YES;
    } else {
        navi.interactivePopGestureRecognizer.delegate = nil;
        navi.interactivePopGestureRecognizer.enabled = NO;
    }
}

[self.methodChannel setMethodCallHandler:^(FlutterMethodCall* call,
                                         FlutterResult result) {
    if([call.method isEqualToString:@"supportedSideSlip"]){//左滑
        BOOL side = [call.arguments boolValue];
        self.isSideslip = side;
    }
}];

@end

//主页
class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  void dispose() {
    super.dispose();
    PageVisibilityBinding.instance.removeObserver(this);
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    ///注册监听器
    PageVisibilityBinding.instance.addObserver(this, ModalRoute.of(context));
  }

  @override
  void onPageHide() {
    super.onPageHide();
    print("LifecycleTestPage - onPageHide");
    methodChannel.invokeMethod(channel_supportedSideSlip, false);
  }

  @override
  void onPageShow() {
    super.onPageShow();
    print("LifecycleTestPage - onPageShow");
    methodChannel.invokeMethod(channel_supportedSideSlip, true);
  }
}

Flutter 编译模式debug和release判断

参考文章

第一种、通过断言识别

assert((){
     // Do something for debug
     print('这是asset下的输出内容');
     return true;
 }());

第二种、通过编译常数识别

if (kReleaseMode){ // 
      //release
}else {
     //debug
}

解决Flutter真机debug拔线后闪退

Flutter - debug/release切换优化

iOS高版本,debug在断开连接时,进入flutter模块会闪退;使用flutter_boast在启动时就闪退。

可设置在debug也能运行release

image
image

Release问题怎么排查

有时debug正常,但release可能卡死、闪退。没有办法联调,只能通过日志观察,分析有问题的代码。

FlutterError.onError = (FlutterErrorDetails details) async {
    // 转发至 Zone 中
    Zone.current.handleUncaughtError(details.exception, details.stack);
  };

  runZoned<Future<Null>>(() async {
    runApp(MyApp());
  }, onError: (error, stackTrace) async {
    //Do sth for error
    String message =
        "error = ${error.toString()}" + "\nstackTrace ${stackTrace.toString()}";
    debugPrint(message);
  });

BuildContext问题导致退出到首页失败

统一封装了退到首页的方法:

void popRoot(BuildContext context) {
  // ignore: unnecessary_statements
  Navigator.popUntil(context, (route) {
    //跳到根目录
    String name = route.settings.name;
    if (name != "/") {
      return false;
    }
    return true;
  });
}

如果在_MyAppState中收到消息,直接调用popRoot(context)会失效。
需要获取顶层的context。

  1. 定义navigatorKey
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
  1. 注册navigatorKey
MaterialApp(
navigatorKey:navigatorKey
           ...)
  1. 获取当前的context
Future.delayed(Duration(seconds: 0)).then((value) {
    BuildContext curContext = navigatorKey.currentState.overlay.context;
    popRoot(curContext);
});

FlutterViewController内存没有释放

FlutterMethodChannel强引用self,导致内存泄露

self.methodChannel = [FlutterMethodChannel
          methodChannelWithName:@"cn.percent.online_document"
                binaryMessenger:self];

解决方案

self.methodChannel = [FlutterMethodChannel
          methodChannelWithName:@"cn.percent.online_document"
                binaryMessenger:[BLWeakProxy proxyWithTarget:self]];

@interface BLWeakProxy : NSObject
@property (weak,nonatomic,readonly)id target;

+ (instancetype)proxyWithTarget:(id)target;
- (instancetype)initWithTarget:(id)target;
@end

@implementation BLWeakProxy

- (instancetype)initWithTarget:(id)target{
    _target = target;
    return self;
}

+ (instancetype)proxyWithTarget:(id)target{
    return [[self alloc] initWithTarget:target];
}

- (void)forwardInvocation:(NSInvocation *)invocation{
    SEL sel = [invocation selector];

    if ([self.target respondsToSelector:sel]) {
        [invocation invokeWithTarget:self.target];
    }
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
    return [self.target methodSignatureForSelector:aSelector];
}

- (BOOL)respondsToSelector:(SEL)aSelector{
    return [self.target respondsToSelector:aSelector];
}

@end

attach联调时出现下面错误

There are multiple observatory ports available.
Rerun this command with one of the following passed in as the appId:

  flutter attach --app-id bundleId
  flutter attach --app-id bundleId (2)

Exited (1)

XCode运行,flutter直接停止,再次启动会出现上述错误。
可以重新运行XCode工程,暴力解法直接关掉模拟器,重新attch。

打了断点却不走

  1. 检查下新加的代码,有可能在断点前面的代码抛异常了。try...cache前面的代码,看报错原因。或者找离的近的代码,一行一行代码调试,看最后在哪里突然消失。
  2. 重命名类大小写问题:如果文件仅修改了大小写,可能定位在老的文件。

跳转flutter页面,白屏问题

  1. 增加白屏的加载效果
UIView * splashScreenView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
UIActivityIndicatorView * loadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[loadingView startAnimating];
loadingView.center = splashScreenView.center;
loadingView.size = CGSizeMake(40, 40);
[splashScreenView addSubview:loadingView];
  1. 增加缓存
@import Flutter;
@interface AppDelegate : FlutterAppDelegate <UIApplicationDelegate>
@property (nonatomic,strong) FlutterEngine *flutterEngine;
@end

@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.flutterEngine = [[FlutterEngine alloc] initWithName:@"my flutter engine"];
    [self.flutterEngine run];
    [GeneratedPluginRegistrant registerWithRegistry:self.flutterEngine];
}
@end

//初始化viewController
FlutterEngine *flutterEngine =
                ((AppDelegate *)UIApplication.sharedApplication.delegate).flutterEngine;
BLFlutterViewController *viewController = [[BLFlutterViewController alloc] initWithEngine:flutterEngine nibName:nil bundle:nil];
viewController.splashScreenView = splashScreenView;
[self.navigationController pushViewController:viewController animated:YES];

flutter 卡死闪退

flutter的UI线程在iOS中是常驻线程。如果出现闪退不会立刻崩溃,而是界面卡死,过段时间后闪退。

有点时候debug调试时,并没注意控制台的报错信息,直接热更了。而到了release情况,会引起程序卡死、闪退。

flutter: error = Null check operator used on a null value
stackTrace #0 State.setState (package:flutter/src/widgets/framework.dart:1108)
1 _MySpaceState.loadFiltrate (package:online_document/Section/myspace/MySpace.dart:126)

检查数据是否有越界,空的情况。有时候debug情况没有注意,或者测试的时候没有复现。到release会一直打印信息,直到闪退。
flutter 开启了4个常驻线程,崩溃时不会立刻崩溃,而是一直在疯狂跑CPU,界面卡住。然后闪退。

Widget body() {
    ...
    return list.pullCustomListViewHeader(headerWidget,
        (BuildContext context, int index) {
      if (index >= list.datas.length) {
        return SizedBox();
      }
      return cell(context, list.datas[index]);
    });
  }

多次跳转flutter页面,出现白屏

快速点击时,小概率出现多次跳到同一个页面。其中有些页面没刷新出来,出现白屏。

模拟测试:

for (int i = 0; i<3; i++) {
   [self.navigationController pushViewController:[BLFlutterViewController flutterVC] animated:YES];
} 

解决方案:
防止按钮快速点击。

Flutter Intl插件不生效

flutter_intl:
  enabled: true # Required. Must be set to true to activate the plugin. Default: false
  arb_dir: lib/l10n # Optional. Sets the directory of your ARB resource files. Provided value should be a valid path on your system. Default: lib/l10n
  output_dir: lib/generated # Optional. Sets the directory of generated localization files. Provided value should be a valid path on your system. Default: lib/generated
  use_deferred_loading: false

有时候发现arb更改后,插件没有自动更新。主要原因有两个:

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

推荐阅读更多精彩内容