使用AppGallery Connect构建在线学习平台

基于HarmonyOS Next的教育类应用开发实战:使用AppGallery Connect构建在线学习平台

一、项目概述与准备工作

在当今数字化教育时代,移动学习应用已成为教育领域的重要组成部分。本次我们将基于HarmonyOS Next系统,使用AppGallery Connect服务开发一个功能完善的在线教育应用。该应用将包含课程展示、用户认证、学习进度跟踪等核心功能,适合各类教育机构和个人开发者参考学习。

在开始开发前,我们需要做好以下准备工作:

  1. 安装最新版本的DevEco Studio开发工具
  2. 注册华为开发者账号并开通AppGallery Connect服务
  3. 创建HarmonyOS应用项目并配置基本参数
  4. 在AppGallery Connect控制台初始化项目并启用所需服务

二、项目架构设计

我们的教育应用将采用模块化设计,主要包含以下几个核心模块:

  • 用户认证模块:处理用户注册、登录和权限管理
  • 课程管理模块:展示课程列表、详情和学习资源
  • 学习记录模块:跟踪用户学习进度和成绩
  • 互动交流模块:实现师生问答和讨论功能

下面我们将重点实现前三个核心模块,展示如何利用AppGallery Connect服务简化开发流程。

三、用户认证模块实现

用户认证是教育应用的基础功能,我们将使用AppGallery Connect提供的Auth Service来实现安全的用户认证系统。

1. 配置Auth Service

首先在项目的entry/build.gradle文件中添加依赖:

dependencies {
    implementation 'com.huawei.agconnect:agconnect-auth-harmony:1.6.5.300'
}

然后在resources/config.json中配置Auth Service:

{
  "app": {
    "bundleName": "com.example.educationapp",
    "vendor": "example",
    "version": {
      "code": 1000000,
      "name": "1.0.0"
    },
    "apiVersion": {
      "compatible": 8,
      "target": 9,
      "releaseType": "Release"
    }
  },
  "deviceConfig": {},
  "module": {
    "name": "entry",
    "type": "entry",
    "abilities": [
      {
        "name": "MainAbility",
        "type": "page",
        "label": "$string:MainAbility_label",
        "icon": "$media:icon",
        "launchType": "standard",
        "metaData": {
          "customizeData": [
            {
              "name": "hwc-theme",
              "value": "androidhwext:style/Theme.Emui.Light.NoTitleBar",
              "extra": ""
            }
          ]
        }
      }
    ],
    "distro": {
      "deliveryWithInstall": true,
      "moduleName": "entry",
      "moduleType": "entry",
      "installationFree": false
    },
    "reqPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]
  }
}

2. 实现用户注册功能

创建UserAuth.ts文件,实现用户注册逻辑:

import agconnect from '@hw-agconnect/api-harmony';
import '@hw-agconnect/auth-harmony';

// 初始化AGConnectAuth
let agcAuth = agconnect.auth();

// 用户注册函数
async function registerUser(email: string, password: string, username: string): Promise<boolean> {
  try {
    // 创建用户请求对象
    let userRequest = {
      email: email,
      password: password,
      verifyCode: '', // 实际项目中需要通过邮件或短信获取验证码
      displayName: username
    };
    
    // 调用注册接口
    let user = await agcAuth.createUser(userRequest);
    console.log('注册成功,用户ID:', user.getUid());
    return true;
  } catch (error) {
    console.error('注册失败:', error);
    return false;
  }
}

// 用户登录函数
async function loginUser(email: string, password: string): Promise<boolean> {
  try {
    // 创建登录请求对象
    let loginRequest = {
      email: email,
      password: password,
      verifyCode: '' // 如果需要验证码验证
    };
    
    // 调用登录接口
    let user = await agcAuth.signIn(loginRequest);
    console.log('登录成功,用户:', user);
    return true;
  } catch (error) {
    console.error('登录失败:', error);
    return false;
  }
}

// 获取当前用户信息
function getCurrentUser(): any {
  return agcAuth.getCurrentUser();
}

// 用户登出
async function logoutUser(): Promise<void> {
  try {
    await agcAuth.signOut();
    console.log('登出成功');
  } catch (error) {
    console.error('登出失败:', error);
  }
}

