DEV Community

linzhongxue
linzhongxue

Posted on

Practical Development of Sports Applications Based on HarmonyOS Next: AppGallery Connect Integration and ArkTS Implementation

Practical Development of Sports Applications Based on HarmonyOS Next: AppGallery Connect Integration and ArkTS Implementation

I. Introduction and Development Environment Setup

With the popularity of smart wearable devices and growing health awareness, sports applications have become a hot field in mobile development. HarmonyOS Next, as a next-generation distributed operating system, provides powerful technical support for sports app development. This chapter will explain how to set up the development environment and create a basic project.

First, ensure you have installed the latest version of DevEco Studio and configured the HarmonyOS SDK. When creating a new project, select the "Application" template, choose ArkTS as the language, and select a phone or smartwatch as the device type.

// Project entry file: EntryAbility.ts  
import UIAbility from '@ohos.app.ability.UIAbility';  
import window from '@ohos.window';  

export default class EntryAbility extends UIAbility {  
  // Create a window when the application starts  
  onCreate(want, launchParam) {  
    console.log('[EntryAbility] onCreate');  
    window.create(this.context, 'mainWindow', (err, data) => {  
      if (err) {  
        console.error('Failed to create window. Cause: ' + JSON.stringify(err));  
        return;  
      }  
      let windowClass = data;  
      windowClass.loadContent('pages/Index', (err) => {  
        if (err) {  
          console.error('Failed to load the content. Cause: ' + JSON.stringify(err));  
          return;  
        }  
        windowClass.show();  
      });  
    });  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

II. AppGallery Connect Service Integration

AppGallery Connect provides key services such as data analytics, user authentication, and cloud storage for sports applications. The integration steps are as follows:

  1. Create a project in the AppGallery Connect console and enable the required services.
  2. Download the agconnect-services.json configuration file and place it in the project's resources directory.
  3. Add dependencies in build-profile.json5.
// Example configuration in build-profile.json5  
{  
  "app": {  
    "signingConfigs": [],  
    "compileSdkVersion": 9,  
    "compatibleSdkVersion": 9,  
    "products": [  
      {  
        "name": "default",  
        "signingConfig": "default",  
        "compileSdkVersion": "9",  
        "compatibleSdkVersion": "9",  
        "runtimeOS": "HarmonyOS"  
      }  
    ]  
  },  
  "modules": [  
    {  
      "name": "entry",  
      "srcPath": "./src/main/ets",  
      "targets": [  
        {  
          "name": "default",  
          "applyToProducts": [  
            "default"  
          ],  
          "dependencies": [  
            {  
              "packageName": "@ohos/agconnect",  
              "version": "1.0.0"  
            },  
            {  
              "packageName": "@ohos/agconnect-auth",  
              "version": "1.0.0"  
            }  
          ]  
        }  
      ]  
    }  
  ]  
}  
Enter fullscreen mode Exit fullscreen mode

III. Sports Data Collection and Processing

The core of a sports application is data collection. HarmonyOS provides rich sensor APIs to gather user movement data.

// Example of sports sensor data collection: SportsSensorManager.ts  
import sensor from '@ohos.sensor';  
import { SportsData } from '../model/SportsData';  

export class SportsSensorManager {  
  private accelerometer: sensor.AccelerometerResponse | null = null;  
  private heartRate: sensor.HeartRateResponse | null = null;  
  private stepCounter: sensor.StepCounterResponse | null = null;  
  private sportsData: SportsData = new SportsData();  

  // Initialize all sensors  
  initSensors(): void {  
    try {  
      // Accelerometer  
      sensor.on(sensor.SensorId.ACCELEROMETER, (data: sensor.AccelerometerResponse) => {  
        this.accelerometer = data;  
        this.updateSportsData();  
      }, { interval: 'normal' });  

      // Heart rate sensor  
      sensor.on(sensor.SensorId.HEART_RATE, (data: sensor.HeartRateResponse) => {  
        this.heartRate = data;  
        this.updateSportsData();  
      }, { interval: 'normal' });  

      // Step counter  
      sensor.on(sensor.SensorId.STEP_COUNTER, (data: sensor.StepCounterResponse) => {  
        this.stepCounter = data;  
        this.updateSportsData();  
      }, { interval: 'normal' });  
    } catch (error) {  
      console.error(`Failed to initialize sensors: ${JSON.stringify(error)}`);  
    }  
  }  

  // Update sports data model  
  private updateSportsData(): void {  
    if (this.accelerometer) {  
      this.sportsData.accelerationX = this.accelerometer.x;  
      this.sportsData.accelerationY = this.accelerometer.y;  
      this.sportsData.accelerationZ = this.accelerometer.z;  
    }  
    if (this.heartRate) {  
      this.sportsData.heartRate = this.heartRate.heartRate;  
    }  
    if (this.stepCounter) {  
      this.sportsData.steps = this.stepCounter.steps;  
    }  
    // Trigger data update event  
    this.notifyDataChanged();  
  }  

  // Data change notification method  
  private notifyDataChanged(): void {  
    // Implement observer pattern to notify related components  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

IV. User Authentication and Data Synchronization

Using AppGallery Connect's authentication service, you can quickly implement user login and sync sports data to the cloud.

// User authentication service: AuthService.ts  
import agconnect from '@ohos/agconnect';  
import { agc } from '@ohos/agconnect-auth';  

export class AuthService {  
  // Anonymous login  
  static async anonymousLogin(): Promise<agc.User> {  
    try {  
      const user = await agconnect.auth().signInAnonymously();  
      console.log('Anonymous login success: ' + JSON.stringify(user));  
      return user;  
    } catch (error) {  
      console.error('Anonymous login failed: ' + JSON.stringify(error));  
      throw error;  
    }  
  }  

  // Email and password login  
  static async emailLogin(email: string, password: string): Promise<agc.User> {  
    try {  
      const user = await agconnect.auth().signInWithEmailAndPassword(email, password);  
      console.log('Email login success: ' + JSON.stringify(user));  
      return user;  
    } catch (error) {  
      console.error('Email login failed: ' + JSON.stringify(error));  
      throw error;  
    }  
  }  

  // Get current user  
  static getCurrentUser(): agc.User | null {  
    return agconnect.auth().getCurrentUser();  
  }  

  // Logout  
  static async logout(): Promise<void> {  
    try {  
      await agconnect.auth().signOut();  
      console.log('Logout success');  
    } catch (error) {  
      console.error('Logout failed: ' + JSON.stringify(error));  
      throw error;  
    }  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

V. Sports Data Visualization

Intuitive display of sports data is crucial for user experience. Below is an example of using ArkUI to draw sports data charts.

// Sports data chart component: SportsChart.ets  
@Component  
export struct SportsChart {  
  @State heartRateData: number[] = [];  
  @State stepData: number[] = [];  

  build() {  
    Column() {  
      // Heart rate chart  
      Text('Heart Rate Trends').fontSize(16).margin({ bottom: 10 })  
      Canvas(this.heartRateContext)  
        .width('100%')  
        .height(200)  
        .backgroundColor('#f5f5f5')  
        .margin({ bottom: 20 })  

      // Step count chart  
      Text('Step Statistics').fontSize(16).margin({ bottom: 10 })  
      Canvas(this.stepContext)  
        .width('100%')  
        .height(200)  
        .backgroundColor('#f5f5f5')  
    }  
  }  

  // Draw heart rate chart  
  private heartRateContext: RenderingContext = new RenderingContext();  
  @Builder  
  private drawHeartRateChart(ctx: RenderingContext) {  
    if (this.heartRateData.length === 0) return;  

    const width = ctx.width;  
    const height = ctx.height;  
    const maxValue = Math.max(...this.heartRateData);  
    const step = width / (this.heartRateData.length - 1);  

    ctx.beginPath();  
    ctx.strokeStyle = '#ff5252';  
    ctx.lineWidth = 2;  

    this.heartRateData.forEach((value, index) => {  
      const x = index * step;  
      const y = height - (value / maxValue) * height;  

      if (index === 0) {  
        ctx.moveTo(x, y);  
      } else {  
        ctx.lineTo(x, y);  
      }  
    });  

    ctx.stroke();  
  }  

  // Draw step count chart  
  private stepContext: RenderingContext = new RenderingContext();  
  @Builder  
  private drawStepChart(ctx: RenderingContext) {  
    if (this.stepData.length === 0) return;  

    const width = ctx.width;  
    const height = ctx.height;  
    const maxValue = Math.max(...this.stepData);  
    const barWidth = width / this.stepData.length - 5;  

    this.stepData.forEach((value, index) => {  
      const barHeight = (value / maxValue) * height;  
      const x = index * (barWidth + 5);  
      const y = height - barHeight;  

      ctx.fillStyle = '#4caf50';  
      ctx.fillRect(x, y, barWidth, barHeight);  
    });  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

VI. Implementing Social Features for Sports

Social features in sports apps can enhance user engagement. Below is an implementation of a friend system and workout sharing.

// Social feature service: SocialService.ts  
import agconnect from '@ohos/agconnect';  
import { cloud } from '@ohos/agconnect-cloud';  

export class SocialService {  
  // Add a friend  
  static async addFriend(friendId: string): Promise<void> {  
    try {  
      const db = cloud.database();  
      const currentUser = agconnect.auth().getCurrentUser();  

      if (!currentUser) {  
        throw new Error('User not logged in');  
      }  

      await db.collection('friendships').add({  
        userId: currentUser.uid,  
        friendId: friendId,  
        createdAt: new Date().toISOString(),  
        status: 'pending'  
      });  

      console.log('Friend request sent successfully');  
    } catch (error) {  
      console.error('Failed to send friend request: ' + JSON.stringify(error));  
      throw error;  
    }  
  }  

  // Share a workout  
  static async shareWorkout(workoutId: string, recipients: string[]): Promise<void> {  
    try {  
      const db = cloud.database();  
      const currentUser = agconnect.auth().getCurrentUser();  

      if (!currentUser) {  
        throw new Error('User not logged in');  
      }  

      await db.collection('shares').add({  
        workoutId: workoutId,  
        senderId: currentUser.uid,  
        recipients: recipients,  
        sharedAt: new Date().toISOString()  
      });  

      console.log('Workout shared successfully');  
    } catch (error) {  
      console.error('Failed to share workout: ' + JSON.stringify(error));  
      throw error;  
    }  
  }  

  // Get friend list  
  static async getFriends(): Promise<any[]> {  
    try {  
      const db = cloud.database();  
      const currentUser = agconnect.auth().getCurrentUser();  

      if (!currentUser) {  
        throw new Error('User not logged in');  
      }  

      const query = db.collection('friendships')  
        .where({  
          userId: currentUser.uid,  
          status: 'accepted'  
        });  

      const result = await query.get();  
      return result.data;  
    } catch (error) {  
      console.error('Failed to get friends list: ' + JSON.stringify(error));  
      throw error;  
    }  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

VII. Performance Optimization and Testing

Sports applications require continuous operation and processing of large amounts of sensor data, making performance optimization critical.

  1. Sensor Sampling Rate Optimization: Adjust sensor sampling frequency based on application scenarios.
  2. Batch Data Processing: Bundle multiple data points for upload to reduce network requests.
  3. Local Caching: Use HarmonyOS's DataAbility for local data caching.
  4. Background Task Management: Properly use background tasks for continuous data collection.
// Performance optimization example: DataBatchUploader.ts  
import agconnect from '@ohos/agconnect';  
import { cloud } from '@ohos/agconnect-cloud';  
import { SportsData } from '../model/SportsData';  

export class DataBatchUploader {  
  private static BATCH_SIZE = 50;  
  private static uploadQueue: SportsData[] = [];  
  private static timerId: number | null = null;  

  // Add to upload queue  
  static addToUploadQueue(data: SportsData): void {  
    this.uploadQueue.push(data);  

    // Upload immediately if batch size is reached  
    if (this.uploadQueue.length >= this.BATCH_SIZE) {  
      this.uploadBatch();  
      return;  
    }  

    // Otherwise, start/reset timer (max wait: 10 seconds)  
    if (this.timerId !== null) {  
      clearTimeout(this.timerId);  
    }  

    this.timerId = setTimeout(() => {  
      this.uploadBatch();  
    }, 10000) as unknown as number;  
  }  

  // Upload batch data  
  private static async uploadBatch(): Promise<void> {  
    if (this.uploadQueue.length === 0) return;  

    const batchToUpload = [...this.uploadQueue];  
    this.uploadQueue = [];  

    if (this.timerId !== null) {  
      clearTimeout(this.timerId);  
      this.timerId = null;  
    }  

    try {  
      const db = cloud.database();  
      const currentUser = agconnect.auth().getCurrentUser();  

      if (!currentUser) {  
        throw new Error('User not logged in');  
      }  

      // Batch write to cloud database  
      const batch = db.startBatch();  
      const collection = db.collection('sportsData');  

      batchToUpload.forEach(data => {  
        batch.set(collection, {  
          userId: currentUser.uid,  
          timestamp: data.timestamp,  
          heartRate: data.heartRate,  
          steps: data.steps,  
          acceleration: {  
            x: data.accelerationX,  
            y: data.accelerationY,  
            z: data.accelerationZ  
          }  
        });  
      });  

      await batch.commit();  
      console.log(`Successfully uploaded ${batchToUpload.length} records`);  
    } catch (error) {  
      console.error('Batch upload failed: ' + JSON.stringify(error));  
      // Re-add to queue if failed  
      this.uploadQueue.unshift(...batchToUpload);  
    }  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

VIII. Publishing and Operational Analytics

After development, publish the app via AppGallery Connect and analyze user behavior data.

  1. App Publishing: Configure app information, build versions, and submit for review.
  2. A/B Testing: Test feature effectiveness with different user groups.
  3. Data Analytics: Use AppGallery Connect's analytics tools to track key metrics.
// Operational analytics example: AnalyticsService.ts  
import agconnect from '@ohos/agconnect';  
import { analytics } from '@ohos/agconnect-analytics';  

export class AnalyticsService {  
  // Log custom events  
  static logEvent(eventName: string, params: Record<string, string> = {}): void {  
    try {  
      analytics.instance().onEvent(eventName, params);  
      console.log(`Event logged: ${eventName}`);  
    } catch (error) {  
      console.error(`Failed to log event: ${JSON.stringify(error)}`);  
    }  
  }  

  // Log user properties  
  static setUserProperty(key: string, value: string): void {  
    try {  
      analytics.instance().setUserProperty(key, value);  
      console.log(`User property set: ${key}=${value}`);  
    } catch (error) {  
      console.error(`Failed to set user property: ${JSON.stringify(error)}`);  
    }  
  }  

  // Log screen views  
  static logScreenView(screenName: string): void {  
    try {  
      analytics.instance().setCurrentScreen(screenName);  
      console.log(`Screen view logged: ${screenName}`);  
    } catch (error) {  
      console.error(`Failed to log screen view: ${JSON.stringify(error)}`);  
    }  
  }  
}  
Enter fullscreen mode Exit fullscreen mode

IX. Conclusion and Future Directions

This article detailed the entire process of developing a sports application based on HarmonyOS Next and AppGallery Connect. From environment setup to core feature implementation, performance optimization, and operational analytics, it covered key development aspects.

Future expansion directions include:

  1. Cross-Device Collaboration: Utilize HarmonyOS's distributed capabilities for data sync between phones and wearables.
  2. AI-Based Motion Recognition: Integrate machine learning models to identify exercise types and form accuracy.
  3. AR-Based Exercise Guidance: Provide real-time posture correction using AR technology.
  4. Competition Features: Develop online sports challenges and event systems.

Through continuous iteration and innovation, more competitive sports applications can be created, offering users better health and fitness services.

Top comments (0)