DEV Community

linzhongxue
linzhongxue

Posted on

Developing an Educational Application Based on HarmonyOS Next

Developing an Educational Application Based on HarmonyOS Next: Building a Smart Learning Assistant from Scratch

1. Project Overview and Development Environment Setup

In the rapidly evolving landscape of digital education, developing educational applications on HarmonyOS Next holds immense potential. This tutorial will guide you through using AppGallery Connect services to build a "Smart Learning Assistant" application featuring course management, learning progress tracking, and knowledge assessment.

First, ensure your development environment is ready:

  1. Install the latest version of DevEco Studio (recommended 4.0 or above).
  2. Register a Huawei Developer account and complete identity verification.
  3. Create a new project in AppGallery Connect and enable the required services.
// Example of project initialization configuration  
import { Ability, AbilityConstant, UIAbility, Want } from '@ohos.app.ability.UIAbility';  
import { window } from '@ohos.window';  

export default class EntryAbility extends UIAbility {  
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {  
    console.info('EducationApp onCreate');  
    // Initialize the application's global state  
    globalThis.educationContext = this.context;  
  }  

  onWindowStageCreate(windowStage: window.WindowStage) {  
    console.info('EducationApp onWindowStageCreate');  
    // Load the home page  
    windowStage.loadContent('pages/Index', (err) => {  
      if (err.code) {  
        console.error('Failed to load the content. Cause:' + JSON.stringify(err));  
        return;  
      }  
      console.info('Succeeded in loading the content');  
    });  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

2. Application Architecture Design and Core Feature Planning

2.1 Overall Architecture Design

Our Smart Learning Assistant adopts a layered architecture:

  • Presentation Layer: ArkUI-based page components
  • Business Logic Layer: Handles education-related business logic
  • Data Access Layer: Uses AppGallery Connect's Cloud DB and authentication services
  • Service Layer: Integrates Huawei's analytics and push services

2.2 Core Feature Modules

  1. User Authentication Module: Supports login for teachers and students
  2. Course Management Module: Create, edit, and browse course content
  3. Learning Progress Module: Tracks and visualizes learning progress
  4. Assessment Module: Provides knowledge tests and a wrong-answer notebook

3. Implementing the User Authentication Module

Educational apps often require distinguishing between teacher and student roles, which can be achieved using AppGallery Connect's authentication service.

// Import authentication modules  
import { agconnect } from '@hw-agconnect/api-ohos';  
import '@hw-agconnect/auth-ohos';  

// User authentication service class  
export class AuthService {  
  // User login method  
  async login(email: string, password: string): Promise<boolean> {  
    try {  
      const user = await agconnect.auth().signInWithEmailAndPassword(email, password);  
      console.info('Login success:', user);  
      return true;  
    } catch (error) {  
      console.error('Login failed:', error);  
      return false;  
    }  
  }  

  // User registration method  
  async register(email: string, password: string, role: string): Promise<boolean> {  
    try {  
      const user = await agconnect.auth().createUserWithEmailAndPassword(email, password);  
      // Save user role to Cloud DB  
      await this.saveUserRole(user.uid, role);  
      return true;  
    } catch (error) {  
      console.error('Registration failed:', error);  
      return false;  
    }  
  }  

  // Save user role to Cloud DB  
  private async saveUserRole(uid: string, role: string): Promise<void> {  
    const db = agconnect.cloudDB();  
    const userRole = {  
      userId: uid,  
      role: role,  
      createdAt: new Date().toISOString()  
    };  
    await db.insert('UserRoles', userRole);  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

4. Developing the Course Management Module

Courses are the core content of educational apps, requiring well-designed database structures and related functionalities.

4.1 Data Model Design

Create a Course object type in AppGallery Connect with the following fields:

  • courseId: String (primary key)
  • title: String (course title)
  • description: String (course description)
  • teacherId: String (teacher ID)
  • chapters: Array (list of chapters)
  • createTime: Timestamp
// Course service class  
export class CourseService {  
  private db: any;  

  constructor() {  
    this.db = agconnect.cloudDB();  
  }  

  // Create a new course  
  async createCourse(courseData: any): Promise<string> {  
    try {  
      const result = await this.db.insert('Courses', courseData);  
      console.info('Course created:', result);  
      return result.id;  
    } catch (error) {  
      console.error('Failed to create course:', error);  
      throw error;  
    }  
  }  

  // Get all courses by a teacher  
  async getCoursesByTeacher(teacherId: string): Promise<Array<any>> {  
    try {  
      const query = this.db.createQuery();  
      query.equalTo('teacherId', teacherId);  
      query.orderByDesc('createTime');  
      const result = await this.db.executeQuery('Courses', query);  
      return result.getSnapshotObjects();  
    } catch (error) {  
      console.error('Failed to get courses:', error);  
      return [];  
    }  
  }  

  // Get course details  
  async getCourseDetail(courseId: string): Promise<any> {  
    try {  
      const query = this.db.createQuery();  
      query.equalTo('courseId', courseId);  
      const result = await this.db.executeQuery('Courses', query);  
      const courses = result.getSnapshotObjects();  
      return courses.length > 0 ? courses[0] : null;  
    } catch (error) {  
      console.error('Failed to get course detail:', error);  
      return null;  
    }  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

5. Implementing Learning Progress Tracking

Learning progress is a crucial feature in educational apps, helping students track their learning journey.

// Learning progress service class  
export class ProgressService {  
  private db: any;  

  constructor() {  
    this.db = agconnect.cloudDB();  
  }  

  // Update learning progress  
  async updateProgress(userId: string, courseId: string, chapterId: string, progress: number): Promise<void> {  
    try {  
      const record = {  
        userId,  
        courseId,  
        chapterId,  
        progress,  
        lastUpdate: new Date().toISOString()  
      };  

      // Check if a record already exists  
      const query = this.db.createQuery();  
      query.equalTo('userId', userId);  
      query.equalTo('courseId', courseId);  
      query.equalTo('chapterId', chapterId);  
      const result = await this.db.executeQuery('LearningProgress', query);  
      const existingRecords = result.getSnapshotObjects();  

      if (existingRecords.length > 0) {  
        // Update existing record  
        record.id = existingRecords[0].id;  
        await this.db.update('LearningProgress', record);  
      } else {  
        // Insert new record  
        await this.db.insert('LearningProgress', record);  
      }  
    } catch (error) {  
      console.error('Failed to update progress:', error);  
      throw error;  
    }  
  }  

  // Get a user's progress in a course  
  async getCourseProgress(userId: string, courseId: string): Promise<Array<any>> {  
    try {  
      const query = this.db.createQuery();  
      query.equalTo('userId', userId);  
      query.equalTo('courseId', courseId);  
      const result = await this.db.executeQuery('LearningProgress', query);  
      return result.getSnapshotObjects();  
    } catch (error) {  
      console.error('Failed to get progress:', error);  
      return [];  
    }  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

6. Developing the Assessment Module

Tests help students reinforce knowledge, while teachers can evaluate teaching effectiveness through results.

// Quiz service class  
export class QuizService {  
  private db: any;  

  constructor() {  
    this.db = agconnect.cloudDB();  
  }  

  // Get quiz questions for a course  
  async getQuizQuestions(courseId: string, chapterId: string): Promise<Array<any>> {  
    try {  
      const query = this.db.createQuery();  
      query.equalTo('courseId', courseId);  
      query.equalTo('chapterId', chapterId);  
      query.orderByAsc('questionNumber');  
      const result = await this.db.executeQuery('QuizQuestions', query);  
      return result.getSnapshotObjects();  
    } catch (error) {  
      console.error('Failed to get quiz questions:', error);  
      return [];  
    }  
  }  

  // Submit quiz answers  
  async submitQuizAnswers(userId: string, quizId: string, answers: Array<any>): Promise<any> {  
    try {  
      const resultRecord = {  
        userId,  
        quizId,  
        answers,  
        submitTime: new Date().toISOString(),  
        score: this.calculateScore(answers)  
      };  

      await this.db.insert('QuizResults', resultRecord);  
      return resultRecord;  
    } catch (error) {  
      console.error('Failed to submit quiz:', error);  
      throw error;  
    }  
  }  

  // Calculate quiz score  
  private calculateScore(answers: Array<any>): number {  
    let correctCount = 0;  
    answers.forEach(answer => {  
      if (answer.isCorrect) {  
        correctCount++;  
      }  
    });  
    return Math.round((correctCount / answers.length) * 100);  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

7. UI Implementation Example

Below is an example implementation of a course list page:

// Course list page  
@Entry  
@Component  
struct CourseListPage {  
  @State courses: Array<any> = [];  
  @State isLoading: boolean = true;  

  private courseService: CourseService = new CourseService();  

  aboutToAppear() {  
    this.loadCourses();  
  }  

  async loadCourses() {  
    try {  
      // Get current user ID  
      const currentUser = agconnect.auth().getCurrentUser();  
      if (!currentUser) return;  

      this.isLoading = true;  
      this.courses = await this.courseService.getCoursesByTeacher(currentUser.uid);  
    } catch (error) {  
      console.error('Failed to load courses:', error);  
    } finally {  
      this.isLoading = false;  
    }  
  }  

  build() {  
    Column() {  
      // Title bar  
      Row() {  
        Text('My Courses')  
          .fontSize(24)  
          .fontWeight(FontWeight.Bold)  
        Blank()  
        Button('+ New Course')  
          .onClick(() => {  
            // Navigate to create course page  
            router.pushUrl({ url: 'pages/CreateCoursePage' });  
          })  
      }  
      .width('100%')  
      .padding(20)  
      .justifyContent(FlexAlign.SpaceBetween)  

      // Loading indicator  
      if (this.isLoading) {  
        LoadingProgress()  
          .height(100)  
          .width(100)  
      } else {  
        // Course list  
        List({ space: 20 }) {  
          ForEach(this.courses, (course: any) => {  
            ListItem() {  
              CourseCard({ course: course })  
                .onClick(() => {  
                  // Navigate to course details page  
                  router.pushUrl({  
                    url: 'pages/CourseDetailPage',  
                    params: { courseId: course.courseId }  
                  });  
                })  
            }  
          })  
        }  
        .width('100%')  
        .layoutWeight(1)  
        .divider({ strokeWidth: 1, color: '#F1F1F1' })  
      }  
    }  
    .height('100%')  
    .width('100%')  
    .backgroundColor('#F5F5F5')  
  }  
}  

// Course card component  
@Component  
struct CourseCard {  
  @Prop course: any;  

  build() {  
    Column() {  
      // Course cover image  
      Image(this.course.coverUrl || '/common/default_course.png')  
        .width('100%')  
        .height(120)  
        .objectFit(ImageFit.Cover)  
        .borderRadius(8)  

      // Course information  
      Column() {  
        Text(this.course.title)  
          .fontSize(18)  
          .fontWeight(FontWeight.Medium)  
          .margin({ bottom: 4 })  
        Text(this.course.description)  
          .fontSize(14)  
          .fontColor('#666')  
          .maxLines(2)  
          .textOverflow({ overflow: TextOverflow.Ellipsis })  
      }  
      .padding(10)  
      .width('100%')  
    }  
    .width('100%')  
    .backgroundColor(Color.White)  
    .borderRadius(8)  
    .shadow({ radius: 8, color: '#1A000000', offsetX: 2, offsetY: 2 })  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

8. Application Optimization and Expansion Suggestions

8.1 Performance Optimization

  1. Data Caching: Use local databases to cache frequently accessed data and reduce network requests.
  2. Image Optimization: Implement thumbnail techniques to reduce image loading times.
  3. Lazy Loading: Apply lazy loading for long lists to improve scrolling performance.

8.2 Feature Expansion

  1. Real-Time Interaction: Integrate Huawei's Real-Time Communication service for teacher-student interaction.
  2. Data Analytics: Use AppGallery Connect's analytics service to study learning behavior.
  3. Offline Learning: Enable offline support for core features to enhance user experience.
// Example of offline data synchronization  
async syncOfflineData() {  
  try {  
    const db = agconnect.cloudDB();  
    // Sync course data  
    await db.sync('Courses', { policy: 'LOCAL_FIRST' });  
    // Sync learning progress  
    await db.sync('LearningProgress', { policy: 'LOCAL_FIRST' });  
    console.info('Data sync completed');  
  } catch (error) {  
    console.error('Data sync failed:', error);  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

9. Conclusion and Release Preparation

Through this tutorial, we've developed the core features of a Smart Learning Assistant application based on HarmonyOS Next. Before release, ensure:

  1. Complete testing of all features.
  2. Configure app information in AppGallery Connect.
  3. Prepare app screenshots and descriptions.
  4. Follow Huawei AppGallery's publishing guidelines.

Educational app development requires special attention to data security and user experience. HarmonyOS Next provides robust security mechanisms and smooth animations, making it ideal for educational scenarios. This tutorial aims to help you quickly get started with HarmonyOS development and create more outstanding educational applications.

Top comments (0)