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

目录

前言:跨生态开发的新机遇

在移动开发领域,我们总是面临着选择与适配。今天,你的Flutter应用在Android和iOS上跑得正欢,明天可能就需要考虑一个新的平台:HarmonyOS(鸿蒙)。这不是一道选答题,而是很多团队正在面对的现实。

Flutter的优势很明确——写一套代码,就能在两个主要平台上运行,开发体验流畅。而鸿蒙代表的是下一个时代的互联生态,它不仅仅是手机系统,更着眼于未来全场景的体验。将现有的Flutter应用适配到鸿蒙,听起来像是一个“跨界”任务,但它本质上是一次有价值的技术拓展:让产品触达更多用户,也让技术栈覆盖更广。

不过,这条路走起来并不像听起来那么简单。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. DailyHoroscope 组件

DailyHoroscope 是本次开发的核心组件,负责实现每日运势查看功能,包括星座选择、运势详情展示和交互效果。

组件结构设计
class ZodiacSign {
  final String name;
  final String symbol;
  final Color color;

  ZodiacSign({
    required this.name,
    required this.symbol,
    required this.color,
  });
}

class HoroscopeData {
  final String zodiacSign;
  final String date;
  final String overall;
  final String love;
  final String career;
  final String health;
  final String finance;
  final String luckyNumber;
  final String luckyColor;

  HoroscopeData({
    required this.zodiacSign,
    required this.date,
    required this.overall,
    required this.love,
    required this.career,
    required this.health,
    required this.finance,
    required this.luckyNumber,
    required this.luckyColor,
  });
}

class DailyHoroscope extends StatefulWidget {
  const DailyHoroscope({Key? key}) : super(key: key);

  
  State<DailyHoroscope> createState() => _DailyHoroscopeState();
}

设计思路

  • 使用 StatefulWidget 来管理组件状态,支持实时 UI 更新
  • 创建 ZodiacSign 类来存储星座信息,包括名称、符号和颜色
  • 创建 HoroscopeData 类来存储运势数据,包括整体运势、爱情、事业、健康、财运等信息
状态管理实现
class _DailyHoroscopeState extends State<DailyHoroscope> {
  final List<ZodiacSign> _zodiacSigns = [
    ZodiacSign(name: '白羊座', symbol: '♈', color: Colors.red),
    ZodiacSign(name: '金牛座', symbol: '♉', color: Colors.green),
    ZodiacSign(name: '双子座', symbol: '♊', color: Colors.yellow),
    ZodiacSign(name: '巨蟹座', symbol: '♋', color: Colors.blue),
    ZodiacSign(name: '狮子座', symbol: '♌', color: Colors.orange),
    ZodiacSign(name: '处女座', symbol: '♍', color: Colors.purple),
    ZodiacSign(name: '天秤座', symbol: '♎', color: Colors.pink),
    ZodiacSign(name: '天蝎座', symbol: '♏', color: Colors.indigo),
    ZodiacSign(name: '射手座', symbol: '♐', color: Colors.teal),
    ZodiacSign(name: '摩羯座', symbol: '♑', color: Colors.brown),
    ZodiacSign(name: '水瓶座', symbol: '♒', color: Colors.cyan),
    ZodiacSign(name: '双鱼座', symbol: '♓', color: Colors.lightBlue),
  ];

  ZodiacSign? _selectedSign;
  HoroscopeData? _horoscopeData;

  void _selectZodiacSign(ZodiacSign sign) {
    setState(() {
      _selectedSign = sign;
      _horoscopeData = _generateHoroscopeData(sign);
    });
  }

  HoroscopeData _generateHoroscopeData(ZodiacSign sign) {
    // 生成模拟的运势数据
    return HoroscopeData(
      zodiacSign: sign.name,
      date: '${DateTime.now().year}${DateTime.now().month}${DateTime.now().day}日',
      overall: '今天整体运势不错,保持积极的心态,会有意外的惊喜。',
      love: '感情方面会有新的进展,单身的朋友可能会遇到心仪的对象。',
      career: '工作上会有新的机会,好好把握,展示自己的能力。',
      health: '身体健康状况良好,建议适当运动,保持良好的作息。',
      finance: '财运亨通,可能会有意外的收入,建议合理规划支出。',
      luckyNumber: (1 + DateTime.now().day % 9).toString(),
      luckyColor: _getLuckyColor(sign),
    );
  }

