第30篇:设置与帮助系统

📚 本篇导读

设置与帮助系统是应用的重要组成部分,为用户提供个性化配置、通知管理、隐私设置、使用帮助和反馈渠道。本篇教程将实现一个完整的设置与帮助系统。

本篇将实现

  • ⚙️ 应用设置(主题、语言、通知等)
  • 🔔 通知设置(推送通知、提醒管理)
  • 🔐 隐私设置(权限管理、数据隐私)
  • 📖 帮助中心(使用指南、常见问题)
  • ℹ️ 关于页面(版本信息、用户协议)
  • 💬 用户反馈(问题反馈、建议提交)

🎯 学习目标

完成本篇教程后,你将掌握:

  1. 如何设计和实现应用设置页面
  2. 如何管理应用通知和权限
  3. 如何实现帮助文档系统
  4. 如何处理用户反馈
  5. 应用配置的持久化管理
  6. 用户协议和隐私政策的展示

一、功能架构设计

1.1 设置系统功能结构

设置与帮助系统
├── 通知设置页面
│   ├── 任务提醒开关
│   ├── 天气预警开关
│   ├── 节气提醒开关
│   └── 提醒时间设置
│
├── 隐私设置页面
│   ├── 权限管理
│   ├── 数据收集说明
│   ├── 账号安全
│   └── 隐私政策
│
├── 帮助中心页面
│   ├── 快速入门
│   ├── 功能介绍
│   ├── 常见问题
│   └── 视频教程
│
├── 关于页面
│   ├── 应用信息
│   ├── 版本号
│   ├── 用户协议
│   ├── 隐私政策
│   └── 开源许可
│
└── 反馈页面
    ├── 问题反馈
    ├── 功能建议
    └── 联系我们

1.2 数据模型设计

/**
 * 应用设置
 */
interface AppSettings {
  // 通知设置
  notifications: {
    taskReminder: boolean;
    weatherAlert: boolean;
    solarTermReminder: boolean;
    reminderTime: string;
  };
  
  // 隐私设置
  privacy: {
    dataCollection: boolean;
    locationSharing: boolean;
    crashReporting: boolean;
  };
  
  // 显示设置
  display: {
    theme: 'light' | 'dark' | 'auto';
    language: string;
    fontSize: 'small' | 'medium' | 'large';
  };
  
  // 其他设置
  other: {
    autoBackup: boolean;
    wifiOnlySync: boolean;
  };
}

/**
 * 反馈信息
 */
interface Feedback {
  id: string;
  type: 'bug' | 'feature' | 'other';
  title: string;
  content: string;
  contact: string;
  images: string[];
  createdAt: number;
  status: 'pending' | 'processing' | 'resolved';
}

二、实现通知设置页面

2.1 页面结构

文件位置entry/src/main/ets/pages/Services/NotificationSettingsPage.ets

import { router } from '@kit.ArkUI';
import { promptAction } from '@kit.ArkUI';
import { StorageUtil } from '../../utils/StorageUtil';
import { notificationManager } from '@kit.NotificationKit';

@Entry
@ComponentV2
struct NotificationSettingsPage {
  @Local taskReminder: boolean = true;
  @Local weatherAlert: boolean = true;
  @Local solarTermReminder: boolean = true;
  @Local reminderTime: string = '09:00';
  @Local notificationEnabled: boolean = false;

  async aboutToAppear(): Promise<void> {
    await this.loadSettings();
    await this.checkNotificationPermission();
  }

  /**
   * 加载通知设置
   */
  async loadSettings(): Promise<void> {
    this.taskReminder = await StorageUtil.getBoolean('task_reminder', true);
    this.weatherAlert = await StorageUtil.getBoolean('weather_alert', true);
    this.solarTermReminder = await StorageUtil.getBoolean('solar_term_reminder', true);
    this.reminderTime = await StorageUtil.getString('reminder_time', '09:00');
  }

  /**
   * 检查通知权限
   */
  async checkNotificationPermission(): Promise<void> {
    try {
      this.notificationEnabled = await notificationManager.isNotificationEnabled();
    } catch (error) {
      console.error('Failed to check notification permission:', error);
    }
  }

