返回笔记首页

Flutter 跨端项目简历示例

主题配置

示例一:金融理财 App(Flutter)

项目名称

XX 互联网金融 App(Flutter)

项目背景

公司原有 iOS 和 Android 两套原生代码,开发成本高,功能迭代慢。金融业务对性能和安全要求高,需要高性能的跨端方案。选择 Flutter 实现 60fps 流畅体验。

业务场景

  • 行情中心:实时 K 线图、分时图、大盘指数
  • 基金交易:买入、卖出、定投设置
  • 资产总览:收益曲线、持仓明细
  • 理财产品:产品列表、详情、购买
  • 资讯动态:财经新闻、公告通知

核心职责

1. 离线缓存 - 行情数据

业务场景: 用户频繁查看基金净值、股票行情,每次刷新都请求服务器

问题
  • 行情接口 QPS 高,服务器压力大
  • 用户流量消耗大,每天产生大量重复请求
  • 弱网环境下行情刷新失败
解决方案
  • 使用 Hive 本地数据库缓存行情数据
  • 基金净值缓存 30 分钟,K 线数据缓存 5 分钟
  • 实时数据通过 WebSocket 推送,历史数据走缓存
  • 离线时展示最近一次缓存数据
技术实现
dart
// 缓存层
class MarketCache {
  final box = Hive.box('market');

  Future<MarketData?> get(String code) async {
    final cached = box.get(code);
    if (cached == null) return null;

    // 检查过期
    if (DateTime.now().difference(cached.timestamp) > Duration(minutes: 30)) {
      return null;
    }
    return cached;
  }

  Future<void> set(String code, MarketData data) async {
    await box.put(code, data);
  }
}

// 业务层
Future<MarketData> getMarket(String code) async {
  // 先读缓存
  final cached = await marketCache.get(code);
  if (cached != null) return cached;

  // 请求接口
  final data = await api.getMarket(code);
  await marketCache.set(code, data);
  return data;
}
项目成果
  • 行情接口 QPS 从 5000 降到 1200,降低 76%
  • 用户流量消耗减少 60%
  • 行情加载成功率从 90% 提升到 99%

2. 启动优化 - 金融级性能

业务场景: 用户打开 App 查看实时行情,要求启动快、响应快

问题
  • 冷启动需要 3 秒,用户感觉慢
  • 首页渲染卡顿,影响体验
  • 大盘数据加载慢,用户焦虑
解决方案
  • Splash 页面优化,使用 Flutter native splash
  • 首页骨架屏,先展示框架再填充数据
  • 数据预加载,并行请求自选股、大盘指数、资讯
  • 图表懒加载,滚动到可视区域再渲染
  • 使用 Isolate 处理复杂计算,避免阻塞 UI
技术实现
dart
// 预加载关键数据
@override
void initState() {
  super.initState();
  _loadCriticalData();

  // 延迟加载非关键数据
  Future.delayed(Duration(seconds: 1), () {
    _loadNonCriticalData();
  });
}

Future<void> _loadCriticalData() async {
  await Future.wait([
    _loadUserAsset(),     // 用户资产
    _loadMarketIndex(),   // 大盘指数
    _loadSelfSelect(),    // 自选股
  ]);
  setState(() => _loading = false);
}

// 复杂计算放到 Isolate
Future<ChartData> _calculateChart(List<Kline> data) async {
  return compute(_chartCalculation, data);
}

static ChartData _chartCalculation(List<Kline> data) {
  // 大量计算逻辑
  return result;
}
项目成果
  • 冷启动从 3 秒优化到 0.8 秒
  • 首页渲染 60fps 无卡顿
  • K 线图滑动流畅度提升 80%

3. 本地数据库 - 交易记录

业务场景: 用户需要查询历史交易记录、持仓变化

问题
  • 交易记录接口慢,需要 2-3 秒
  • 用户频繁查询,产生大量重复请求
  • 离线时无法查看历史记录