export { registerUser, loginUser, getCurrentUser, logoutUser };

3. 创建注册登录界面

pages目录下创建LoginPage.etsRegisterPage.ets文件:

// LoginPage.ets
@Entry
@Component
struct LoginPage {
  @State email: string = ''
  @State password: string = ''
  @State isLoading: boolean = false

  build() {
    Column() {
      Text('教育学习平台登录')
        .fontSize(24)
        .margin({ bottom: 30 })
      
      TextInput({ placeholder: '请输入邮箱' })
        .width('90%')
        .height(50)
        .margin({ bottom: 20 })
        .onChange((value: string) => {
          this.email = value
        })
      
      TextInput({ placeholder: '请输入密码' })
        .width('90%')
        .height(50)
        .type(InputType.Password)
        .margin({ bottom: 30 })
        .onChange((value: string) => {
          this.password = value
        })
      
      Button('登录', { type: ButtonType.Capsule })
        .width('80%')
        .height(50)
        .backgroundColor('#007DFF')
        .fontColor(Color.White)
        .onClick(async () => {
          this.isLoading = true
          let success = await loginUser(this.email, this.password)
          this.isLoading = false
          if (success) {
            // 跳转到主页
            router.replaceUrl({ url: 'pages/MainPage' })
          } else {
            prompt.showToast({ message: '登录失败,请检查邮箱和密码' })
          }
        })
        .loading(this.isLoading)
      
      Row() {
        Text('还没有账号?')
        Text('立即注册')
          .fontColor('#007DFF')
          .onClick(() => {
            router.pushUrl({ url: 'pages/RegisterPage' })
          })
      }.margin({ top: 20 })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }
}

四、课程管理模块实现

课程管理是教育应用的核心功能,我们将使用AppGallery Connect的Cloud DB服务来存储和管理课程数据。

1. 配置Cloud DB

首先在AppGallery Connect控制台创建课程数据模型:

  1. 对象类型名称:Course
  2. 字段设计: courseId: 字符串,主键title: 字符串,课程标题description: 字符串,课程描述coverUrl: 字符串,封面图URLteacher: 字符串,授课教师duration: 整型,课程时长(分钟)price: 浮点型,课程价格category: 字符串,课程分类

然后在项目中添加Cloud DB依赖:

dependencies {
    implementation 'com.huawei.agconnect:agconnect-clouddb-harmony:1.5.8.300'
}

2. 实现课程数据操作

创建CourseService.ts文件:

import agconnect from '@hw-agconnect/api-harmony';
import '@hw-agconnect/clouddb-harmony';

// 定义课程对象类型
interface Course {
  courseId: string;
  title: string;
  description: string;
  coverUrl: string;
  teacher: string;
  duration: number;
  price: number;
  category: string;
}

class CourseService {
  private cloudDB: any;
  private zoneName: string = 'CourseZone';
  
  // 初始化Cloud DB
  async initCloudDB() {
    try {
      const agcCloudDB = agconnect.cloudDB();
      this.cloudDB = await agcCloudDB.createInstance({
        zoneName: this.zoneName,
        objectTypeName: 'Course'
      });
      console.log('Cloud DB初始化成功');
    } catch (error) {
      console.error('Cloud DB初始化失败:', error);
    }
  }
  
  // 添加课程
  async addCourse(course: Course): Promise<boolean> {
    try {
      await this.cloudDB.upsert(course);
      return true;
    } catch (error) {
      console.error('添加课程失败:', error);
      return false;
    }
  }
  
  // 获取所有课程
  async getAllCourses(): Promise<Course[]> {
    try {
      const query = this.cloudDB.createQuery();
      const result = await this.cloudDB.executeQuery(query);
      return result.getSnapshotObjects();
    } catch (error) {
      console.error('获取课程列表失败:', error);
      return [];
    }
  }
  
  // 根据ID获取课程详情
  async getCourseById(courseId: string): Promise<Course | null> {
    try {
      const query = this.cloudDB.createQuery();
      query.equalTo('courseId', courseId);
      const result = await this.cloudDB.executeQuery(query);
      const courses = result.getSnapshotObjects();
      return courses.length > 0 ? courses[0] : null;
    } catch (error) {
      console.error('获取课程详情失败:', error);
      return null;
    }
  }
  