  build() {
    Column() {
      // 头部导航
      this.buildHeader()

      Scroll() {
        Column({ space: 16 }) {
          // 通知权限状态
          this.buildPermissionStatus()

          // 提醒设置
          this.buildReminderSettings()

          // 提醒时间
          this.buildReminderTime()
        }
        .padding(16)
      }
      .layoutWeight(1)
    }
    .width('100%')
    .height('100%')
    .backgroundColor($r('app.color.background'))
  }
}

2.2 通知权限状态

显示当前通知权限状态并提供开启入口:

@Builder
buildPermissionStatus() {
  Column({ space: 12 }) {
    Row() {
      Column({ space: 4 }) {
        Text('通知权限')
          .fontSize(15)
          .fontWeight(FontWeight.Medium)
        Text(this.notificationEnabled ? '已开启' : '未开启')
          .fontSize(12)
          .fontColor(this.notificationEnabled ? 
            $r('app.color.success') : $r('app.color.danger'))
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)

      if (!this.notificationEnabled) {
        Button('去开启')
          .height(36)
          .fontSize(14)
          .onClick(() => {
            this.openNotificationSettings();
          })
      }
    }
    .width('100%')
    .padding(16)
    .backgroundColor($r('app.color.card_background'))
    .borderRadius(12)

    if (!this.notificationEnabled) {
      Text('开启通知权限后,您将及时收到任务提醒、天气预警等重要信息')
        .fontSize(12)
        .fontColor($r('app.color.text_secondary'))
        .width('100%')
    }
  }
  .width('100%')
}

/**
 * 打开系统通知设置
 */
openNotificationSettings(): void {
  // 跳转到系统设置页面
  promptAction.showToast({
    message: '请在系统设置中开启通知权限',
    duration: 2000
  });
}

2.3 提醒设置开关

提供各类提醒的开关控制:

@Builder
buildReminderSettings() {
  Column({ space: 12 }) {
    Text('提醒设置')
      .fontSize(16)
      .fontWeight(FontWeight.Bold)
      .width('100%')

    // 任务提醒
    Row() {
      Column({ space: 4 }) {
        Text('📋 任务提醒')
          .fontSize(15)
          .fontWeight(FontWeight.Medium)
        Text('到期任务和待办事项提醒')
          .fontSize(12)
          .fontColor($r('app.color.text_secondary'))
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)

      Toggle({ type: ToggleType.Switch, isOn: $$this.taskReminder })
        .onChange(async (isOn: boolean) => {
          this.taskReminder = isOn;
          await StorageUtil.setBoolean('task_reminder', isOn);
        })
    }
    .width('100%')
    .padding(12)
    .backgroundColor($r('app.color.background'))
    .borderRadius(8)

    // 天气预警
    Row() {
      Column({ space: 4 }) {
        Text('🌤️ 天气预警')
          .fontSize(15)
          .fontWeight(FontWeight.Medium)
        Text('恶劣天气和气象灾害预警')
          .fontSize(12)
          .fontColor($r('app.color.text_secondary'))
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)

      Toggle({ type: ToggleType.Switch, isOn: $$this.weatherAlert })
        .onChange(async (isOn: boolean) => {
          this.weatherAlert = isOn;
          await StorageUtil.setBoolean('weather_alert', isOn);
        })
    }
    .width('100%')
    .padding(12)
    .backgroundColor($r('app.color.background'))
    .borderRadius(8)

    // 节气提醒
    Row() {
      Column({ space: 4 }) {
        Text('🌾 节气提醒')
          .fontSize(15)
          .fontWeight(FontWeight.Medium)
        Text('二十四节气和农事建议')
          .fontSize(12)
          .fontColor($r('app.color.text_secondary'))
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)

      Toggle({ type: ToggleType.Switch, isOn: $$this.solarTermReminder })
        .onChange(async (isOn: boolean) => {
          this.solarTermReminder = isOn;
          await StorageUtil.setBoolean('solar_term_reminder', isOn);
        })
    }
    .width('100%')
    .padding(12)
    .backgroundColor($r('app.color.background'))
    .borderRadius(8)
  }
  .width('100%')
  .padding(16)
  .backgroundColor($r('app.color.card_background'))
  .borderRadius(12)
}