  String _getLuckyColor(ZodiacSign sign) {
    Map<Color, String> colorNames = {
      Colors.red: '红色',
      Colors.green: '绿色',
      Colors.yellow: '黄色',
      Colors.blue: '蓝色',
      Colors.orange: '橙色',
      Colors.purple: '紫色',
      Colors.pink: '粉色',
      Colors.indigo: '靛蓝色',
      Colors.teal: '青色',
      Colors.brown: '棕色',
      Colors.cyan: '蓝绿色',
      Colors.lightBlue: '浅蓝色',
    };
    return colorNames[sign.color] ?? '彩色';
  }

关键状态变量

  • _zodiacSigns:存储12个星座的信息,包括名称、符号和颜色
  • _selectedSign:存储当前选择的星座
  • _horoscopeData:存储当前星座的运势数据

核心方法

  • _selectZodiacSign:处理星座选择逻辑,更新状态并生成运势数据
  • _generateHoroscopeData:根据选择的星座生成模拟的运势数据
  • _getLuckyColor:根据星座颜色获取对应的中文颜色名称
星座选择实现
Widget _buildZodiacSignItem(ZodiacSign sign) {
  bool isSelected = _selectedSign?.name == sign.name;
  return GestureDetector(
    onTap: () => _selectZodiacSign(sign),
    child: Container(
      margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
      decoration: BoxDecoration(
        color: isSelected ? sign.color.withOpacity(0.2) : Colors.grey.shade100,
        borderRadius: BorderRadius.circular(12),
        border: Border.all(
          color: isSelected ? sign.color : Colors.grey.shade300,
          width: isSelected ? 2 : 1,
        ),
      ),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        mainAxisSize: MainAxisSize.min,
        children: [
          Text(
            sign.symbol,
            style: TextStyle(
              fontSize: 20,
              color: sign.color,
            ),
          ),
          const SizedBox(height: 2),
          Text(
            sign.name,
            style: TextStyle(
              fontSize: 12,
              color: isSelected ? sign.color : Colors.grey.shade700,
              fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
            ),
          ),
        ],
      ),
    ),
  );
}

实现要点

  • 使用 GestureDetector 实现星座卡片的点击交互
  • 根据是否选中状态,调整卡片的背景色、边框和文字样式
  • 使用 Column 布局展示星座符号和名称
  • 设置 mainAxisSize: MainAxisSize.min 确保卡片高度合理