  // 根据分类获取课程
  async getCoursesByCategory(category: string): Promise<Course[]> {
    try {
      const query = this.cloudDB.createQuery();
      query.equalTo('category', category);
      const result = await this.cloudDB.executeQuery(query);
      return result.getSnapshotObjects();
    } catch (error) {
      console.error('按分类获取课程失败:', error);
      return [];
    }
  }
}

export default new CourseService();

3. 创建课程列表和详情页面

pages目录下创建CourseListPage.etsCourseDetailPage.ets

// CourseListPage.ets
@Entry
@Component
struct CourseListPage {
  @State courses: Course[] = []
  @State isLoading: boolean = true
  @State selectedCategory: string = 'all'

  private categories: string[] = ['all', 'programming', 'language', 'business', 'design']

  async aboutToAppear() {
    await CourseService.initCloudDB()
    this.loadCourses()
  }

  loadCourses() {
    this.isLoading = true
    if (this.selectedCategory === 'all') {
      CourseService.getAllCourses().then(courses => {
        this.courses = courses
        this.isLoading = false
      })
    } else {
      CourseService.getCoursesByCategory(this.selectedCategory).then(courses => {
        this.courses = courses
        this.isLoading = false
      })
    }
  }

  build() {
    Column() {
      // 分类筛选
      Scroll() {
        Row() {
          ForEach(this.categories, (category: string) => {
            Button(category === 'all' ? '全部' : this.getCategoryName(category))
              .type(ButtonType.Normal)
              .stateEffect(true)
              .backgroundColor(this.selectedCategory === category ? '#007DFF' : '#F5F5F5')
              .fontColor(this.selectedCategory === category ? Color.White : Color.Black)
              .onClick(() => {
                this.selectedCategory = category
                this.loadCourses()
              })
              .margin(5)
          })
        }
        .padding(10)
      }
      .scrollable(ScrollDirection.Horizontal)

      // 课程列表
      List({ space: 10 }) {
        ForEach(this.courses, (course: Course) => {
          ListItem() {
            CourseItem({ course: course })
          }
          .onClick(() => {
            router.pushUrl({ url: `pages/CourseDetailPage?courseId=${course.courseId}` })
          })
        })
      }
      .layoutWeight(1)
      .visibility(this.isLoading ? Visibility.None : Visibility.Visible)

      // 加载指示器
      if (this.isLoading) {
        LoadingProgress()
          .width(50)
          .height(50)
      }
    }
    .width('100%')
    .height('100%')
  }

  private getCategoryName(category: string): string {
    const map: Record<string, string> = {
      programming: '编程',
      language: '语言',
      business: '商业',
      design: '设计'
    }
    return map[category] || category
  }
}

@Component
struct CourseItem {
  private course: Course

  build() {
    Row() {
      Image(this.course.coverUrl)
        .width(120)
        .height(80)
        .objectFit(ImageFit.Cover)
        .borderRadius(5)
      
      Column() {
        Text(this.course.title)
          .fontSize(18)
          .fontWeight(FontWeight.Bold)
          .margin({ bottom: 5 })
        
        Text(this.course.teacher)
          .fontSize(14)
          .fontColor('#666666')
          .margin({ bottom: 5 })
        
        Row() {
          Text(`${this.course.duration}分钟`)
            .fontSize(12)
            .fontColor('#999999')
          
          Text(`¥${this.course.price.toFixed(2)}`)
            .fontSize(16)
            .fontColor('#FF6600')
            .margin({ left: 20 })
        }
      }
      .margin({ left: 15 })
      .layoutWeight(1)
    }
    .width('100%')
    .padding(10)
    .backgroundColor(Color.White)
    .borderRadius(10)
    .shadow({ radius: 5, color: '#F1F1F1', offsetX: 2, offsetY: 2 })
  }
}

五、学习记录模块实现

学习记录功能可以帮助用户跟踪学习进度,我们将使用AppGallery Connect的Cloud Storage和Cloud Functions来实现这一功能。

1. 设计学习记录数据结构

在AppGallery Connect控制台创建学习记录对象类型:

  1. 对象类型名称:LearningRecord
  2. 字段设计: recordId: 字符串,主键userId: 字符串,用户IDcourseId: 字符串,课程IDprogress: 整型,学习进度(0-100)lastStudyTime: 日期,最后学习时间completed: 布尔型,是否已完成

2. 实现学习记录服务

创建LearningRecordService.ts文件:

import agconnect from '@hw-agconnect/api-harmony';
import '@hw-agconnect/clouddb-harmony';

interface LearningRecord {
  recordId: string;
  userId: string;
  courseId: string;
  progress: number;
  lastStudyTime: Date;
  completed: boolean;
}

class LearningRecordService {
  private cloudDB: any;
  private zoneName: string = 'LearningRecordZone';
  
  async initCloudDB() {
    try {
      const agcCloudDB = agconnect.cloudDB();
      this.cloudDB = await agcCloudDB.createInstance({
        zoneName: this.zoneName,
        objectTypeName: 'LearningRecord'
      });
      console.log('学习记录Cloud DB初始化成功');
    } catch (error) {
      console.error('学习记录Cloud DB初始化失败:', error);
    }
  }
  
  // 更新学习进度
  async updateLearningProgress(userId: string, courseId: string, progress: number): Promise<boolean> {
    try {
      // 先查询是否已有记录
      const query = this.cloudDB.createQuery();
      query.equalTo('userId', userId);
      query.equalTo('courseId', courseId);
      const result = await this.cloudDB.executeQuery(query);
      const records = result.getSnapshotObjects();
      
      let record: LearningRecord;
      if (records.length > 0) {
        // 更新现有记录
        record = records[0];
        record.progress = Math.min(progress, 100);
        record.lastStudyTime = new Date();
        record.completed = record.progress >= 100;
      } else {
        // 创建新记录
        record = {
          recordId: this.generateId(),
          userId: userId,
          courseId: courseId,
          progress: Math.min(progress, 100),
          lastStudyTime: new Date(),
          completed: progress >= 100
        };
      }
      
      await this.cloudDB.upsert(record);
      return true;
    } catch (error) {
      console.error('更新学习进度失败:', error);
      return false;
    }
  }
  
  // 获取用户的学习记录
  async getUserLearningRecords(userId: string): Promise<LearningRecord[]> {
    try {
      const query = this.cloudDB.createQuery();
      query.equalTo('userId', userId);
      const result = await this.cloudDB.executeQuery(query);
      return result.getSnapshotObjects();
    } catch (error) {
      console.error('获取学习记录失败:', error);
      return [];
    }
  }
  
  // 获取特定课程的学习进度
  async getCourseProgress(userId: string, courseId: string): Promise<number> {
    try {
      const query = this.cloudDB.createQuery();
      query.equalTo('userId', userId);
      query.equalTo('courseId', courseId);
      const result = await this.cloudDB.executeQuery(query);
      const records = result.getSnapshotObjects();
      return records.length > 0 ? records[0].progress : 0;
    } catch (error) {
      console.error('获取课程进度失败:', error);
      return 0;
    }
  }
  
  private generateId(): string {
    return Math.random().toString(36).substring(2) + Date.now().toString(36);
  }
}

export default new LearningRecordService();

3. 在课程详情页集成学习记录功能

更新CourseDetailPage.ets

@Entry
@Component
struct CourseDetailPage {
  @State course: Course | null = null
  @State isLoading: boolean = true
  @State progress: number = 0
  private courseId: string = ''

  async aboutToAppear() {
    // 从路由参数获取课程ID
    const params = router.getParams() as Record<string, string>;
    this.courseId = params['courseId'] || '';
    
    await Promise.all([
      CourseService.initCloudDB(),
      LearningRecordService.initCloudDB()
    ]);
    
    this.loadCourseDetail();
    this.loadLearningProgress();
  }

  async loadCourseDetail() {
    this.course = await CourseService.getCourseById(this.courseId);
    this.isLoading = false;
  }

  async loadLearningProgress() {
    const user = getCurrentUser();
    if (user) {
      this.progress = await LearningRecordService.getCourseProgress(user.uid, this.courseId);
    }
  }

  async updateProgress(newProgress: number) {
    const user = getCurrentUser();
    if (user) {
      const success = await LearningRecordService.updateLearningProgress(
        user.uid,
        this.courseId,
        newProgress
      );
      if (success) {
        this.progress = newProgress;
        prompt.showToast({ message: '学习进度已保存' });
      }
    } else {
      prompt.showToast({ message: '请先登录' });
    }
  }