2.4 提醒时间设置

设置每日提醒的时间:

@Builder
buildReminderTime() {
  Column({ space: 12 }) {
    Text('提醒时间')
      .fontSize(16)
      .fontWeight(FontWeight.Bold)
      .width('100%')

    Row() {
      Column({ space: 4 }) {
        Text('⏰ 每日提醒时间')
          .fontSize(15)
          .fontWeight(FontWeight.Medium)
        Text('设置每天接收提醒的时间')
          .fontSize(12)
          .fontColor($r('app.color.text_secondary'))
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)

      Text(this.reminderTime)
        .fontSize(15)
        .fontColor($r('app.color.primary_professional'))
        .onClick(() => {
          this.showTimePickerDialog();
        })
    }
    .width('100%')
    .padding(16)
    .backgroundColor($r('app.color.background'))
    .borderRadius(8)
  }
  .width('100%')
  .padding(16)
  .backgroundColor($r('app.color.card_background'))
  .borderRadius(12)
}

/**
 * 显示时间选择器
 */
showTimePickerDialog(): void {
  // 使用TimePickerDialog选择时间
  const currentTime = this.reminderTime.split(':');
  const hour = parseInt(currentTime[0]);
  const minute = parseInt(currentTime[1]);

  TimePickerDialog.show({
    selected: new Date(2024, 0, 1, hour, minute),
    onAccept: async (value: TimePickerResult) => {
      const h = value.hour?.toString().padStart(2, '0');
      const m = value.minute?.toString().padStart(2, '0');
      this.reminderTime = `${h}:${m}`;
      await StorageUtil.setString('reminder_time', this.reminderTime);

      promptAction.showToast({
        message: `提醒时间已设置为 ${this.reminderTime}`,
        duration: 2000
      });
    }
  });
}

三、实现隐私设置页面

3.1 页面结构

文件位置entry/src/main/ets/pages/Services/PrivacySettingsPage.ets

import { router } from '@kit.ArkUI';
import { promptAction } from '@kit.ArkUI';
import { StorageUtil } from '../../utils/StorageUtil';
import { abilityAccessCtrl, Permissions } from '@kit.AbilityKit';

@Entry
@ComponentV2
struct PrivacySettingsPage {
  @Local dataCollection: boolean = true;
  @Local crashReporting: boolean = true;
  @Local locationPermission: boolean = false;
  @Local cameraPermission: boolean = false;
  @Local storagePermission: boolean = false;

  async aboutToAppear(): Promise<void> {
    await this.loadSettings();
    await this.checkPermissions();
  }

  /**
   * 加载隐私设置
   */
  async loadSettings(): Promise<void> {
    this.dataCollection = await StorageUtil.getBoolean('data_collection', true);
    this.crashReporting = await StorageUtil.getBoolean('crash_reporting', true);
  }

  /**
   * 检查权限状态
   */
  async checkPermissions(): Promise<void> {
    try {
      const atManager = abilityAccessCtrl.createAtManager();

      // 检查定位权限
      this.locationPermission = await this.checkPermission(
        atManager, 'ohos.permission.APPROXIMATELY_LOCATION'
      );

      // 检查相机权限
      this.cameraPermission = await this.checkPermission(
        atManager, 'ohos.permission.CAMERA'
      );

      // 检查存储权限
      this.storagePermission = await this.checkPermission(
        atManager, 'ohos.permission.READ_MEDIA'
      );
    } catch (error) {
      console.error('Failed to check permissions:', error);
    }
  }

  /**
   * 检查单个权限
   */
  async checkPermission(atManager: abilityAccessCtrl.AtManager, permission: Permissions): Promise<boolean> {
    try {
      const grantStatus = await atManager.checkAccessToken(
        getContext(this).applicationInfo.accessTokenId,
        permission
      );
      return grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
    } catch (error) {
      return false;
    }
  }