解决方案
  • 使用 sqflite 存储交易记录
  • 首次加载后本地缓存,增量同步新数据
  • 支持本地筛选、排序、分页
  • 离线可查看所有历史记录
技术实现
dart
class TransactionDB {
  Database? _db;

  Future<void> init() async {
    _db = await openDatabase(
      'transaction.db',
      version: 1,
      onCreate: (db, version) {
        return db.execute(
          'CREATE TABLE transactions(id TEXT PRIMARY KEY, time INTEGER, amount REAL, type TEXT)'
        );
      },
    );
  }

  Future<void> saveTransactions(List<Transaction> list) async {
    final batch = _db!.batch();
    for (var item in list) {
      batch.insert('transactions', item.toMap(),
        conflictAlgorithm: ConflictAlgorithm.replace
      );
    }
    await batch.commit();
  }

  Future<List<Transaction>> query({String? type, int? limit}) async {
    final List<Map<String, dynamic>> maps = await _db!.query(
      'transactions',
      where: type != null ? 'type = ?' : null,
      whereArgs: type != null ? [type] : null,
      orderBy: 'time DESC',
      limit: limit,
    );
    return maps.map((m) => Transaction.fromMap(m)).toList();
  }
}
项目成果
  • 交易记录查询时间从 2.5 秒降到 100ms
  • 支持离线查看 5 年历史记录
  • 接口请求量减少 80%

4. Native 能力封装 - 生物识别

业务场景: 登录、支付需要指纹、面容识别

问题
  • iOS 和 Android 生物识别接口不同
  • 不同设备支持的认证方式不一样
  • 需要处理各种异常情况
解决方案
  • 使用 local_auth 插件统一接口
  • 检测设备支持的认证方式
  • 完善的错误处理和降级方案
  • 支持密码备用方案
技术实现
dart
class BiometricAuth {
  final LocalAuthentication auth = LocalAuthentication();

  Future<bool> canAuth() async {
    try {
      return await auth.canCheckBiometrics && await auth.isDeviceSupported();
    } catch (e) {
      return false;
    }
  }

  Future<List<BiometricType>> getAvailableBiometrics() async {
    try {
      return await auth.getAvailableBiometrics();
    } catch (e) {
      return [];
    }
  }

  Future<bool> authenticate() async {
    try {
      return await auth.authenticate(
        localizedReason: '请验证身份以继续',
        options: const AuthenticationOptions(
          stickyAuth: true,
          biometricOnly: true,
        ),
      );
    } on PlatformException catch (e) {
      if (e.code == 'NotAvailable') {
        // 生物识别不可用,降级到密码
        return _authenticateWithPassword();
      }
      return false;
    }
  }

  Future<bool> _authenticateWithPassword() async {
    // 密码验证逻辑
  }
}
项目成果
  • 支持指纹、面容、虹膜识别
  • 登录成功率 99.5%
  • 用户体验评分从 4.2 提升到 4.7

5. 异常监控 - 交易异常

业务场景: 用户反馈买入失败、支付卡住等问题

问题
  • 交易链路长,不知道哪个环节出错
  • 无法复现用户问题
  • 金融业务容错率低
解决方案
  • 接入 Sentry,捕获所有异常
  • 交易流程全埋点,记录每个步骤
  • 实时告警,交易失败立即通知
  • 建立交易监控大盘
技术实现
dart
// 初始化 Sentry
await SentryFlutter.init(
  (options) {
    options.dsn = 'https://xxx@sentry.io/xxx';
    options.tracesSampleRate = 1.0;
  },
  appRunner: () => runApp(MyApp()),
);