  build() {
    Column() {
      if (this.isLoading) {
        LoadingProgress()
          .width(50)
          .height(50)
      } else if (this.course) {
        Scroll() {
          Column() {
            // 课程封面
            Image(this.course.coverUrl)
              .width('100%')
              .height(200)
              .objectFit(ImageFit.Cover)
            
            // 课程基本信息
            Column() {
              Text(this.course.title)
                .fontSize(22)
                .fontWeight(FontWeight.Bold)
                .margin({ bottom: 10 })
              
              Row() {
                Text(this.course.teacher)
                  .fontSize(16)
                  .fontColor('#666666')
                
                Text(`${this.course.duration}分钟`)
                  .fontSize(16)
                  .fontColor('#666666')
                  .margin({ left: 20 })
              }
              .margin({ bottom: 15 })
              
              Text(this.course.description)
                .fontSize(14)
                .fontColor('#333333')
                .margin({ bottom: 20 })
            }
            .padding(15)
            
            // 学习进度
            Column() {
              Text('学习进度')
                .fontSize(18)
                .fontWeight(FontWeight.Bold)
                .margin({ bottom: 10 })
              
              Progress({
                value: this.progress,
                total: 100,
                type: ProgressType.Linear
              })
                .width('100%')
                .height(10)
                .margin({ bottom: 10 })
              
              Text(`${this.progress}%`)
                .fontSize(16)
                .fontColor('#007DFF')
                .alignSelf(ItemAlign.End)
              
              Row() {
                Button('标记为25%')
                  .type(ButtonType.Normal)
                  .onClick(() => this.updateProgress(25))
                  .margin(5)
                
                Button('标记为50%')
                  .type(ButtonType.Normal)
                  .onClick(() => this.updateProgress(50))
                  .margin(5)
                
                Button('标记为75%')
                  .type(ButtonType.Normal)
                  .onClick(() => this.updateProgress(75))
                  .margin(5)
                
                Button('标记为完成')
                  .type(ButtonType.Normal)
                  .onClick(() => this.updateProgress(100))
                  .margin(5)
              }
              .margin({ top: 15 })
              .justifyContent(FlexAlign.SpaceBetween)
            }
            .padding(15)
            .backgroundColor('#F9F9F9')
            .borderRadius(10)
            .margin({ top: 10, bottom: 20 })
          }
        }
      } else {
        Text('课程加载失败')
          .fontSize(18)
          .fontColor(Color.Red)
      }
    }
    .width('100%')
    .height('100%')
    .padding(10)
  }
}

六、项目总结与扩展建议

通过本教程,我们完成了一个基于HarmonyOS Next的教育类应用基础开发,实现了以下核心功能:

  1. 用户认证系统:使用AppGallery Connect Auth Service实现安全的用户注册和登录
  2. 课程管理系统:利用Cloud DB存储和管理课程数据
  3. 学习进度跟踪:通过自定义对象类型记录用户学习进度

扩展功能建议

  1. 课程内容管理:可以集成视频播放SDK,实现课程视频的在线播放和离线下载功能
  2. 测试与评估:添加课后测试功能,使用Cloud Functions自动评分
  3. 消息推送:集成Push Kit,向用户发送课程更新和学习提醒
  4. 数据分析:使用AppGallery Connect的分析服务,了解用户学习行为
  5. 支付功能:对于付费课程,可以集成华为支付服务

性能优化建议

  1. 对于课程列表,实现分页加载,避免一次性加载过多数据
  2. 使用本地缓存机制,减少网络请求次数
  3. 对图片资源进行压缩和懒加载
  4. 在用户网络不佳时,提供适当的降级方案

通过本项目的学习,开发者可以掌握HarmonyOS Next应用开发的核心技术,以及如何利用AppGallery Connect的各种服务快速构建功能完善的应用程序。希望本教程能为您的HarmonyOS开发之旅提供有价值的参考。

全部评论

相关推荐

点赞 评论 收藏
分享
07-11 13:16
湖南工学院 Java
点赞 评论 收藏
分享
陈逸轩1205:才105 哥们在养生呢
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
07-07 13:15
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务