DEV Community

linzhongxue
linzhongxue

Posted on

Building an Intelligent Learning Platform Using AppGallery Connect

Practical Development of Educational Applications Based on HarmonyOS Next: Building an Intelligent Learning Platform Using AppGallery Connect

1. Project Overview and Development Environment Setup

With the rapid development of educational informatization, educational applications based on HarmonyOS Next have become a hot topic for developers. This chapter will introduce how to use AppGallery Connect services to develop a fully functional intelligent learning platform, including core features such as course management, learning progress tracking, and online testing.

First, configure the development environment:

  1. Install the latest version of DevEco Studio.
  2. Create a new project in AppGallery Connect and enable the required services.
  3. Configure project signing and certificates.
// Example project configuration file: entry/build-profile.json5  
{  
  "app": {  
    "signingConfigs": [{  
      "name": "release",  
      "material": {  
        "certpath": "signature/release.p12",  
        "storePassword": "******",  
        "keyAlias": "release",  
        "keyPassword": "******",  
        "signAlg": "SHA256withECDSA",  
        "profile": "signature/release.p7b",  
        "type": "HarmonyApp"  
      }  
    }],  
    "buildType": "release"  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

2. User Authentication and Permission Management

Educational applications typically require a robust user system. We can leverage AppGallery Connect's Auth Service to quickly implement user authentication.

2.1 Implementing the User Login Module

// User authentication module: UserAuth.ets  
import { agconnect } from '@hw-agconnect/api-ohos';  
import '@hw-agconnect/auth-ohos';  

@Entry  
@Component  
struct LoginPage {  
  @State username: string = ''  
  @State password: string = ''  
  @State loginStatus: string = 'Not logged in'  

  // User login method  
  async login() {  
    try {  
      const user = await agconnect.auth().signIn(this.username, this.password)  
      this.loginStatus = `Login successful: ${user.getUser().getDisplayName()}`  
      // Redirect to the main page after successful login  
      router.replaceUrl({ url: 'pages/MainPage' })  
    } catch (error) {  
      this.loginStatus = `Login failed: ${error.message}`  
    }  
  }  

  build() {  
    Column() {  
      TextInput({ placeholder: 'Enter username' })  
        .onChange((value: string) => {  
          this.username = value  
        })  
      TextInput({ placeholder: 'Enter password', type: InputType.Password })  
        .onChange((value: string) => {  
          this.password = value  
        })  
      Button('Login')  
        .onClick(() => {  
          this.login()  
        })  
      Text(this.loginStatus)  
        .margin(10)  
    }  
    .width('100%')  
    .height('100%')  
    .justifyContent(FlexAlign.Center)  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

2.2 Hierarchical User Permission Management

Educational applications often require distinguishing between teacher, student, and administrator roles. We can implement this using Auth Service's custom attributes:

// Set user role attributes after registration  
async setUserRole(userId: string, role: string) {  
  const auth = agconnect.auth()  
  const user = auth.currentUser  
  if (user) {  
    await user.setCustomAttributes({  
      'role': role,  
      'userId': userId  
    })  
  }  
}  

// Check user role  
async checkUserRole(): Promise<string> {  
  const user = agconnect.auth().currentUser  
  if (user) {  
    const attributes = await user.getCustomAttributes()  
    return attributes['role'] || 'student'  
  }  
  return 'guest'  
}  
Enter fullscreen mode Exit fullscreen mode

3. Course Management and Learning Resource Storage

3.1 Managing Course Data with CloudDB

AppGallery Connect's CloudDB service is ideal for storing course and chapter data:

// Define course object type  
@Observed  
class Course {  
  id: string = ''  
  courseName: string = ''  
  teacherId: string = ''  
  description: string = ''  
  coverUrl: string = ''  
  createTime: number = 0  
}  

// Course management service  
class CourseService {  
  private cloudDB: agconnect.cloudDB.CloudDBZone  

  constructor() {  
    const config = {  
      name: 'CourseZone',  
      persistenceEnabled: true,  
      securityLevel: agconnect.cloudDB.SecurityLevel.STRONG  
    }  
    this.cloudDB = agconnect.cloudDB.CloudDBZoneWrapper.openCloudDBZone(config)  
  }  

  // Add a new course  
  async addCourse(course: Course): Promise<boolean> {  
    try {  
      course.id = generateUUID() // Generate a unique ID  
      course.createTime = new Date().getTime()  
      await this.cloudDB.executeUpsert('Course', [course])  
      return true  
    } catch (error) {  
      console.error('Failed to add course:', error)  
      return false  
    }  
  }  

  // Get all course listings  
  async getAllCourses(): Promise<Array<Course>> {  
    const query = agconnect.cloudDB.CloudDBZoneQuery.where(Course)  
      .orderByDesc('createTime')  
    return await this.cloudDB.executeQuery(query)  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

3.2 Uploading and Downloading Learning Resources

Use AppGallery Connect's Cloud Storage service to store teaching videos and documents:

// File upload service  
class FileService {  
  private storage: agconnect.cloudStorage.CloudStorage  

  constructor() {  
    this.storage = agconnect.cloudStorage()  
  }  

  // Upload learning resources  
  async uploadFile(fileUri: string, courseId: string): Promise<string> {  
    const reference = this.storage.reference(`courses/${courseId}/${Date.now()}`)  
    await reference.putFile(fileUri)  
    return await reference.getDownloadURL()  
  }  

  // Download learning resources  
  async downloadFile(url: string, localPath: string): Promise<void> {  
    const reference = this.storage.referenceFromURL(url)  
    await reference.getFile(localPath)  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

4. Learning Progress Tracking and Data Analysis

4.1 Recording Student Learning Behavior

// Learning record service  
class LearningRecordService {  
  private cloudDB: agconnect.cloudDB.CloudDBZone  

  constructor() {  
    const config = {  
      name: 'LearningZone',  
      persistenceEnabled: true  
    }  
    this.cloudDB = agconnect.cloudDB.CloudDBZoneWrapper.openCloudDBZone(config)  
  }  

  // Record learning activity  
  async recordLearning(courseId: string, chapterId: string, userId: string, duration: number) {  
    const record = {  
      id: generateUUID(),  
      courseId,  
      chapterId,  
      userId,  
      startTime: new Date().getTime(),  
      duration,  
      deviceType: deviceInfo.deviceType  
    }  
    await this.cloudDB.executeUpsert('LearningRecord', [record])  
  }  

  // Get user learning progress  
  async getUserProgress(userId: string, courseId: string) {  
    const query = agconnect.cloudDB.CloudDBZoneQuery.where('LearningRecord')  
      .equalTo('userId', userId)  
      .equalTo('courseId', courseId)  
      .orderByDesc('startTime')  
    return await this.cloudDB.executeQuery(query)  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

4.2 Implementing Personalized Learning Paths with Remote Configuration

// Personalized learning configuration  
class PersonalizedLearning {  
  private remoteConfig: agconnect.remoteConfig.RemoteConfig  

  constructor() {  
    this.remoteConfig = agconnect.remoteConfig()  
    this.remoteConfig.applyDefault({  
      'recommend_algorithm': 'default',  
      'daily_learning_goal': 30,  
      'difficulty_adjustment': 0.5  
    })  
  }  

  // Get learning configuration  
  async getLearningConfig(userLevel: string) {  
    await this.remoteConfig.fetch(0) // 0 means fetch the latest config immediately  
    await this.remoteConfig.apply()  

    return {  
      algorithm: this.remoteConfig.getValue('recommend_algorithm').asString(),  
      dailyGoal: this.remoteConfig.getValue('daily_learning_goal').asNumber(),  
      difficulty: this.remoteConfig.getValue('difficulty_adjustment').asNumber()  
    }  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

5. Online Testing and Instant Feedback System

5.1 Creating an Online Testing Module

// Define question type  
interface Question {  
  id: string  
  courseId: string  
  questionText: string  
  options: string[]  
  correctAnswer: number  
  difficulty: number  
  explanation: string  
}  

// Testing service  
class QuizService {  
  private cloudDB: agconnect.cloudDB.CloudDBZone  

  constructor() {  
    const config = {  
      name: 'QuizZone',  
      persistenceEnabled: true  
    }  
    this.cloudDB = agconnect.cloudDB.CloudDBZoneWrapper.openCloudDBZone(config)  
  }  

  // Get quiz questions for a course  
  async getQuizQuestions(courseId: string, count: number = 10): Promise<Question[]> {  
    const query = agconnect.cloudDB.CloudDBZoneQuery.where('Question')  
      .equalTo('courseId', courseId)  
      .limit(count)  
    return await this.cloudDB.executeQuery(query)  
  }  

  // Submit quiz results  
  async submitQuizResult(userId: string, courseId: string, score: number, answers: Record<string, number>) {  
    const result = {  
      id: generateUUID(),  
      userId,  
      courseId,  
      score,  
      answers: JSON.stringify(answers),  
      submitTime: new Date().getTime()  
    }  
    await this.cloudDB.executeUpsert('QuizResult', [result])  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

5.2 Implementing the Test Interface

@Entry  
@Component  
struct QuizPage {  
  @State questions: Question[] = []  
  @State currentIndex: number = 0  
  @State selectedOption: number = -1  
  @State showResult: boolean = false  
  @State score: number = 0  

  private courseId: string = ''  

  async onPageShow() {  
    const params = router.getParams()  
    this.courseId = params?.courseId || ''  
    this.questions = await new QuizService().getQuizQuestions(this.courseId)  
  }  

  nextQuestion() {  
    if (this.selectedOption === this.questions[this.currentIndex].correctAnswer) {  
      this.score += 10  
    }  

    if (this.currentIndex < this.questions.length - 1) {  
      this.currentIndex++  
      this.selectedOption = -1  
    } else {  
      this.showResult = true  
      new QuizService().submitQuizResult(  
        agconnect.auth().currentUser?.uid || '',  
        this.courseId,  
        this.score,  
        this.collectAnswers()  
      )  
    }  
  }  

  collectAnswers(): Record<string, number> {  
    // Implement answer collection logic  
  }  

  build() {  
    Column() {  
      if (this.showResult) {  
        Text(`Test completed! Score: ${this.score}/${this.questions.length * 10}`)  
          .fontSize(20)  
      } else if (this.questions.length > 0) {  
        Text(`Question ${this.currentIndex + 1}/${this.questions.length}`)  
        Text(this.questions[this.currentIndex].questionText)  
          .margin(10)  

        ForEach(this.questions[this.currentIndex].options, (option, index) => {  
          Radio({ value: index, group: 'options' })  
            .checked(this.selectedOption === index)  
            .onChange((isChecked: boolean) => {  
              if (isChecked) this.selectedOption = index  
            })  
          Text(option)  
        })  

        Button('Next', { type: ButtonType.Normal })  
          .onClick(() => this.nextQuestion())  
          .enabled(this.selectedOption !== -1)  
      } else {  
        Text('Loading questions...')  
      }  
    }  
    .padding(20)  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

6. Application Publishing and Operational Analysis

6.1 Preparing for Application Release

Configure application information, distribution countries, and categories in AppGallery Connect. Ensure educational applications are correctly categorized for better discoverability by target users.

6.2 Analyzing Learning Behavior with AppGallery Connect

// Integrate analytics service  
import '@hw-agconnect/analytics-ohos'  

class AnalyticsService {  
  private analytics: agconnect.analytics.Analytics  

  constructor() {  
    this.analytics = agconnect.analytics()  
  }  

  // Log learning events  
  logLearningEvent(courseId: string, duration: number) {  
    this.analytics.logEvent('learning', {  
      course_id: courseId,  
      duration: duration,  
      user_type: await checkUserRole()  
    })  
  }  

  // Log quiz completion events  
  logQuizCompleted(courseId: string, score: number) {  
    this.analytics.logEvent('quiz_completed', {  
      course_id: courseId,  
      score: score,  
      timestamp: new Date().getTime()  
    })  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

6.3 In-App Messaging and Updates

// Check for application updates  
async checkForUpdates() {  
  const appUpdate = agconnect.appUpdate()  
  const updateInfo = await appUpdate.checkAppUpdate()  

  if (updateInfo.updatePriority === 5) { // High-priority update  
    const result = await appUpdate.startUpdateFlow(updateInfo)  
    if (result === 0) {  
      // User agreed to update  
    }  
  }  
}  

// Fetch in-app messages  
async fetchInAppMessages() {  
  const messaging = agconnect.appMessaging()  
  const messages = await messaging.fetch()  
  messages.display()  
}  
Enter fullscreen mode Exit fullscreen mode

7. Summary and Best Practices

Through this tutorial, we have completed the development of a comprehensive educational application based on HarmonyOS Next and AppGallery Connect. Here are some key best practices:

  1. Data Security: Educational data is sensitive—always use CloudDB's strong security level configuration.
  2. Offline Support: Enable CloudDB persistence to ensure learning continuity in weak network conditions.
  3. Performance Optimization: Use chunked uploads and resumable transfers for large files.
  4. Accessibility: Ensure the application complies with accessibility standards for educational apps.
  5. Multi-Device Collaboration: Leverage HarmonyOS's distributed capabilities for cross-device learning experiences.

Educational application development is an iterative process. Regularly analyze user behavior through AppGallery Connect to continuously optimize the learning experience.

Top comments (0)