  build() {
    Column() {
      // 头部导航
      this.buildHeader()

      Scroll() {
        Column({ space: 16 }) {
          // 权限管理
          this.buildPermissionSection()

          // 数据隐私
          this.buildPrivacySection()

          // 账号安全
          this.buildSecuritySection()
        }
        .padding(16)
      }
      .layoutWeight(1)
    }
    .width('100%')
    .height('100%')
    .backgroundColor($r('app.color.background'))
  }
}

3.2 权限管理区域

显示应用权限状态:

@Builder
buildPermissionSection() {
  Column({ space: 12 }) {
    Text('权限管理')
      .fontSize(16)
      .fontWeight(FontWeight.Bold)
      .width('100%')

    // 定位权限
    this.buildPermissionItem(
      '📍',
      '定位权限',
      '用于获取您的位置信息,提供天气和地块管理服务',
      this.locationPermission
    )

    // 相机权限
    this.buildPermissionItem(
      '📷',
      '相机权限',
      '用于拍照识别植物和记录农事活动',
      this.cameraPermission
    )

    // 存储权限
    this.buildPermissionItem(
      '📁',
      '存储权限',
      '用于保存图片和导出数据',
      this.storagePermission
    )
  }
  .width('100%')
  .padding(16)
  .backgroundColor($r('app.color.card_background'))
  .borderRadius(12)
}

@Builder
buildPermissionItem(icon: string, title: string, desc: string, granted: boolean) {
  Row() {
    Text(icon)
      .fontSize(24)
      .margin({ right: 12 })

    Column({ space: 4 }) {
      Text(title)
        .fontSize(15)
        .fontWeight(FontWeight.Medium)
      Text(desc)
        .fontSize(12)
        .fontColor($r('app.color.text_secondary'))
    }
    .alignItems(HorizontalAlign.Start)
    .layoutWeight(1)

    Text(granted ? '已授权' : '未授权')
      .fontSize(14)
      .fontColor(granted ? $r('app.color.success') : $r('app.color.text_secondary'))
  }
  .width('100%')
  .padding(12)
  .backgroundColor($r('app.color.background'))
  .borderRadius(8)
}

3.3 数据隐私设置

管理数据收集和使用:

@Builder
buildPrivacySection() {
  Column({ space: 12 }) {
    Text('数据隐私')
      .fontSize(16)
      .fontWeight(FontWeight.Bold)
      .width('100%')

    // 数据收集
    Row() {
      Column({ space: 4 }) {
        Text('📊 数据收集')
          .fontSize(15)
          .fontWeight(FontWeight.Medium)
        Text('收集使用数据以改进应用体验')
          .fontSize(12)
          .fontColor($r('app.color.text_secondary'))
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)

      Toggle({ type: ToggleType.Switch, isOn: $$this.dataCollection })
        .onChange(async (isOn: boolean) => {
          this.dataCollection = isOn;
          await StorageUtil.setBoolean('data_collection', isOn);
        })
    }
    .width('100%')
    .padding(12)
    .backgroundColor($r('app.color.background'))
    .borderRadius(8)

    // 崩溃报告
    Row() {
      Column({ space: 4 }) {
        Text('🐛 崩溃报告')
          .fontSize(15)
          .fontWeight(FontWeight.Medium)
        Text('自动发送崩溃报告帮助我们修复问题')
          .fontSize(12)
          .fontColor($r('app.color.text_secondary'))
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)

      Toggle({ type: ToggleType.Switch, isOn: $$this.crashReporting })
        .onChange(async (isOn: boolean) => {
          this.crashReporting = isOn;
          await StorageUtil.setBoolean('crash_reporting', isOn);
        })
    }
    .width('100%')
    .padding(12)
    .backgroundColor($r('app.color.background'))
    .borderRadius(8)

    // 隐私政策
    Row() {
      Text('📄 隐私政策')
        .fontSize(15)
        .fontWeight(FontWeight.Medium)
        .layoutWeight(1)

      Text('查看 >')
        .fontSize(14)
        .fontColor($r('app.color.text_secondary'))
    }
    .width('100%')
    .padding(16)
    .backgroundColor($r('app.color.background'))
    .borderRadius(8)
    .onClick(() => {
      router.pushUrl({ url: 'pages/Services/PrivacyPolicyPage' });
    })
  }
  .width('100%')
  .padding(16)
  .backgroundColor($r('app.color.card_background'))
  .borderRadius(12)
}