// 捕获交易异常
Future<void> buyFund(String code, double amount) async {
  final transaction = Sentry.startTransaction('buy_fund', 'transaction');

  try {
    // 步骤1: 风险检查
    final span1 = transaction.startChild('risk_check');
    await riskCheck(code, amount);
    span1.finish();

    // 步骤2: 创建订单
    final span2 = transaction.startChild('create_order');
    final order = await createOrder(code, amount);
    span2.finish();

    // 步骤3: 支付
    final span3 = transaction.startChild('payment');
    await payment(order.id);
    span3.finish();

    transaction.status = SpanStatus.ok();
  } catch (e, stackTrace) {
    transaction.status = SpanStatus.internalError();
    Sentry.captureException(e, stackTrace: stackTrace);
    rethrow;
  } finally {
    transaction.finish();
  }
}
项目成果
  • 交易异常定位时间从 2 小时缩短到 10 分钟
  • 发现并修复 15+ 个交易链路问题
  • 交易成功率从 96% 提升到 99.8%

6. 热更新 - 代码推送

业务场景: 发现交易 bug,需要紧急修复

问题
  • Flutter 是 AOT 编译,不能像 JS 那样热更新
  • 应用商店审核需要 3-5 天
  • 影响用户交易体验
解决方案
  • 轻量级 bug:通过服务端开关控制功能开关
  • 中度 bug:使用 shorebird 进行代码推送
  • 重大问题:紧急发版 + 加急审核
技术实现
dart
// 远程配置控制
class RemoteConfig {
  static bool get enableNewFeature {
    return _config.getBool('enable_new_feature', defaultValue: true);
  }

  static int get maxBuyAmount {
    return _config.getInt('max_buy_amount', defaultValue: 100000);
  }
}

// 使用
if (RemoteConfig.enableNewFeature) {
  // 新功能逻辑
} else {
  // 旧逻辑
}

// shorebird 更新检查
void _checkUpdate() async {
  final updater = Updater();
  final status = await updater.checkForUpdate();

  if (status.isUpdateAvailable) {
    await updater.update();
  }
}
项目成果
  • 紧急修复时间从 5 天缩短到 4 小时
  • 功能灰度发布,降低风险
  • 避免 3 次重大业务损失

技术栈

Flutter、Dart、Provider、Dio、Hive、sqflite、Sentry

项目成果

  • 支持 iOS 和 Android,代码复用率 92%
  • App 性能达到原生级别,60fps 流畅体验
  • 包体积比原生减少 30%(Android 15MB,iOS 25MB)
  • 开发效率提升 50%,双端同步迭代
  • 日活 120 万,交易额 50 亿+/月
  • 线上崩溃率 0.1%,行业领先

示例二:社交 App(Flutter)

项目名称

XX 即时通讯社交 App(Flutter)

项目背景

打造一款主打年轻人的社交 App,需要流畅的动画、实时的消息推送、丰富的交互。选择 Flutter 实现高性能 UI 和跨平台开发。

业务场景

  • 消息聊天:单聊、群聊、语音通话、视频通话
  • 动态广场:发布动态、图片/视频、点赞评论
  • 个人主页:个人信息、动态列表、相册
  • 发现:推荐用户、热门话题、附近的人
  • 直播:直播间、礼物打赏、实时互动

核心职责

1. 离线缓存 - 聊天记录

业务场景: 用户需要查看历史聊天记录,包括文字、图片、语音

问题
  • 聊天记录存储在服务器,查询慢
  • 用户频繁翻看历史消息
  • 离线时无法查看聊天记录
解决方案
  • 使用 isar 本地数据库存储聊天记录
  • 消息收发时自动保存到本地
  • 支持全文搜索、按时间筛选
  • 媒体文件本地缓存,路径存数据库
技术实现
dart
@collection
class Message {
  Id id = Isar.autoIncrement;

  late String messageId;
  late String conversationId;
  late String content;
  late int timestamp;
  late String type; // text/image/voice/video
  late String? mediaPath;

  @Index()
  late String senderId;
}

class MessageDB {
  late Isar isar;

  Future<void> init() async {
    isar = await Isar.open([MessageSchema]);
  }

  Future<void> saveMessage(Message msg) async {
    await isar.writeTxn(() async {
      await isar.messages.put(msg);
    });
  }

  Future<List<Message>> getMessages(String conversationId, {int limit = 20}) async {
    return await isar.messages
      .filter()
      .conversationIdEqualTo(conversationId)
      .sortByTimestampDesc()
      .limit(limit)
      .findAll();
  }

