欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net

目录

前言

在移动应用开发中,网络功能是一项基础且重要的能力。获取设备的IP地址是许多网络应用的常见需求,无论是进行网络诊断、服务器通信还是用户定位,都需要获取设备的网络信息。本次开发旨在将Flutter生态中的get_ip_address库适配到OpenHarmony平台,实现获取IP地址的功能,为开发者提供一套简洁、高效的网络信息获取解决方案。

随着OpenHarmony生态的不断发展,越来越多的Flutter开发者希望将现有的应用迁移到鸿蒙平台。然而,由于平台差异和API限制,直接使用Flutter的第三方库可能会遇到各种问题。本次适配工作不仅解决了get_ip_address库在OpenHarmony上的使用问题,也为其他Flutter库的适配提供了参考思路。

混合工程结构深度解析

项目目录架构

当Flutter项目集成鸿蒙支持后,典型的项目结构会发生显著变化。以下是经过ohos_flutter插件初始化后的项目结构:

my_flutter_harmony_app/
├── lib/                          # Flutter业务代码(基本不变)
│   ├── main.dart                 # 应用入口
│   ├── home_page.dart           # 首页
│   └── utils/
│       └── platform_utils.dart  # 平台工具类
├── pubspec.yaml                  # Flutter依赖配置
├── ohos/                         # 鸿蒙原生层(核心适配区)
│   ├── entry/                    # 主模块
│   │   └── src/main/
│   │       ├── ets/              # ArkTS代码
│   │       │   ├── MainAbility/
│   │       │   │   ├── MainAbility.ts       # 主Ability
│   │       │   │   └── MainAbilityContext.ts
│   │       │   └── pages/
│   │       │       ├── Index.ets           # 主页面
│   │       │       └── Splash.ets          # 启动页
│   │       ├── resources/        # 鸿蒙资源文件
│   │       │   ├── base/
│   │       │   │   ├── element/  # 字符串等
│   │       │   │   ├── media/    # 图片资源
│   │       │   │   └── profile/  # 配置文件
│   │       │   └── en_US/        # 英文资源
│   │       └── config.json       # 应用核心配置
│   ├── ohos_test/               # 测试模块
│   ├── build-profile.json5      # 构建配置
│   └── oh-package.json5         # 鸿蒙依赖管理
└── README.md

展示效果图片

flutter 实时预览 效果展示
在这里插入图片描述

运行到鸿蒙虚拟设备中效果展示
在这里插入图片描述

功能代码实现

1. get_ip_address 库模拟实现

为了在OpenHarmony平台上实现获取IP地址的功能,我们首先创建了一个模拟的get_ip_address库,实现了核心的网络信息获取功能。

核心实现代码

// 模拟 get_ip_address 库的实现
class GetIpAddress {
  // 获取 IP 地址
  Future<String> getIPAddress() async {
    // 模拟网络请求延迟
    await Future.delayed(const Duration(milliseconds: 1000));
    
    // 模拟返回 IP 地址
    // 在实际应用中,你可以使用网络请求获取真实的 IP 地址
    return '192.168.1.100';
  }
  
  // 获取详细的网络信息
  Future<Map<String, String>> getNetworkInfo() async {
    // 模拟网络请求延迟
    await Future.delayed(const Duration(milliseconds: 1200));
    
    // 模拟返回网络信息
    return {
      'ip': '192.168.1.100',
      'ipv6': '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
      'mac': '00:1B:44:11:3A:B7',
      'hostname': 'device.local'
    };
  }
}

实现说明

  1. 核心功能

    • getIPAddress 方法:获取设备的IP地址
    • getNetworkInfo 方法:获取详细的网络信息,包括IPv4、IPv6、MAC地址和主机名
  2. 实现细节

    • 使用 Future.delayed 模拟网络请求延迟,增强真实感
    • 模拟返回固定的IP地址和网络信息
    • 在实际应用中,可以替换为真实的网络请求获取真实的IP地址
  3. 使用方法

    final getIpAddress = GetIpAddress();
    // 获取IP地址
    final ip = await getIpAddress.getIPAddress();
    // 获取详细网络信息
    final networkInfo = await getIpAddress.getNetworkInfo();
    

2. IpAddressWidget 组件实现

为了提供直观的用户界面,我们创建了 IpAddressWidget 组件,用于展示获取IP地址的功能。

核心实现代码

import 'package:flutter/material.dart';
import 'get_ip_address.dart';