四、实现帮助中心页面

4.1 页面结构

文件位置entry/src/main/ets/pages/Services/HelpPage.ets

import { router } from '@kit.ArkUI';

interface HelpCategory {
  id: string;
  title: string;
  icon: string;
  items: HelpItem[];
}

interface HelpItem {
  id: string;
  question: string;
  answer: string;
}

@Entry
@ComponentV2
struct HelpPage {
  @Local selectedCategory: string = 'getting-started';
  @Local expandedItems: Set<string> = new Set();

  private categories: HelpCategory[] = [
    {
      id: 'getting-started',
      title: '快速入门',
      icon: '🚀',
      items: [
        {
          id: 'q1',
          question: '如何开始使用高高种地?',
          answer: '首次打开应用后,您需要选择使用模式(家庭园艺或专业农业),然后填写基本信息。完成引导后,您就可以开始添加地块、种植作物了。'
        },
        {
          id: 'q2',
          question: '如何添加地块?',
          answer: '进入"管理"页面,点击右上角的"+"按钮,填写地块信息(名称、位置、面积等),保存后即可在地图上看到您的地块标记。'
        },
        {
          id: 'q3',
          question: '如何使用AI识别功能?',
          answer: '在首页点击"AI识别"按钮,选择拍照或从相册选择图片,系统会自动识别植物种类或病虫害情况,并提供相应的建议。'
        }
      ]
    },
    {
      id: 'features',
      title: '功能介绍',
      icon: '✨',
      items: [
        {
          id: 'f1',
          question: '地图功能有什么用?',
          answer: '地图是应用的核心功能,可以查看所有地块位置、规划路线、搜索周边服务(农资店、农机租赁等),还能查看实时天气信息。'
        },
        {
          id: 'f2',
          question: '如何记录农事活动?',
          answer: '在地块详情页面,点击"添加农事记录",选择活动类型(播种、施肥、浇水等),填写详细信息和照片,系统会自动记录时间和位置。'
        },
        {
          id: 'f3',
          question: '成本核算功能如何使用?',
          answer: '在"管理"页面进入"成本核算",添加各项支出(种子、肥料、人工等),系统会自动统计总成本,并生成成本分析报告。'
        }
      ]
    },
    {
      id: 'faq',
      title: '常见问题',
      icon: '❓',
      items: [
        {
          id: 'faq1',
          question: '为什么无法获取定位?',
          answer: '请检查:1) 是否授予了定位权限;2) 是否开启了设备的位置服务;3) 是否在室内或信号较弱的地方。建议到室外空旷处重试。'
        },
        {
          id: 'faq2',
          question: '数据会丢失吗?',
          answer: '应用会自动保存所有数据到本地。建议定期使用"数据管理"功能导出备份,以防设备损坏或更换设备时数据丢失。'
        },
        {
          id: 'faq3',
          question: '如何切换使用模式?',
          answer: '进入"服务与设置"页面,点击"切换模式",选择目标模式后确认即可。注意:切换模式会影响首页显示的功能。'
        }
      ]
    }
  ];

  build() {
    Column() {
      // 头部导航
      this.buildHeader()

      Row() {
        // 左侧分类列表
        this.buildCategoryList()

        // 右侧内容区域
        this.buildContentArea()
      }
      .layoutWeight(1)
    }
    .width('100%')
    .height('100%')
    .backgroundColor($r('app.color.background'))
  }
}

4.2 帮助内容展示

实现可折叠的问答列表:

@Builder
buildContentArea() {
  Scroll() {
    Column({ space: 12 }) {
      ForEach(this.getCurrentCategory().items, (item: HelpItem) => {
        this.buildHelpItem(item);
      })
    }
    .padding(16)
  }
  .layoutWeight(1)
  .backgroundColor($r('app.color.background'))
}

