Build a Smart Umbrella Reminder on HarmonyOS NEXT: Background Alerts with ArkTS
This tutorial walks through building a HarmonyOS NEXT app that uses ArkTS and the reminderAgentManager API to deliver daily 7:30 AM weather-based umbrella notifications, covering permissions, network requests, decision logic, and UI design.
Introduction
As a developer who rushes to work early, the author often forgot to check the weather and got caught in the rain. Existing weather apps require opening them or push irrelevant news. The goal was a pure, single-purpose function: every morning at 7:30, a reminder pops up telling whether to bring an umbrella. The author built this "Umbrella Reminder" app on HarmonyOS NEXT using ArkTS, and this article dissects the full implementation from low-level logic to UI, network requests, and background reminder tasks.
Technical Selection and Design
Core Problems
Data source : Where to get real-time weather data?
Trigger mechanism : How to wake the system at 7:30 AM even after the app process is killed?
Decision logic : How to translate weather data into a clear "bring umbrella" recommendation?
Tech Stack
IDE: DevEco Studio
SDK: HarmonyOS NEXT SDK (API 12)
Core capabilities: @ohos.net.http: Call third-party weather API for real-time data. @ohos.reminderAgentManager: Register background agent reminders so the system shows notifications even if the app process is dead. @ohos.data.preferences: Persist user city and reminder time.
Logic Flow
Initialization : User sets city and reminder time (e.g., 07:30).
Register reminder : Use reminderAgentManager to register an alarm-style reminder.
Execute task : System wakes app logic at the specified time (or triggers refresh on notification click).
Weather verification : Request weather API, parse rain (precipitation) or weather_code.
Push result : Send final notification based on precipitation probability.
Hands-On: From Architecture to Core Logic
1. Permission Declaration
In module.json5, declare two required permissions:
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.INTERNET",
"reason": "$string:reason_internet",
"usedScene": { "abilities": ["EntryAbility"], "when": "always" }
},
{
"name": "ohos.permission.PUBLISH_AGENT_REMINDER",
"reason": "$string:reason_reminder",
"usedScene": { "abilities": ["EntryAbility"], "when": "always" }
}
]
}
}2. Weather Model Definition
Define TypeScript interfaces matching mainstream weather API responses (e.g., QWeather), focusing on precipitation:
// WeatherModel.etsexport interface WeatherData {
temp: string; // temperature
text: string; // weather phenomenon (sunny, rain, snow...)
precip: string; // precipitation (mm)
humidity: string; // humidity
}
export class WeatherResult {
code: string = "";
now: WeatherData = {
temp: "0",
text: "Unknown",
precip: "0",
humidity: "0"
};
}3. Network Layer Encapsulation
Wrap HarmonyOS native http module with Promise for async requests:
// WeatherService.etsimport http from '@ohos.net.http';
import { WeatherResult } from './WeatherModel';
export class WeatherService {
private static readonly API_KEY = 'YOUR_API_KEY';
private static readonly BASE_URL = 'https://devapi.qweather.com/v7/weather/now';
static async getTodayWeather(locationID: string): Promise<WeatherResult> {
let httpRequest = http.createHttp();
let url = `
${this.BASE_URL}?location=${locationID}&key=${this.API_KEY}`;
try {
let response = await httpRequest.request(url, {
method: http.RequestMethod.GET,
expectDataType: http.HttpDataType.OBJECT
});
if (response.responseCode === 200) {
return response.result as WeatherResult;
}
} catch (err) {
console.error('Weather fetch failed:', JSON.stringify(err));
} finally {
httpRequest.destroy();
}
return new WeatherResult();
}
}Core Challenge: Background Agent Reminder Implementation
Ordinary timers ( setTimeout) become unreliable when the app goes to background. HarmonyOS requires reminderAgentManager for reliable background alerts.
1. Register Daily Reminder Task
Use ReminderRequestAlarm for daily recurring triggers:
// ReminderManager.etsimport reminderAgentManager from '@ohos.reminderAgentManager';
import notificationManager from '@ohos.notificationManager';
export class ReminderManager {
static async publishDailyReminder(hour: number, minute: number) {
let targetReminder: reminderAgentManager.ReminderRequestAlarm = {
reminderType: reminderAgentManager.ReminderType.REMINDER_TYPE_ALARM,
hour: hour,
minute: minute,
daysOfWeek: [1, 2, 3, 4, 5, 6, 7], // daily
title: 'Umbrella Action: Weather Self-Check',
content: 'Checking today\'s weather for you, tap to see if you need an umbrella',
alarmIndex: 1,
ringDuration: 5, // ring 5 seconds
wantAgent: {
pkgName: 'com.example.weatherreminder',
abilityName: 'EntryAbility'
},
slotType: notificationManager.SlotType.SOCIAL_COMMUNICATION
};
try {
let reminderId = await reminderAgentManager.publishReminder(targetReminder);
console.info('Reminder published, ID: ' + reminderId);
} catch (error) {
console.error('Failed to publish reminder: ' + JSON.stringify(error));
}
}
}2. Decision Algorithm: To Bring Umbrella or Not?
Logic based on precipitation value and weather text:
// UmbrellaLogic.etsexport function getUmbrellaAdvice(precip: string, text: string): { title: string, advice: string, icon: Resource } {
const rainValue = parseFloat(precip);
if (rainValue > 0 || text.includes("雨")) {
if (rainValue > 10) {
return { title: "Heavy Rain", advice: "Heavy rain today, bring a long umbrella and wear waterproof shoes!", icon: $r('app.media.heavy_rain') };
}
return { title: "Rain Today", advice: "Bring a folding umbrella, just in case.", icon: $r('app.media.light_rain') };
} else if (text.includes("云") || text.includes("阴")) {
return { title: "Cloudy", advice: "Gloomy weather, an umbrella for rain or shade is nice.", icon: $r('app.media.cloudy') };
} else {
return { title: "Sunny", advice: "Sunny and bright, no umbrella needed, remember sunscreen.", icon: $r('app.media.sunny') };
}
}UI Design: Clean and Intuitive
Main interface built with ArkUI RelativeContainer, Column, Stack, gradient background, blur effects, and a weather card showing temperature, condition, title, and advice. A settings list item lets user view reminder time, and a "Test Reminder Now" button triggers a test notification in 1 minute.
// Index.ets (excerpt)@Entry@Component
struct Index {
@State weather: WeatherData = { temp: '--', text: 'Loading...', precip: '0', humidity: '0' };
@State advice: string = "Fetching...";
@State title: string = "Good Morning";
@State reminderTime: string = "07:30";
aboutToAppear() {
this.refreshWeather();
}
async refreshWeather() {
let res = await WeatherService.getTodayWeather('101010100'); // Beijing LocationID
if (res.now) {
this.weather = res.now;
let result = getUmbrellaAdvice(this.weather.precip, this.weather.text);
this.advice = result.advice;
this.title = result.title;
}
}
build() {
Stack() {
Column()
.width('100%')
.height('100%')
.linearGradient({
direction: GradientDirection.Bottom,
colors: [['#4facfe', 0.0], ['#00f2fe', 1.0]]
})
Column({ space: 20 }) {
Text('Umbrella Assistant')
.fontSize(28).fontWeight(FontWeight.Bold).fontColor(Color.White).margin({ top: 60 })
Column() {
Text(`${this.weather.temp}°C`).fontSize(64).fontColor(Color.White).fontWeight(FontWeight.Lighter)
Text(this.weather.text).fontSize(24).fontColor(Color.White)
Divider().margin({ top: 20, bottom: 20 }).color('#66FFFFFF')
Text(this.title).fontSize(22).fontWeight(FontWeight.Medium).fontColor(Color.White)
Text(this.advice).fontSize(16).fontColor('#F5F5F5').textAlign(TextAlign.Center).margin({ top: 10, left: 20, right: 20 })
}
.width('90%').padding(30).backgroundColor('#33000000').borderRadius(24).blur(10)
List() {
ListItem() {
Row() {
Text('Morning Reminder Time').fontColor(Color.White)
Blank()
Text(this.reminderTime).fontColor(Color.White).opacity(0.8)
Image($r('app.media.arrow_right')).width(16).fillColor(Color.White)
}.width('100%').padding(16)
}
}.width('90%').backgroundColor('#22000000').borderRadius(16)
Button('Test Reminder Now')
.width('80%').height(50).backgroundColor('#FFFFFF').fontColor('#4facfe').fontWeight(FontWeight.Bold)
.onClick(() => {
const now = new Date();
ReminderManager.publishDailyReminder(now.getHours(), now.getMinutes() + 1);
})
}.width('100%').height('100%')
}
}
}Deep Dive: Ensuring Reminder Reliability
1. Dynamic Permission Request
Even with PUBLISH_AGENT_REMINDER declared in module.json5, some OS versions require a runtime notification authorization dialog. Request it in aboutToAppear:
import notificationManager from '@ohos.notificationManager';
notificationManager.requestEnableNotification().then(() => {
console.info('Notification authorized');
}).catch((err) => {
console.error('Notification authorization failed', err);
});2. Data Persistence
Persist user-set reminder time (e.g., 07:30) using Preferences so it survives app restarts:
import dataPreferences from '@ohos.data.preferences';
async function saveReminderTime(time: string) {
let pref = await dataPreferences.getPreferences(getContext(), 'settings');
await pref.put('reminder_time', time);
await pref.flush();
}3. Agent Reminder Wake-Up Mechanism
When the scheduled time arrives, the system shows a notification. If the user taps it, the system launches EntryAbility. In EntryAbility.ets, override onWindowStageCreate or onNewWant to detect this launch and trigger a fresh weather fetch, achieving "tap notification to auto-refresh latest weather".
Running and Debugging Steps
Environment : Open DevEco Studio NEXT, create an Empty Ability project.
Network config : Ensure module.json5 includes INTERNET permission.
API Key : Get a free key from QWeather developer platform, paste into WeatherService.ets. For offline testing, mock WeatherResult data.
Real-device test : Background agent reminders may be unstable on emulator; use a real device (e.g., Mate 60 or newer).
Verify logic :
Open app, tap "Test Reminder Now".
Lock screen or go to home screen.
Wait 1 minute, observe system-level alarm notification.
Tap notification, confirm app navigates to main page and shows latest umbrella advice.
Project Summary and Future Extensions
This mini-project practiced core HarmonyOS NEXT capabilities:
ArkUI declarative UI : Gaussian blur, gradient backgrounds for modern look.
Background agent reminder : Solves the classic mobile dev pain of "timers die when process is killed".
Network and data handling : Standard async patterns keep UI responsive.
Future upgrades:
Auto-location : Integrate @ohos.geoLocationManager to fetch weather for current location instead of fixed Beijing.
Service Widget (card) : Surface "umbrella advice" as a desktop widget so users see it without opening the app.
Multi-level alerts : Stronger vibration/alerts for extreme weather like typhoons or heavy storms.
Conclusion
HarmonyOS NEXT provides fertile ground for developers. System-integrated capabilities like reminderAgentManager turn complex background logic into simple APIs. The codebase is small but covers a complete production-tool loop. Hope readers can build their own weather-aware "personal weather butler" in DevEco Studio.
Source tip: Replace YOUR_API_KEY in WeatherService with a real key. For local-only runs, modify getTodayWeather to return a static JSON object for quick verification.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
51CTO HarmonyOS Developer Community
The HarmonyOS Developer Community is a learning-oriented community for developers to learn, communicate, ask questions, and share.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