  Future<List<Message>> searchMessages(String keyword) async {
    return await isar.messages
      .filter()
      .contentContains(keyword)
      .findAll();
  }
}
项目成果
  • 聊天记录加载时间从 1.5 秒降到 50ms
  • 支持离线查看所有历史消息
  • 全文搜索响应时间 100ms 以内

2. 启动优化 - 消息推送

业务场景: 用户收到消息推送,点击通知进入 App

问题
  • 从通知栏启动 App 慢,用户体验差
  • 需要快速进入对应的聊天界面
  • 未读消息数加载慢
解决方案
  • 优化 App 启动流程,减少初始化时间
  • 预加载消息列表,并行加载未读数
  • 使用 Deeplink 直达指定页面
  • 通知数据本地缓存
技术实现
dart
// 启动优化
void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 必要的初始化
  await MessageDB.instance.init();
  await PushService.init();

  runApp(MyApp());

  // 延迟初始化
  WidgetsBinding.instance.addPostFrameCallback((_) {
    _initNonCritical();
  });
}

void _initNonCritical() {
  // 分享SDK
  ShareSDK.init();
  // 统计SDK
  Analytics.init();
}

// Deeplink 处理
void _handleDeeplink(String link) {
  final uri = Uri.parse(link);
  if (uri.path == '/chat') {
    final conversationId = uri.queryParameters['id'];
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (_) => ChatPage(conversationId: conversationId)
      ),
    );
  }
}
项目成果
  • 启动时间从 2.5 秒优化到 0.6 秒
  • 通知到聊天页面 1 秒内完成
  • 消息推送点击率提升 35%

3. 媒体缓存 - 图片视频

业务场景: 聊天中的图片、视频、语音需要加载

问题
  • 媒体文件重复下载,浪费流量
  • 加载慢,用户体验差
  • 占用存储空间过大
解决方案
  • 使用 cached_network_image 缓存图片
  • 视频使用 LRU 缓存策略
  • 定期清理过期缓存
  • 支持用户手动清理
技术实现
dart
// 图片缓存
CachedNetworkImage(
  imageUrl: imageUrl,
  placeholder: (context, url) => CircularProgressIndicator(),
  errorWidget: (context, url, error) => Icon(Icons.error),
  cacheManager: CacheManager(
    Config(
      'chat_images',
      stalePeriod: Duration(days: 7),
      maxNrOfCacheObjects: 1000,
    ),
  ),
)

// 视频缓存
class VideoCache {
  final cache = <String, File>{};
  final maxSize = 100; // 最多缓存100个视频

  Future<File?> get(String url) async {
    if (cache.containsKey(url)) {
      return cache[url];
    }

    final file = await _downloadVideo(url);
    if (file != null) {
      _add(url, file);
    }
    return file;
  }

  void _add(String url, File file) {
    if (cache.length >= maxSize) {
      final firstKey = cache.keys.first;
      cache[firstKey]?.deleteSync();
      cache.remove(firstKey);
    }
    cache[url] = file;
  }
}
项目成果
  • 图片加载速度提升 80%
  • 流量消耗减少 65%
  • 用户平均停留时长增加 40%

4. MethodChannel - 音视频通话

业务场景: 语音通话、视频通话

问题
  • Flutter 没有成熟的音视频方案
  • 需要集成腾讯云 TRTC SDK
  • iOS 和 Android 原生 SDK 不同
解决方案
  • 封装 MethodChannel 调用原生 SDK
  • 统一 Dart 层 API
  • 处理权限申请、网络切换等
  • 完善的错误处理
技术实现
dart
class RTCChannel {
  static const platform = MethodChannel('com.xxx.app/rtc');

  Future<void> startCall(String userId, bool isVideo) async {
    try {
      await platform.invokeMethod('startCall', {
        'userId': userId,
        'isVideo': isVideo,
      });
    } on PlatformException catch (e) {
      throw RTCException(e.message);
    }
  }