@Builder
buildHelpItem(item: HelpItem) {
  Column() {
    // 问题标题
    Row() {
      Text(item.question)
        .fontSize(15)
        .fontWeight(FontWeight.Medium)
        .layoutWeight(1)

      Image(this.expandedItems.has(item.id) ?
        $r('sys.symbol.chevron_up') : $r('sys.symbol.chevron_down'))
        .width(20)
        .height(20)
        .fillColor($r('app.color.text_secondary'))
    }
    .width('100%')
    .padding(16)
    .onClick(() => {
      if (this.expandedItems.has(item.id)) {
        this.expandedItems.delete(item.id);
      } else {
        this.expandedItems.add(item.id);
      }
    })

    // 答案内容(可折叠)
    if (this.expandedItems.has(item.id)) {
      Text(item.answer)
        .fontSize(14)
        .fontColor($r('app.color.text_secondary'))
        .lineHeight(22)
        .padding({ left: 16, right: 16, bottom: 16 })
    }
  }
  .width('100%')
  .backgroundColor($r('app.color.card_background'))
  .borderRadius(12)
}

getCurrentCategory(): HelpCategory {
  return this.categories.find(c => c.id === this.selectedCategory) || this.categories[0];
}

五、实现关于页面

5.1 页面结构

文件位置entry/src/main/ets/pages/Services/AboutPage.ets

import { router } from '@kit.ArkUI';
import { bundleManager } from '@kit.AbilityKit';

@Entry
@ComponentV2
struct AboutPage {
  @Local appVersion: string = '1.0.0';
  @Local buildNumber: string = '100';

  async aboutToAppear(): Promise<void> {
    await this.loadAppInfo();
  }

  /**
   * 加载应用信息
   */
  async loadAppInfo(): Promise<void> {
    try {
      const bundleInfo = await bundleManager.getBundleInfoForSelf(
        bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT
      );
      this.appVersion = bundleInfo.versionName;
      this.buildNumber = bundleInfo.versionCode.toString();
    } catch (error) {
      console.error('Failed to load app info:', error);
    }
  }

  build() {
    Column() {
      // 头部导航
      this.buildHeader()

      Scroll() {
        Column({ space: 24 }) {
          // 应用Logo和信息
          this.buildAppInfo()

          // 版本信息
          this.buildVersionInfo()

          // 法律信息
          this.buildLegalInfo()

          // 联系方式
          this.buildContactInfo()
        }
        .padding(16)
      }
      .layoutWeight(1)
    }
    .width('100%')
    .height('100%')
    .backgroundColor($r('app.color.background'))
  }