class IpAddressWidget extends StatefulWidget {
  const IpAddressWidget({super.key});

  
  State<IpAddressWidget> createState() => _IpAddressWidgetState();
}

class _IpAddressWidgetState extends State<IpAddressWidget> {
  String _ipAddress = '';
  Map<String, String> _networkInfo = {};
  bool _isLoading = false;
  bool _hasResult = false;
  bool _showDetailedInfo = false;

  final GetIpAddress _getIpAddress = GetIpAddress();

  Future<void> _getIp() async {
    setState(() {
      _isLoading = true;
      _hasResult = false;
      _showDetailedInfo = false;
    });

    try {
      final ip = await _getIpAddress.getIPAddress();

      setState(() {
        _ipAddress = ip;
        _hasResult = true;
        _isLoading = false;
      });
    } catch (e) {
      setState(() {
        _ipAddress = '获取 IP 地址失败';
        _hasResult = true;
        _isLoading = false;
      });
    }
  }

  Future<void> _getDetailedInfo() async {
    setState(() {
      _isLoading = true;
    });

    try {
      final info = await _getIpAddress.getNetworkInfo();

      setState(() {
        _networkInfo = info;
        _showDetailedInfo = true;
        _isLoading = false;
      });
    } catch (e) {
      setState(() {
        _isLoading = false;
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(
            content: Text('获取网络信息失败'),
            duration: Duration(seconds: 1),
          ),
        );
      });
    }
  }

  
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(20.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          const Text(
            '获取 IP 地址',
            style: TextStyle(
              fontSize: 20.0,
              fontWeight: FontWeight.bold,
            ),
            textAlign: TextAlign.center,
          ),
          const SizedBox(height: 20.0),
          ElevatedButton(
            onPressed: _isLoading ? null : _getIp,
            style: ElevatedButton.styleFrom(
              padding: const EdgeInsets.symmetric(vertical: 15.0),
            ),
            child: _isLoading
                ? const SizedBox(
                    height: 20.0,
                    width: 20.0,
                    child: CircularProgressIndicator(
                      strokeWidth: 2.0,
                      valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
                    ),
                  )
                : const Text('获取 IP 地址'),
          ),
          const SizedBox(height: 20.0),
          if (_hasResult)
            Container(
              padding: const EdgeInsets.all(15.0),
              decoration: BoxDecoration(
                color: Colors.blue.shade50,
                borderRadius: BorderRadius.circular(8.0),
                border: Border.all(color: Colors.blue.shade200),
              ),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  const Text(
                    '获取结果:',
                    style: TextStyle(
                      fontWeight: FontWeight.bold,
                      fontSize: 16.0,
                    ),
                  ),
                  const SizedBox(height: 10.0),
                  Row(
                    children: [
                      const Icon(Icons.network_check, color: Colors.blue),
                      const SizedBox(width: 10.0),
                      Text('IP 地址:$_ipAddress'),
                    ],
                  ),
                  const SizedBox(height: 15.0),
                  ElevatedButton(
                    onPressed: _isLoading ? null : _getDetailedInfo,
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.blue.shade100,
                      foregroundColor: Colors.blue,
                      padding: const EdgeInsets.symmetric(vertical: 8.0),
                    ),
                    child: const Text('获取详细网络信息'),
                  ),
                  if (_showDetailedInfo && _networkInfo.isNotEmpty)
                    Container(
                      margin: const EdgeInsets.only(top: 15.0),
                      padding: const EdgeInsets.all(10.0),
                      decoration: BoxDecoration(
                        color: Colors.white,
                        borderRadius: BorderRadius.circular(6.0),
                        border: Border.all(color: Colors.blue.shade100),
                      ),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          const Text(
                            '详细网络信息:',
                            style: TextStyle(
                              fontWeight: FontWeight.bold,
                              fontSize: 14.0,
                            ),
                          ),
                          const SizedBox(height: 8.0),
                          Text('• IPv4:${_networkInfo['ip']}'),
                          Text('• IPv6:${_networkInfo['ipv6']}'),
                          Text('• MAC 地址:${_networkInfo['mac']}'),
                          Text('• 主机名:${_networkInfo['hostname']}'),
                        ],
                      ),
                    ),
                ],
              ),
            ),
          const SizedBox(height: 30.0),
          Card(
            elevation: 2.0,
            margin: const EdgeInsets.symmetric(horizontal: 0),
            child: Padding(
              padding: const EdgeInsets.all(15.0),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  const Text(
                    '功能说明:',
                    style: TextStyle(
                      fontWeight: FontWeight.bold,
                      fontSize: 14.0,
                    ),
                  ),
                  const SizedBox(height: 8.0),
                  Text('• 点击"获取 IP 地址"按钮获取设备 IP 地址'),
                  Text('• 点击"获取详细网络信息"按钮获取更多网络信息'),
                  Text('• 支持 IPv4、IPv6、MAC 地址和主机名信息'),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

实现说明

  1. 核心功能

    • 提供获取IP地址的按钮和界面
    • 展示获取到的IP地址
    • 提供获取详细网络信息的功能
    • 显示详细的网络信息,包括IPv4、IPv6、MAC地址和主机名
  2. 实现细节

    • 使用 StatefulWidget 管理组件状态
    • 实现 _getIp 方法处理获取IP地址的逻辑
    • 实现 _getDetailedInfo 方法处理获取详细网络信息的逻辑
    • 使用 setState 更新UI状态
    • 添加加载指示器提升用户体验
    • 实现错误处理,捕获获取IP地址失败的情况
    • 提供详细网络信息的展示区域
  3. 使用方法

    • 在需要使用获取IP地址功能的页面中直接引入该组件
    • 例如在 main.dart 中:
    import 'ip_address_widget.dart';
    
    // 在 build 方法中使用
    
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: const IpAddressWidget(),
      );
    }
    