运势卡片实现
Widget _buildHoroscopeCard() {
  if (_horoscopeData == null) {
    return Container(
      margin: const EdgeInsets.only(top: 32),
      padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 64),
      decoration: BoxDecoration(
        color: Colors.grey.shade50,
        borderRadius: BorderRadius.circular(16),
        border: Border.all(
          color: Colors.grey.shade200,
          width: 1,
        ),
      ),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(
            Icons.star_outline,
            size: 48,
            color: Colors.grey.shade300,
          ),
          const SizedBox(height: 16),
          Text(
            '请选择一个星座查看今日运势',
            style: TextStyle(
              fontSize: 16,
              color: Colors.grey.shade500,
            ),
            textAlign: TextAlign.center,
          ),
        ],
      ),
    );
  }

  return Container(
    margin: const EdgeInsets.only(top: 32),
    padding: const EdgeInsets.all(24),
    decoration: BoxDecoration(
      color: _selectedSign!.color.withOpacity(0.05),
      borderRadius: BorderRadius.circular(16),
      border: Border.all(
        color: _selectedSign!.color.withOpacity(0.3),
        width: 1,
      ),
    ),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        // 标题
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text(
              '${_horoscopeData!.zodiacSign} ${_zodiacSigns.firstWhere((sign) => sign.name == _horoscopeData!.zodiacSign).symbol}',
              style: TextStyle(
                fontSize: 24,
                fontWeight: FontWeight.bold,
                color: _selectedSign!.color,
              ),
            ),
            Text(
              _horoscopeData!.date,
              style: TextStyle(
                fontSize: 14,
                color: Colors.grey.shade600,
              ),
            ),
          ],
        ),
        const SizedBox(height: 24),

        // 运势详情
        _buildHoroscopeItem('整体运势', _horoscopeData!.overall),
        const SizedBox(height: 16),
        _buildHoroscopeItem('爱情运势', _horoscopeData!.love),
        const SizedBox(height: 16),
        _buildHoroscopeItem('事业运势', _horoscopeData!.career),
        const SizedBox(height: 16),
        _buildHoroscopeItem('健康运势', _horoscopeData!.health),
        const SizedBox(height: 16),
        _buildHoroscopeItem('财运', _horoscopeData!.finance),
        const SizedBox(height: 24),

        // 幸运数字和颜色
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Container(
              padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(8),
                boxShadow: [
                  BoxShadow(
                    color: Colors.grey.shade200,
                    spreadRadius: 1,
                    blurRadius: 2,
                    offset: const Offset(0, 1),
                  ),
                ],
              ),
              child: Text(
                '幸运数字: ${_horoscopeData!.luckyNumber}',
                style: TextStyle(
                  fontSize: 14,
                  color: _selectedSign!.color,
                ),
              ),
            ),
            Container(
              padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(8),
                boxShadow: [
                  BoxShadow(
                    color: Colors.grey.shade200,
                    spreadRadius: 1,
                    blurRadius: 2,
                    offset: const Offset(0, 1),
                  ),
                ],
              ),
              child: Row(
                children: [
                  Text(
                    '幸运颜色: ',
                    style: TextStyle(
                      fontSize: 14,
                      color: _selectedSign!.color,
                    ),
                  ),
                  Container(
                    width: 16,
                    height: 16,
                    margin: const EdgeInsets.only(left: 8),
                    decoration: BoxDecoration(
                      color: _selectedSign!.color,
                      borderRadius: BorderRadius.circular(4),
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ],
    ),
  );
}

实现要点

  • 处理两种状态:未选择星座时显示提示信息,选择星座后显示运势详情
  • 运势卡片的颜色会根据选择的星座动态变化,增强视觉效果
  • 显示完整的运势信息,包括整体运势、爱情、事业、健康、财运等
  • 展示幸运数字和幸运颜色,提供更多个性化信息
主界面布局

Widget build(BuildContext context) {
  return Container(
    padding: const EdgeInsets.all(24),
    margin: const EdgeInsets.all(16),
    decoration: BoxDecoration(
      color: Colors.white,
      borderRadius: BorderRadius.circular(16),
      boxShadow: [
        BoxShadow(
          color: Colors.grey.shade200,
          spreadRadius: 2,
          blurRadius: 8,
          offset: const Offset(0, 4),
        ),
      ],
    ),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        // 标题
        Text(
          '每日运势',
          style: TextStyle(
            fontSize: 24,
            fontWeight: FontWeight.bold,
            color: Colors.deepPurple,
          ),
        ),
        const SizedBox(height: 8),
        Text(
          '选择星座查看今日运势',
          style: TextStyle(
            fontSize: 16,
            color: Colors.grey.shade600,
          ),
        ),
        const SizedBox(height: 24),

        // 星座选择
        SizedBox(
          height: 80,
          child: ListView.builder(
            scrollDirection: Axis.horizontal,
            itemCount: _zodiacSigns.length,
            itemBuilder: (context, index) {
              return _buildZodiacSignItem(_zodiacSigns[index]);
            },
          ),
        ),

        // 运势卡片
        _buildHoroscopeCard(),
      ],
    ),
  );
}

布局要点

  • 使用卡片式布局,添加阴影效果提升视觉层次感
  • 顶部显示标题和提示文字
  • 中间使用水平滚动的 ListView 展示星座选择卡片
  • 底部显示运势详情卡片

2. 主页面集成

main.dart 文件修改
import 'package:flutter/material.dart';
import 'components/daily_horoscope.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),
        backgroundColor: Colors.deepPurple,
      ),
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: DailyHoroscope(),
        ),
      ),
    );
  }
}