  @Builder
  buildAppInfo() {
    Column({ space: 16 }) {
      // 应用图标
      Image($r('app.media.app_icon'))
        .width(80)
        .height(80)
        .borderRadius(16)

      // 应用名称
      Text('高高种地')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)

      // 应用简介
      Text('智慧农业管理平台')
        .fontSize(14)
        .fontColor($r('app.color.text_secondary'))

      // 版本号
      Text(`版本 ${this.appVersion}`)
        .fontSize(12)
        .fontColor($r('app.color.text_secondary'))
    }
    .width('100%')
    .padding(24)
    .backgroundColor($r('app.color.card_background'))
    .borderRadius(16)
  }

  @Builder
  buildVersionInfo() {
    Column({ space: 12 }) {
      Text('版本信息')
        .fontSize(16)
        .fontWeight(FontWeight.Bold)
        .width('100%')

      this.buildInfoRow('版本号', this.appVersion)
      this.buildInfoRow('构建号', this.buildNumber)
      this.buildInfoRow('更新时间', '2024-01-22')

      Button('检查更新')
        .width('100%')
        .height(44)
        .fontSize(15)
        .margin({ top: 8 })
        .onClick(() => {
          this.checkUpdate();
        })
    }
    .width('100%')
    .padding(16)
    .backgroundColor($r('app.color.card_background'))
    .borderRadius(16)
  }

  @Builder
  buildLegalInfo() {
    Column({ space: 12 }) {
      Text('法律信息')
        .fontSize(16)
        .fontWeight(FontWeight.Bold)
        .width('100%')

      this.buildLinkItem('用户协议', () => {
        router.pushUrl({ url: 'pages/Services/UserAgreementPage' });
      })

      this.buildLinkItem('隐私政策', () => {
        router.pushUrl({ url: 'pages/Services/PrivacyPolicyPage' });
      })

      this.buildLinkItem('开源许可', () => {
        router.pushUrl({ url: 'pages/Services/OpenSourceLicensePage' });
      })
    }
    .width('100%')
    .padding(16)
    .backgroundColor($r('app.color.card_background'))
    .borderRadius(16)
  }

  @Builder
  buildContactInfo() {
    Column({ space: 12 }) {
      Text('联系我们')
        .fontSize(16)
        .fontWeight(FontWeight.Bold)
        .width('100%')

      this.buildInfoRow('官方网站', 'www.gaogaozhongdi.com')
      this.buildInfoRow('客服邮箱', 'support@gaogaozhongdi.com')
      this.buildInfoRow('客服电话', '400-123-4567')
    }
    .width('100%')
    .padding(16)
    .backgroundColor($r('app.color.card_background'))
    .borderRadius(16)
  }

  @Builder
  buildInfoRow(label: string, value: string) {
    Row() {
      Text(label)
        .fontSize(14)
        .fontColor($r('app.color.text_secondary'))
        .layoutWeight(1)

      Text(value)
        .fontSize(14)
        .fontColor($r('app.color.text_primary'))
    }
    .width('100%')
    .padding({ top: 8, bottom: 8 })
  }

  @Builder
  buildLinkItem(title: string, onClick: () => void) {
    Row() {
      Text(title)
        .fontSize(15)
        .layoutWeight(1)

      Text('>')
        .fontSize(14)
        .fontColor($r('app.color.text_secondary'))
    }
    .width('100%')
    .padding(16)
    .backgroundColor($r('app.color.background'))
    .borderRadius(8)
    .onClick(onClick)
  }

  checkUpdate(): void {
    promptAction.showToast({
      message: '已是最新版本',
      duration: 2000
    });
  }
}

六、实操练习

6.1 测试通知设置

  1. 进入通知设置页面,测试各项开关
  2. 修改提醒时间,验证时间选择器
  3. 检查权限状态,测试权限引导

6.2 测试隐私设置

  1. 查看权限状态,了解已授予的权限
  2. 切换数据收集开关,验证设置保存
  3. 查看隐私政策,测试页面跳转

6.3 测试帮助中心

  1. 浏览不同分类,查看帮助内容
  2. 展开/折叠问答,测试交互效果
  3. 搜索问题(如果实现了搜索功能)

七、常见问题

7.1 通知不生效

问题:设置了提醒但没有收到通知

解决方案

  1. 检查系统通知权限是否开启
  2. 确认提醒开关是否打开
  3. 检查系统勿扰模式设置
  4. 验证通知发送逻辑

7.2 权限检查失败

问题:无法正确显示权限状态

解决方案

  1. 确认权限声明正确
  2. 检查权限检查代码
  3. 验证应用签名配置
  4. 查看错误日志

7.3 帮助内容加载慢

问题:帮助页面打开缓慢

解决方案

  1. 优化数据结构
  2. 使用懒加载
  3. 缓存常用内容
  4. 减少初始加载数据量

八、本篇小结

本篇教程实现了完整的设置与帮助系统,包括:

通知设置:提醒开关、时间设置、权限管理
隐私设置:权限查看、数据隐私、安全设置
帮助中心:分类帮助、常见问题、使用指南
关于页面:版本信息、法律文档、联系方式
用户反馈:问题反馈、功能建议

核心技术点

  • HarmonyOS 通知管理(NotificationManager)
  • 权限检查和管理(AbilityAccessCtrl)
  • 应用信息获取(BundleManager)
  • 时间选择器(TimePickerDialog)
  • 可折叠列表实现

最佳实践

  • 清晰的设置分类和层级
  • 友好的权限引导提示
  • 详细的帮助文档
  • 及时的用户反馈渠道
  • 完善的法律信息展示

下一篇预告
第31篇将实现桌面小组件开发,包括天气卡片、任务提醒卡片等功能。


📖 参考资料

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