鸿蒙版Flutter快递查询助手

鸿蒙版Flutter快递查询助手

一个使用Flutter开发的鸿蒙原生应用,提供便捷的快递查询服务,支持物流跟踪、短信通知和电话联系等功能。本应用专为鸿蒙系统优化,同时保持对其他主流平台的兼容性,为用户提供统一、高效的快递查询体验。

开发背景

随着电子商务的快速发展,快递服务已成为人们日常生活中不可或缺的一部分。然而,用户经常需要在多个平台之间切换来查询不同快递公司的物流信息,体验不够便捷。

本项目旨在解决这一痛点,通过整合多家快递公司的查询接口,提供统一的查询入口,让用户能够便捷地追踪任何快递包裹的物流状态。同时,项目特别针对鸿蒙系统进行了原生适配,为鸿蒙用户提供流畅的使用体验。

作为一个开源项目,我们希望能够帮助更多的开发者了解Flutter与鸿蒙系统的结合开发,推动跨平台应用在鸿蒙生态中的发展。

功能特点

  • 快递查询:支持多家快递公司查询(顺丰、圆通、中通等)
  • 智能识别:自动识别快递公司,无需手动选择
  • 物流跟踪:实时跟踪物流信息,及时了解包裹状态
  • 时间轴展示:美观的时间轴展示物流进度和详细信息
  • 历史记录:保存查询历史,方便再次查询
  • 短信通知:支持将物流信息通过短信发送给他人
  • 一键拨号:提供客服电话一键拨打功能
  • 鸿蒙适配:针对鸿蒙系统进行了原生适配,提供流畅体验

多平台支持

本项目基于Flutter跨平台框架开发,支持多种操作系统和设备:

  • 鸿蒙OS:针对华为设备进行了原生适配
  • Android:支持Android 5.0及以上版本
  • iOS:支持iOS 11.0及以上版本
  • Web:可部署为网页应用,支持主流浏览器
  • macOS:支持macOS 10.14及以上版本
  • Windows:支持Windows 10及以上版本
  • Linux:支持Ubuntu 18.04及以上版本

效果

鸿蒙

macos

技术栈

  • Flutter框架
  • 鸿蒙OS适配
  • HTTP网络请求
  • 响应式UI设计
  • 状态管理
  • 本地存储
  • 短信发送集成
  • 电话拨打功能

核心功能实现

短信发送功能

应用集成了短信发送功能,可以将快递物流信息通过短信分享给他人:

dart 复制代码
// 短信发送功能实现
Future<void> sendSms(BuildContext context, {String? trackingInfo}) async {
  String defaultNumber = '17752170152';
  String message;
​
  if (trackingInfo != null && trackingInfo.isNotEmpty) {
    // 发送物流信息
    message = '您的快递最新状态: $trackingInfo';
  } else {
    // 发送应用介绍
    message = '快递查询助手是一款便捷的快递查询工具...';
  }
​
  // 显示对话框让用户输入电话号码
  await showSmsDialog(context, defaultNumber, message);
}

电话拨打功能

应用提供了一键拨打客服电话的功能:

csharp 复制代码
// 电话拨打功能实现
Future<void> _callNumber(BuildContext context) async {
  const String number = '17752170152';
  try {
    // 使用FlutterPhoneDirectCaller拨号
    bool? result = await FlutterPhoneDirectCaller.callNumber(number);
​
    if (result != true) {
      // 如果直接拨号失败,显示提示
      if (context.mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(content: Text('无法拨打电话,请手动拨打: 17752170152')),
        );
      }
    }
  } catch (e) {
    // 错误处理
  }
}
​
## 安装方式
​
### 通用安装
​
```bash
# 克隆仓库
git clone git@gitcode.com:nutpi/flutter_express_tracker.git
​
# 进入项目目录
cd flutter_express_tracker
​
# 安装依赖
flutter pub get
​
# 运行应用
flutter run
bash 复制代码
# 运行Web版本
flutter run -d chrome
​
# 运行macOS版本
flutter run -d macos
​
# 运行Linux版本
flutter run -d linux
​
# 运行Windows版本
flutter run -d windows
​
# 构建Web版本
flutter build web
​
# 构建macOS应用
flutter build macos
​
# 构建Linux应用
flutter build linux
​
# 构建Windows应用
flutter build windows

贡献指南

欢迎提交问题和功能请求,或直接提交代码贡献。请确保遵循项目的代码风格和提交规范。

版权信息

MIT License

作者:坚果派 公众号:nutpi 官网: www.nutpi.net/

参考

ohos平台适配flutter三方库指导

历史记录管理

应用实现了本地历史记录管理功能,方便用户查看和管理已查询的快递信息:

ini 复制代码
// 历史记录管理实现
class TrackingHistoryService {
  final _prefs = SharedPreferences.getInstance();
  static const _historyKey = 'tracking_history';
​
  // 保存查询记录
  Future<void> saveTrackingHistory(TrackingHistory history) async {
    final prefs = await _prefs;
    List<String> histories = prefs.getStringList(_historyKey) ?? [];
    histories.insert(0, jsonEncode(history.toJson()));
    await prefs.setStringList(_historyKey, histories);
  }
​
  // 获取历史记录
  Future<List<TrackingHistory>> getTrackingHistories() async {
    final prefs = await _prefs;
    List<String> histories = prefs.getStringList(_historyKey) ?? [];
    return histories
        .map((e) => TrackingHistory.fromJson(jsonDecode(e)))
        .toList();
  }
}

性能优化

为确保应用的流畅运行,我们采取了以下优化措施:

  1. 懒加载:页面组件采用懒加载方式,减少初始加载时间
  2. 缓存管理:实现智能缓存机制,减少网络请求
  3. 状态管理:使用Provider进行高效的状态管理
  4. 图片优化:实现图片懒加载和压缩
  5. 网络优化:请求合并和数据预加载

项目架构

项目采用清晰的分层架构设计:

bash 复制代码
lib/
  ├── main.dart              # 应用入口
  ├── models/                # 数据模型
  │   ├── tracking_model.dart
  │   └── tracking_history_model.dart
  ├── pages/                 # 页面组件
  │   ├── tracking_page.dart
  │   └── history_page.dart
  ├── services/              # 业务逻辑
  │   ├── tracking_service.dart
  │   └── history_service.dart
  └── utils/                 # 工具类
      └── http_util.dart

依赖管理

项目使用了以下主要依赖:

yaml 复制代码
dependencies:
  # 网络请求
  http: ^1.1.0
  
  # 状态管理
  provider: ^6.1.2
  
  # 本地存储
  shared_preferences: ^2.2.2
  
  # UI组件
  flutter_animate: ^4.5.0
  fl_chart: ^0.66.2

鸿蒙适配

为支持鸿蒙系统,我们进行了以下适配:

  1. 原生API适配

    • 短信发送接口适配
    • 电话拨打功能适配
    • 本地存储接口适配
    • 触摸事件和手势处理适配
  2. UI适配

    • 遵循鸿蒙设计规范
    • 支持鸿蒙手势操作(包括点击、长按、拖拽等)
    • 适配不同屏幕尺寸和分辨率
    • 兼容鸿蒙系统的视图层次结构
  3. 性能优化

    • 针对鸿蒙系统进行性能调优
    • 优化启动速度和运行内存
    • 减少不必要的视图重绘和布局计算

使用指南

快递查询

  1. 在首页输入快递单号
  2. 系统自动识别快递公司
  3. 点击查询按钮获取物流信息
  4. 查看物流详情和时间轴展示

历史记录

  1. 点击底部导航栏的"历史"标签
  2. 查看已查询的快递记录
  3. 点击记录可重新查询
  4. 左滑删除不需要的记录

分享功能

  1. 在物流详情页点击分享按钮
  2. 选择短信分享方式
  3. 输入接收方手机号
  4. 确认发送物流信息

常见问题

  1. 为什么无法识别快递公司?

    • 确保输入的快递单号正确
    • 部分新增快递公司可能暂不支持自动识别
  2. 如何处理查询失败?

    • 检查网络连接
    • 确认快递单号是否正确
    • 尝试手动选择快递公司
  3. 短信发送失败怎么办?

    • 检查是否授予应用短信权限
    • 确认手机号格式正确
    • 检查短信服务是否可用
  4. 收到"设备不支持发送短信"错误怎么办?

    • 这是因为某些设备(如模拟器、平板电脑或某些电脑版本)不支持发送短信功能

    • 错误信息"PlatformException(device_not_capable)"表示当前设备硬件不支持短信功能

    • 解决方案:

      • 尝试使用其他分享方式,如复制文本或使用其他通讯应用
      • 在支持短信功能的移动设备上使用该应用
      • 如果在鸿蒙设备上遇到此问题,请确保已授予相应权限并使用最新版本的系统

更新日志

v1.0.0 (2025-03-08)

  • 首次发布
  • 支持多家快递公司查询
  • 实现短信通知功能
  • 支持历史记录管理

v1.0.1 (2025-03-09)

  • 优化查询速度
  • 修复已知问题
  • 改进UI交互体验
  • 增加更多快递公司支持

详细技术实现

应用架构

本项目采用了清晰的MVVM(Model-View-ViewModel)架构模式,有效分离了UI层、业务逻辑层和数据层,提高了代码的可维护性和可测试性。

数据层(Model)

数据层负责处理应用的数据逻辑,包括数据获取、存储和处理:

dart 复制代码
// 快递跟踪模型示例
class TrackingModel {
  final String trackingNumber;
  final String courierCompany;
  final List<TrackingDetail> details;
  final String status;
  final DateTime lastUpdated;
​
  TrackingModel({
    required this.trackingNumber,
    required this.courierCompany,
    required this.details,
    required this.status,
    required this.lastUpdated,
  });
​
  factory TrackingModel.fromJson(Map<String, dynamic> json) {
    // JSON解析逻辑
    return TrackingModel(
      trackingNumber: json['tracking_number'],
      courierCompany: json['courier_company'],
      details: (json['details'] as List)
          .map((e) => TrackingDetail.fromJson(e))
          .toList(),
      status: json['status'],
      lastUpdated: DateTime.parse(json['last_updated']),
    );
  }
}
视图模型层(ViewModel)

视图模型层连接视图和模型,处理业务逻辑并提供数据给UI:

ini 复制代码
class TrackingViewModel extends ChangeNotifier {
  final TrackingService _trackingService = TrackingService();
  final TrackingHistoryService _historyService = TrackingHistoryService();
  
  TrackingModel? _trackingInfo;
  bool _isLoading = false;
  String? _error;
  
  // Getters
  TrackingModel? get trackingInfo => _trackingInfo;
  bool get isLoading => _isLoading;
  String? get error => _error;
  
  // 查询快递信息
  Future<void> queryTracking(String trackingNumber) async {
    _isLoading = true;
    _error = null;
    notifyListeners();
    
    try {
      _trackingInfo = await _trackingService.getTrackingInfo(trackingNumber);
      
      // 保存到历史记录
      if (_trackingInfo != null) {
        await _historyService.saveTrackingHistory(TrackingHistory(
          id: const Uuid().v4(),
          trackingNumber: trackingNumber,
          courierCompany: _trackingInfo!.courierCompany,
          status: _trackingInfo!.status,
          queryTime: DateTime.now(),
        ));
      }
    } catch (e) {
      _error = e.toString();
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }
}
视图层(View)

视图层负责UI展示和用户交互:

less 复制代码
class TrackingPage extends StatelessWidget {
  final TextEditingController _trackingController = TextEditingController();
​
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) => TrackingViewModel(),
      child: Consumer<TrackingViewModel>(
        builder: (context, viewModel, _) {
          return Scaffold(
            appBar: AppBar(title: const Text('快递查询')),
            body: Column(
              children: [
                // 输入框和查询按钮
                Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Row(
                    children: [
                      Expanded(
                        child: TextField(
                          controller: _trackingController,
                          decoration: const InputDecoration(
                            hintText: '请输入快递单号',
                            border: OutlineInputBorder(),
                          ),
                        ),
                      ),
                      const SizedBox(width: 16),
                      ElevatedButton(
                        onPressed: viewModel.isLoading
                            ? null
                            : () => viewModel.queryTracking(_trackingController.text),
                        child: const Text('查询'),
                      ),
                    ],
                  ),
                ),
                
                // 加载指示器
                if (viewModel.isLoading)
                  const CircularProgressIndicator(),
                  
                // 错误信息
                if (viewModel.error != null)
                  Text(
                    viewModel.error!,
                    style: const TextStyle(color: Colors.red),
                  ),
                  
                // 查询结果
                if (viewModel.trackingInfo != null)
                  Expanded(
                    child: TrackingDetailWidget(
                      trackingInfo: viewModel.trackingInfo!,
                    ),
                  ),
              ],
            ),
          );
        },
      ),
    );
  }
}

网络请求实现

应用使用HTTP包处理网络请求,实现了请求重试、超时处理和错误处理机制:

dart 复制代码
class TrackingService {
  final String _baseUrl = 'https://api.example.com/tracking';
  final http.Client _client = http.Client();
  
  Future<TrackingModel> getTrackingInfo(String trackingNumber) async {
    try {
      final response = await _client.get(
        Uri.parse('$_baseUrl?number=$trackingNumber'),
        headers: {'Content-Type': 'application/json'},
      ).timeout(const Duration(seconds: 10));
      
      if (response.statusCode == 200) {
        return TrackingModel.fromJson(jsonDecode(response.body));
      } else {
        throw Exception('查询失败: ${response.statusCode}');
      }
    } on TimeoutException {
      throw Exception('网络请求超时,请检查网络连接');
    } on SocketException {
      throw Exception('网络连接失败,请检查网络设置');
    } catch (e) {
      throw Exception('查询出错: $e');
    }
  }
}

本地存储实现

应用使用SharedPreferences进行本地数据存储,实现了数据的持久化:

dart 复制代码
class ConfigService {
  final _prefs = SharedPreferences.getInstance();
  static const _themeKey = 'app_theme';
  static const _languageKey = 'app_language';
  
  // 保存主题设置
  Future<void> saveThemeMode(ThemeMode mode) async {
    final prefs = await _prefs;
    await prefs.setInt(_themeKey, mode.index);
  }
  
  // 获取主题设置
  Future<ThemeMode> getThemeMode() async {
    final prefs = await _prefs;
    final index = prefs.getInt(_themeKey) ?? ThemeMode.system.index;
    return ThemeMode.values[index];
  }
  
  // 保存语言设置
  Future<void> saveLanguage(String languageCode) async {
    final prefs = await _prefs;
    await prefs.setString(_languageKey, languageCode);
  }
  
  // 获取语言设置
  Future<String> getLanguage() async {
    final prefs = await _prefs;
    return prefs.getString(_languageKey) ?? 'zh';
  }
}

高级功能详解

智能识别快递公司

应用实现了基于单号规则的快递公司智能识别算法:

python 复制代码
String? identifyCourierCompany(String trackingNumber) {
  // 顺丰快递:以SF开头,后接12位数字
  if (RegExp(r'^SF\d{12}$').hasMatch(trackingNumber)) {
    return '顺丰快递';
  }
  
  // 中通快递:以ZTO开头或纯数字(通常为12位)
  if (trackingNumber.startsWith('ZTO') || 
      RegExp(r'^\d{12}$').hasMatch(trackingNumber)) {
    return '中通快递';
  }
  
  // 圆通快递:以YT开头,后接10位数字
  if (RegExp(r'^YT\d{10}$').hasMatch(trackingNumber)) {
    return '圆通快递';
  }
  
  // 更多快递公司识别规则...
  
  // 无法识别
  return null;
}

物流时间轴实现

应用使用自定义Widget实现了美观的物流时间轴展示:

less 复制代码
class TrackingTimeline extends StatelessWidget {
  final List<TrackingDetail> details;
  
  const TrackingTimeline({Key? key, required this.details}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: details.length,
      itemBuilder: (context, index) {
        final detail = details[index];
        final isFirst = index == 0;
        final isLast = index == details.length - 1;
        
        return Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // 时间轴线和节点
            Column(
              children: [
                // 上半部分线条
                if (!isFirst)
                  Container(
                    width: 2,
                    height: 20,
                    color: Colors.grey,
                  ),
                
                // 节点
                Container(
                  width: 12,
                  height: 12,
                  decoration: BoxDecoration(
                    shape: BoxShape.circle,
                    color: isFirst ? Colors.green : Colors.grey,
                  ),
                ),
                
                // 下半部分线条
                if (!isLast)
                  Container(
                    width: 2,
                    height: 20,
                    color: Colors.grey,
                  ),
              ],
            ),
            
            // 物流详情
            Expanded(
              child: Padding(
                padding: const EdgeInsets.all(8.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      detail.time,
                      style: TextStyle(
                        color: isFirst ? Colors.green : Colors.grey,
                        fontWeight: isFirst ? FontWeight.bold : FontWeight.normal,
                      ),
                    ),
                    const SizedBox(height: 4),
                    Text(detail.description),
                  ],
                ),
              ),
            ),
          ],
        );
      },
    );
  }
}

鸿蒙系统适配详解

鸿蒙应用配置

ohos/AppScope/app.json5中配置应用信息:

bash 复制代码
{
  "app": {
    "bundleName": "com.nutpi.express_tracker",
    "vendor": "nutpi",
    "versionCode": 1000000,
    "versionName": "1.0.0",
    "icon": "$media:app_icon",
    "label": "快递查询助手"
  }
}

鸿蒙权限配置

ohos/entry/src/main/module.json5中配置所需权限:

json 复制代码
{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      },
      {
        "name": "ohos.permission.SEND_MESSAGES"
      },
      {
        "name": "ohos.permission.CALL_PHONE"
      }
    ]
  }
}

鸿蒙特有API适配

针对鸿蒙系统的特有功能进行适配:

dart 复制代码
Future<void> sendSmsOnHarmonyOS(String phoneNumber, String message) async {
  try {
    // 使用鸿蒙特有的短信发送API
    await FlutterSms.sendSMS(
      message: message,
      recipients: [phoneNumber],
      sendDirect: true,
    );
  } catch (e) {
    // 处理鸿蒙系统特有的异常
    if (e.toString().contains('harmony_specific_error')) {
      // 特殊处理逻辑
    }
    rethrow;
  }
}

相关推荐
打野赵怀真6 分钟前
render函数中return如果没有使用()会有什么问题?
前端·javascript
Riesenzahn9 分钟前
css在页面上画一个正方形,边长为页面宽度的一半
前端·javascript
tommyrunner10 分钟前
Cursor rule文件测试 一秒了解AI行为规则文件
前端·cursor
北京_宏哥16 分钟前
《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
java·前端·selenium
Nu1120 分钟前
weakMap 和 weakSet 原理
前端·面试
顾林海22 分钟前
深入理解 Dart 函数:从基础到高阶应用
android·前端·flutter
比特鹰26 分钟前
桌面端跨端框架调研
前端·javascript·前端框架
Ratten27 分钟前
【JavaScript】---- JS原生的深拷贝API structuredClone 使用详解与注意事项
前端·javascript
DarisX28 分钟前
JupyterLab前端二开基础上手指南
前端