集成要点

  • 导入 DailyHoroscope 组件
  • MyHomePagebuild 方法中直接使用该组件
  • 使用 SafeAreaPadding 确保在不同设备上的良好显示效果

使用方法

1. 组件导入

在需要使用每日运势功能的页面中导入组件:

import 'components/daily_horoscope.dart';

2. 组件使用

直接在页面的 build 方法中添加组件:


Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: DailyHoroscope(),
    ),
  );
}

3. 功能操作

  • 选择星座:在水平滚动的星座列表中点击选择一个星座
  • 查看运势:选择星座后,下方会显示该星座的今日运势详情
  • 运势内容:包括整体运势、爱情运势、事业运势、健康运势、财运、幸运数字和幸运颜色

开发注意事项

  1. 性能优化

    • 使用 ListView.builder 实现水平滚动的星座选择列表,提高渲染性能
    • 合理设置容器的边距和内边距,确保布局紧凑且美观
  2. 状态管理

    • 使用 setState 管理组件状态,确保 UI 能够及时反映状态变化
    • 避免在 build 方法中进行复杂的计算,提高渲染效率
  3. UI 设计

    • 为每个星座设计独特的颜色标识,增强视觉辨识度
    • 使用 mainAxisSize: MainAxisSize.min 确保组件只占用必要的空间
    • 为选中状态的星座卡片添加特殊样式,提供清晰的视觉反馈
  4. 跨平台兼容

    • 使用 Flutter 的内置组件和 API,确保在不同平台(包括 OpenHarmony)上的一致性
    • 避免使用平台特定的功能,保持代码的通用性

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

1. 垂直溢出问题

问题描述
在运行应用时,可能会遇到 RenderFlex overflowed 错误,提示垂直方向的内容溢出。

解决方案

  • 调整星座卡片的边距和内边距,减少垂直方向的空间占用
  • 使用 mainAxisSize: MainAxisSize.min 确保 Column 只占用必要的空间
  • 调整字体大小和间距,使内容更加紧凑

注意事项

  • 在设计卡片布局时,应考虑到不同设备的屏幕尺寸
  • 使用 SizedBox 控制容器高度,避免内容无限制扩展

2. 中文标识符问题

问题描述
在定义变量或属性时,使用中文标识符(如 “财运”)会导致编译错误。

解决方案

  • 使用英文标识符(如 “finance”)代替中文标识符
  • 保持代码的一致性,使用英文命名变量和属性

注意事项

  • Dart 语言规范推荐使用英文标识符
  • 中文标识符可能在不同的开发环境中产生兼容性问题

3. 依赖管理问题

问题描述
使用第三方库(如 intl)时,可能会遇到依赖冲突或版本不兼容的问题。

解决方案

  • 尽量减少对第三方库的依赖,优先使用 Flutter 内置的功能
  • 如需使用第三方库,确保在 pubspec.yaml 中正确配置版本

注意事项

  • 过多的依赖会增加应用的体积和复杂度
  • 内置功能通常具有更好的跨平台兼容性

4. 布局适配问题

问题描述
在不同尺寸的设备上,布局可能会出现不一致的情况。

解决方案

  • 使用 SafeArea 确保内容不会被设备刘海或底部导航栏遮挡
  • 使用 Padding 为组件添加适当的边距
  • 避免使用固定尺寸,优先使用相对尺寸和弹性布局

注意事项

  • 测试应用在不同尺寸设备上的显示效果
  • 考虑横屏和竖屏两种显示模式

5. 交互反馈问题

问题描述
用户操作后,应用没有提供足够的视觉反馈,影响用户体验。

解决方案

  • 为可点击的元素添加点击效果,如颜色变化或动画
  • 为不同状态的组件设计不同的样式,提供清晰的视觉反馈
  • 使用 GestureDetectorInkWell 实现丰富的触摸交互

注意事项

  • 交互反馈应及时且明确,让用户知道操作是否成功
  • 避免过度的动画效果,以免分散用户注意力

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

核心技术栈

