الإشعارات
الإشعارات المحلية والتذكيرات
اعرض إشعارات فورية، أو جدول تذكيرات تُطلَق حتى والتطبيق مغلق: على الجهاز نفسه، بدون خادم
1ما الذي تضيفه#
يمكن لتطبيقك عرض إشعارات Android من كوده الخاص، على مستويين:
- فوري (المستوى 1): إشعار يظهر الآن، والتطبيق مفتوح. مناسب لـ "اكتمل التنزيل" و"انتهى المؤقت" وما شابه.
- التذكيرات المجدولة (المستوى 2): إشعار يُطلَق في وقت لاحق حتى عندما يكون التطبيق مغلقًا، ويبقى بعد إعادة التشغيل. هذا ما تحتاجه تطبيقات التذكير والعادات والمنبهات والأدوية.
هذه الميزات تعمل 100% على الجهاز وبدون إنترنت: بدون خادم وبدون حساب OneSignal. (إشعارات OneSignal ميزة منفصلة لرسائل ترسلها أنت من خادم.)
2فعّله في معالج الإنشاء#
في الخطوة 4 (الوصول)، فعّل:
- 🔔 الإشعارات: تسمح للتطبيق بنشر الإشعارات (تضيف POST_NOTIFICATIONS).
- ⏰ التذكيرات: تضيف إشعارات مجدولة تُطلَق والتطبيق مغلق (تضيف مكونات التنبيه الدقيق وإعادة الجدولة عند الإقلاع). تفعيل التذكيرات يفعّل الإشعارات تلقائيًا.
اترك الخيارين معطّلين للتطبيقات التي لا تحتاج إلى إشعارات، فلا يُضاف أي شيء زائد إلى APK الخاص بك.
3استدعِ الجسر من كود الويب لديك#
يوفر AppMint جسر JavaScript على window.WebToApk. تحقق دائمًا من وجوده أولًا، فهو موجود داخل التطبيق المثبّت فقط، لذلك يستمر موقعك في العمل في المتصفح.
const b = window.WebToApk || null;
// Ask once (Android 13+):
b?.requestNotificationPermission();
// Tier 1 — instant (app open):
b?.showNotification('Saved', 'Your note was saved', '', 'note');
// Tier 2 — scheduled reminder in 1 hour:
b?.scheduleNotification(
'water-1',
'Drink water',
'Time for a glass of water',
String(Date.now() + 60*60*1000),
'daily' // none | minutely | hourly | daily | weekly
);
b?.cancelNotification('water-1');
b?.cancelAllNotifications();
const pending = JSON.parse(b?.getScheduledNotifications() || '[]');4دع الذكاء الاصطناعي يربطه نيابةً عنك#
في AI App Studio، صِف ما تريده فقط، مثل: 'تذكير بشرب الماء ينبهني كل ساعتين' أو 'متتبع أدوية يذكرني في الثامنة صباحًا يوميًا'. عندما يذكر طلبك التذكيرات أو المنبهات أو الإشعارات، يعلّم AppMint الذكاء الاصطناعي تلقائيًا هذا الجسر ليستخدمه التطبيق الناتج بشكل صحيح (مع بديل سلس عندما لا يكون متاحًا).
5صوتك الخاص بدل الصوت الافتراضي في Android#
ضع ملفًا صوتيًا في حزمة الويب (mp3 أو wav أو ogg أو m4a أو flac أو opus) وحدد مساره كصوت. يعمل بالطريقة نفسها مع إشعار فوري ومع تذكير يُطلَق بعد أيام والتطبيق مغلق.
يُنسخ الملف إلى مكانه عند الجدولة، لذلك يعود اسم الملف الخاطئ بقيمة false فورًا بدل أن يتحول إلى الصوت الافتراضي في الساعة 7 صباحًا.
قاعدة في Android يجدر معرفتها: يُحدَّد صوت قناة الإشعارات عند إنشائها، لذلك ينشئ AppMint قناة منفصلة لكل صوت. وعليه فتغيير الصوت يعيد ضبط إعدادات تلك القناة في شاشة الإشعارات في Android، وهذا أمر لا مفر منه وهو السلوك الصحيح.
const b = window.WebToApk || null;
// Instant, with your sound:
b?.notify(JSON.stringify({
title: 'Order confirmed',
body: 'Arriving Tuesday',
sound: '/audio/chime.mp3' // a file in YOUR bundle
}));
// Check a sound before you save it in a settings screen:
const ok = b?.prepareNotificationSound('/audio/chime.mp3');
// 'silent' for no sound at all; leave it out for the Android default.6تذكيرات بالصوت والصور والأزرار#
تأخذ scheduleNotificationEx() كل ما تأخذه notify() بالإضافة إلى وقت الإطلاق. استخدمها بدل scheduleNotification() الأقدم ذات الوسائط الخمسة عندما تريد أكثر من عنوان ونص.
const b = window.WebToApk || null;
b?.scheduleNotificationEx('dose-1', JSON.stringify({
at: Date.now() + 60*60*1000, // epoch millis
repeat: 'daily', // none|minutely|hourly|daily|weekly
title: 'Time for your dose',
body: 'Vitamin D — 1 tablet',
sound: '/audio/chime.mp3',
actions: [{ id: 'taken', label: 'Taken' }]
}));
// Returns false if the sound file does not exist — check it.7فتح التطبيق نفسه في وقت محدد#
أضف openApp: true فيصبح التذكير تنبيهًا بملء الشاشة: على هاتف مقفل يُفتح التطبيق فوق شاشة القفل، وعلى هاتف مفتوح يظهر كشريط تنبيه منبثق.
هذا كل ما يسمح به Android. لا يمكن لتطبيق أن يشغّل نفسه بصمت في الخلفية، وهذا ممنوع منذ Android 10، لذلك فأي صفحة تَعِد بأن "التطبيق يُفتح وحده في الساعة 7 صباحًا" يجب أن تمر عبر هذه الآلية. في Android 14 وما بعده يمنح المستخدم إذن التنبيه لكل تطبيق؛ تحقق من canOpenAppAtTime() ووجّهه إلى شاشة الإعدادات إذا كانت النتيجة denied.
عندما يُفتح التطبيق بهذه الطريقة تتلقى صفحتك حدث appmint:reminder، فيمكنها تنفيذ العمل الذي لم تستطع إنجازه وهي مغلقة.
const b = window.WebToApk || null;
if (b?.canOpenAppAtTime() === 'denied') b?.requestOpenAppPermission();
b?.scheduleNotificationEx('standup', JSON.stringify({
at: tomorrowAt9am, repeat: 'daily',
title: 'Stand-up', body: 'Daily sync starts now',
sound: '/audio/alarm.mp3',
openApp: true
}));
window.addEventListener('appmint:reminder', e => {
// e.detail = { id: 'standup', overLockScreen: true }
showReminderScreen(e.detail.id);
});8الموثوقية على الأجهزة الحقيقية#
التذكيرات المجدولة موثوقة بقدر ما يسمح به Android:
- في Android 12 وما بعده، يحتاج التوقيت الدقيق إلى SCHEDULE_EXACT_ALARM. إذا كان معطّلًا لتطبيقك، يُضبط التذكير ضمن نافذة مدتها 10 دقائق (وأكثر أثناء سكون الهاتف)، ويشرح التطبيق ذلك للمستخدم مرة واحدة. اسأل getAlarmPrecision() فهي تعيد 'exact' أو 'inexact'، واستدعِ requestExactAlarms() لتوجيه المستخدم إلى الإعداد. يمكن لتطبيق منبه أو تقويم أن يحدد "تطبيقي منبه أو تقويم" في المعالج، فتصبح التنبيهات الدقيقة مفعّلة دائمًا (يشترط Google Play إقرار Exact alarm في Play Console).
- بعض الهواتف (Xiaomi وSamsung وOppo وغيرها) تؤخر التنبيهات في الخلفية أو توقفها لتوفير البطارية. يشرح التطبيق ذلك مرة واحدة (مع مسار حدود الاستخدام في الخلفية في Samsung) ويفتح قائمة تحسين البطارية.
- تُعاد جدولة التذكيرات تلقائيًا بعد إعادة التشغيل أو تحديث التطبيق.
9أعد المستخدمين الذين أوقفوا الإشعارات#
يضغط كثيرون على "عدم السماح" في نافذة الإشعارات في Android 13، أو يتجاهلونها، ولا يعرض Android تلك النافذة إلا عددًا محدودًا من المرات. بعد ذلك لا يمكن إعادة تفعيلها إلا من إعدادات الإشعارات الخاصة بالتطبيق.
AppMint.enableNotifications() يتصرف بالشكل الصحيح عند الضغط على زر من المستخدم: نافذة الإذن ما دام Android قادرًا على عرضها، وإلا إعدادات الإشعارات في التطبيق، ويخبرك بالحالة الجديدة عندما يعود المستخدم. تعيد getNotificationState() القيم 'granted' أو 'prompt' (يمكن الطلب بعد) أو 'blocked' (الإعدادات وحدها تحل المشكلة) أو 'unavailable' (الإصدار لا يتضمن إشعارات). اعرض شريطك فقط عند 'prompt' و'blocked'، ولا تطلب الإذن عند التشغيل أبدًا.
زر في رسالة دفع أو رسالة داخل التطبيق برابط appmint://notifications/enable يؤدي الغرض نفسه بدون أي كود في الصفحة.
const A = window.AppMint;
if (A?.enableNotifications) {
const state = await A.getNotificationState();
// 'granted' | 'prompt' | 'blocked' | 'unavailable'
banner.hidden = !(state === 'prompt' || state === 'blocked');
turnOnButton.onclick = async () => {
const r = await A.enableNotifications();
// r = { state, changed, openedSettings }
banner.hidden = r.state === 'granted';
};
}
// Just the settings screen:
A?.openNotificationSettings?.();