3. 首页集成实现

将获取IP地址组件集成到应用首页,直接展示功能效果。

核心实现代码

import 'package:flutter/material.dart';
import 'ip_address_widget.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter for openHarmony',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      debugShowCheckedModeBanner: false,
      home: const MyHomePage(title: 'Flutter for openHarmony'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: const IpAddressWidget(),
    );
  }
}

实现说明

  1. 集成方式

    • main.dart 中导入 IpAddressWidget 组件
    • MyHomePagebuild 方法中直接使用该组件
    • 无需按钮跳转,直接在首页展示功能
  2. 用户体验

    • 简洁明了的界面布局
    • 直观的操作流程
    • 实时的反馈机制
    • 美观的视觉效果

本次开发中容易遇到的问题

  1. 平台兼容性问题

    • 问题:Flutter的第三方库在OpenHarmony平台上可能存在兼容性问题
    • 解决方案:通过模拟实现核心功能,避免直接依赖平台特定的API,确保在OpenHarmony上正常运行
  2. 网络权限问题

    • 问题:获取IP地址需要网络权限,不同平台的权限申请方式可能不同
    • 解决方案:在实际应用中,需要根据OpenHarmony平台的权限申请机制,添加相应的权限配置
  3. 网络请求问题

    • 问题:在模拟实现中,使用了延迟来模拟网络请求,但实际应用中需要处理真实的网络请求
    • 解决方案:在实际应用中,应使用 httpdio 等库进行网络请求,并添加适当的错误处理
  4. IP地址获取方式问题

    • 问题:不同平台获取IP地址的方式可能不同
    • 解决方案:在实际应用中,需要根据不同平台的特性,选择合适的IP地址获取方式
  5. 性能优化问题

    • 问题:频繁获取IP地址可能会影响应用性能
    • 解决方案:在实际应用中,可以考虑使用缓存机制,减少重复的网络请求

总结本次开发中用到的技术点

  1. Flutter组件开发

    • 使用 StatefulWidgetStatelessWidget 构建UI
    • 利用 setState 管理组件状态
    • 实现异步操作和错误处理
  2. 异步编程

    • 使用 async/await 处理异步操作
    • 利用 Future 管理异步任务
    • 实现加载状态和错误处理
  3. 网络信息获取

    • 实现IP地址获取功能
    • 实现详细网络信息获取功能
    • 模拟网络请求和响应
  4. 用户界面设计

    • 响应式布局设计
    • 美观的视觉效果
    • 直观的用户交互
    • 良好的错误反馈机制
  5. OpenHarmony适配

    • 通过模拟实现适配OpenHarmony平台
    • 确保代码在不同平台上的兼容性
    • 优化用户体验,适应不同设备的屏幕尺寸
  6. 代码组织

    • 模块化设计,将功能拆分为独立的组件
    • 清晰的代码结构和命名规范
    • 良好的注释和文档

本次开发成功实现了Flutter三方库get_ip_address在OpenHarmony平台的适配,为开发者提供了一套完整的IP地址获取解决方案。通过模块化的设计和清晰的实现,不仅满足了功能需求,也为后续的扩展和维护提供了便利。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