1. Flutter 基础组件

  • StatefulWidget:用于管理每日运势组件的状态,支持实时 UI 更新
  • Container:实现卡片式布局,添加阴影效果提升视觉层次感
  • Row/Column:用于组织 UI 元素的布局结构
  • ListView.builder:高效实现水平滚动的星座选择列表
  • GestureDetector:实现星座卡片的点击交互
  • Text:显示标题、运势详情等文本信息
  • Icon:显示提示图标

2. 状态管理

  • setState:触发 UI 更新,反映状态变化
  • 状态变量:管理选中的星座和运势数据
  • 条件渲染:根据是否选择星座显示不同的 UI 内容

3. 数据模型

  • 自定义类:创建 ZodiacSignHoroscopeData 类来组织和管理数据
  • 数据结构:使用列表存储星座信息,使用对象存储运势数据

4. UI 设计与用户体验

  • 响应式布局:使用 SafeAreaPadding 确保在不同设备上的良好显示效果
  • 视觉反馈:为选中的星座卡片添加特殊样式,提供清晰的视觉反馈
  • 色彩设计:为每个星座设计独特的颜色标识,增强视觉辨识度
  • 间距管理:合理设置容器的边距和内边距,确保布局紧凑且美观

5. 跨平台兼容

  • Flutter 跨平台特性:使用 Flutter 的内置组件和 API,确保在不同平台(包括 OpenHarmony)上的一致性
  • 平台无关代码:避免使用平台特定的功能,保持代码的通用性
  • 内置功能:优先使用 Flutter 内置的功能,减少对第三方库的依赖

技术亮点

  1. 模块化设计

    • 将每日运势功能封装为独立的 DailyHoroscope 组件,提高代码复用性
    • 使用自定义类组织数据,使代码结构更加清晰
  2. 交互体验

    • 实现了流畅的星座选择交互,提供清晰的视觉反馈
    • 运势卡片会根据选择的星座动态更新颜色和内容
    • 添加了水平滚动的星座选择列表,提升用户体验
  3. 视觉设计

    • 使用卡片式布局和阴影效果,提升界面的层次感
    • 为每个星座设计独特的颜色标识,增强视觉辨识度
    • 运势卡片的颜色会根据选择的星座动态变化,提供个性化的视觉体验
  4. 性能优化

    • 使用 ListView.builder 实现水平滚动的星座选择列表,提高渲染性能
    • 合理设置容器的边距和内边距,确保布局紧凑且美观
    • 避免在 build 方法中进行复杂的计算,提高渲染效率
  5. 跨平台适配

    • 使用 Flutter 的内置组件和 API,确保在不同平台上的一致性
    • 避免使用平台特定的功能,保持代码的通用性
    • 使用 SafeArea 确保内容不会被设备刘海或底部导航栏遮挡

开发经验总结

  1. 组件化开发

    • 将复杂功能拆分为独立组件,提高代码复用性和可维护性
    • 组件设计应考虑到灵活性和可扩展性,便于在不同场景中使用
  2. 状态管理

    • 合理使用 setState 管理组件状态,确保 UI 能够及时反映状态变化
    • 状态变量的设计应简洁明了,避免冗余和复杂的状态结构
  3. UI 设计

    • 注重用户体验,为交互元素提供清晰的视觉反馈
    • 合理运用色彩和间距,创建美观且易用的界面
    • 考虑不同设备的屏幕尺寸,确保布局的适配性
  4. 性能优化

    • 对于列表等重复元素,使用 ListView.builder 等高效的渲染方式
    • 避免在 build 方法中进行复杂的计算,提高渲染效率
    • 合理设置容器的大小和边距,避免内容溢出
  5. 跨平台开发

    • 优先使用 Flutter 的内置功能,减少对第三方库的依赖
    • 避免使用平台特定的功能,保持代码的通用性
    • 测试应用在不同平台上的显示效果,确保一致性

通过本次开发,我们成功实现了一个功能完整、界面美观的每日运势应用,并确保其在 OpenHarmony 平台上的正常运行。这不仅展示了 Flutter 的跨平台能力,也为未来的跨生态开发积累了宝贵的经验。

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

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