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();
});
});
}
}
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:
- Create a project in the AppGallery Connect console and enable the required services.
- Download the
agconnect-services.json
configuration file and place it in the project'sresources
directory. - 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"
}
]
}
]
}
]
}
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
}
}
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;
}
}
}
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);
});
}
}
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;
}
}
}
VII. Performance Optimization and Testing
Sports applications require continuous operation and processing of large amounts of sensor data, making performance optimization critical.
- Sensor Sampling Rate Optimization: Adjust sensor sampling frequency based on application scenarios.
- Batch Data Processing: Bundle multiple data points for upload to reduce network requests.
- Local Caching: Use HarmonyOS's DataAbility for local data caching.
- 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);
}
}
}
VIII. Publishing and Operational Analytics
After development, publish the app via AppGallery Connect and analyze user behavior data.
- App Publishing: Configure app information, build versions, and submit for review.
- A/B Testing: Test feature effectiveness with different user groups.
- 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)}`);
}
}
}
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:
- Cross-Device Collaboration: Utilize HarmonyOS's distributed capabilities for data sync between phones and wearables.
- AI-Based Motion Recognition: Integrate machine learning models to identify exercise types and form accuracy.
- AR-Based Exercise Guidance: Provide real-time posture correction using AR technology.
- 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)