  Future<void> endCall() async {
    await platform.invokeMethod('endCall');
  }

  void setCallListener(Function(CallEvent) callback) {
    platform.setMethodCallHandler((call) async {
      switch (call.method) {
        case 'onUserJoined':
          callback(CallEvent.userJoined);
          break;
        case 'onUserLeft':
          callback(CallEvent.userLeft);
          break;
        case 'onCallEnd':
          callback(CallEvent.callEnd);
          break;
      }
    });
  }
}
项目成果
  • 支持 1v1 音视频通话
  • 通话成功率 98%
  • 通话延迟 < 300ms

5. 性能监控 - 列表滑动

业务场景: 动态列表、消息列表需要流畅滑动

问题
  • 列表滑动卡顿,帧率下降
  • 不知道哪里影响性能
  • 优化缺少数据支持
解决方案
  • 使用 Flutter DevTools 性能分析
  • 监控帧率,记录卡顿情况
  • Isolate 处理数据解析
  • 优化 widget 构建
技术实现
dart
// 性能监控
class PerformanceMonitor {
  final _frameTimes = <Duration>[];

  void startMonitor() {
    WidgetsBinding.instance.addTimingsCallback((timings) {
      for (final timing in timings) {
        final frameDuration = timing.totalSpan;
        _frameTimes.add(frameDuration);

        // 超过 16ms 认为卡顿
        if (frameDuration.inMilliseconds > 16) {
          _reportJank(frameDuration);
        }
      }
    });
  }

  void _reportJank(Duration duration) {
    // 上报卡顿数据
    Analytics.track('frame_jank', {
      'duration': duration.inMilliseconds,
      'page': _currentPage,
    });
  }
}

// Isolate 处理数据
Future<List<Post>> _parsePostsInIsolate(String json) async {
  return compute(_parsePosts, json);
}

static List<Post> _parsePosts(String json) {
  final list = jsonDecode(json) as List;
  return list.map((e) => Post.fromJson(e)).toList();
}
项目成果
  • 列表滑动保持 60fps
  • 卡顿率从 15% 降到 2%
  • 发现并优化 10+ 个性能瓶颈

技术栈

Flutter、Dart、Riverpod、Dio、isar、MethodChannel

项目成果

  • 日活 300 万,月活 1200 万
  • 平均停留时长 45 分钟
  • 消息发送成功率 99.9%
  • App 崩溃率 0.08%
  • 用户留存率 70%(次日留存)

面试话术(Flutter 项目)

开场(30 秒)

"我做的是一个金融理财 App,用的是 Flutter。选择 Flutter 主要是因为金融业务对性能要求高,Flutter 能达到 60fps 的原生级体验,而且可以一套代码编译到 iOS 和 Android。"

亮点展开

如果问为什么选 Flutter: "我们对比过 React Native 和 uni-app。RN 的性能不够好,复杂列表会卡顿。uni-app 虽然开发快,但动画和交互效果达不到我们的要求。Flutter 是自绘引擎,性能接近原生,而且 UI 一致性好,不用担心双端适配问题。"

如果问技术难点: "最难的是和原生 SDK 集成。我们的音视频通话用的是腾讯云 TRTC,这个 SDK 没有 Flutter 版本。我通过 MethodChannel 封装了一层,Dart 层调用统一接口,底层分别调用 iOS 和 Android 的原生 SDK。难点在于双端 API 差异的抹平和异步回调的处理。"

如果问性能优化: "Flutter 性能已经很好了,但还是有优化空间。我主要做了三件事:一是用 Isolate 处理数据解析,避免阻塞 UI 线程;二是优化 widget 构建,减少不必要的 rebuild;三是使用本地数据库缓存数据,减少网络请求。优化后列表滑动稳定 60fps。"

数据记忆

  • 冷启动 3s → 0.8s
  • 缓存命中率 76%
  • 包体积减少 30%
  • 代码复用率 92%
  • 崩溃率 0.1%
  • 60fps 流畅体验
  • 日活 120 万