Umang: عدة حسابات واتساب وSlack، ومُثبِّت حجمه 3 ميغابايت
Umang تطبيق سطح مكتب مجاني لأنظمة macOS وWindows وLinux، يضع حسابات المراسلة لديك جنبًا إلى جنب: واتساب، وSlack، وTelegram، وDiscord، وGmail، أو أي تطبيق ويب تضيفه بعنوانه. رقمان على واتساب، وSlack للعمل وآخر شخصي، مجمّعة في مساحات عمل — كلها مسجّلة الدخول في الوقت نفسه، دون أن يُخرج أحدها الآخر.
عادةً ما تأتي التطبيقات من هذا النوع بنسخة كاملة من Chromium. أما Umang فلا. فهو مبني بإطار Tauri، لذا يستخدم محرّك الويب الموجود أصلًا في نظام التشغيل. في نسخة الإصدار على macOS ومن دون أي خدمة مفتوحة، يبلغ حجم المُثبِّت 3.1 ميغابايت، ويرفض نظام التكامل المستمر (CI) لدينا نشر أي مُثبِّت يصل إلى 10 ميغابايت.
نافذة واحدة، وعروض ويب كثيرة
تحتوي نافذة Umang على عرض ويب واحد لواجهته الخاصة — المكتوبة بـ Svelte — وعرض ويب أصلي إضافي لكل خدمة تضيفها. ولا يُنشأ عرض الويب الخاص بالخدمة إلا عند فتحها أول مرة.
تتولّى Rust كل ما هو مهم: قائمة الخدمات، والإعدادات، والتحقق من المدخلات، وعروض الويب نفسها. أما جانب Svelte فيرسم الواجهة فقط، وهو الصفحة الوحيدة المسموح لها باستدعاء أوامر Umang. وتحصل صفحات الخدمات — واتساب وSlack وغيرها — على مجموعة أصغر بكثير: الإبلاغ عن إشعار، أو اختصار لوحة مفاتيح، أو ما إذا كانت مسجّلة الدخول. والخدمة التي تضيفها بعنوان URL تحصل على هذه المجموعة الصغيرة لنطاقها فقط.
إبقاء الحسابات منفصلة
تحصل كل خدمة على معرّف عشوائي خاص بها، يحدّد قسم تخزين منفصلًا لملفات تعريف الارتباط وبيانات الموقع. وتختلف طريقة إنشاء هذا القسم حسب النظام:
- macOS: يحصل كل حساب على مخزن بيانات WebKit خاص به. هذه الواجهة البرمجية متاحة فقط بدءًا من macOS 14، ولهذا يحتاج Umang إلى macOS 14 أو أحدث — فالإصدارات الأقدم لا تستطيع ببساطة فصل جلستَي واتساب عن بعضهما.
- Windows وLinux: يحصل كل حساب على مجلد بيانات خاص به.
لا يخزّن Umang نفسه أي كلمة مرور أو رمز دخول؛ فكل خدمة تحتفظ بتسجيل دخولها في قسمها الخاص. وعند إزالة خدمة يمكنك اختيار مسح تسجيل دخولها أو الاحتفاظ به، وإذا أضفت التطبيق نفسه مجددًا بالاسم نفسه استعاد تسجيل الدخول المحفوظ.
وفي التنظيف كنّا حذرين. تُحذف الأقسام غير المستخدمة بعد ثانيتين من إغلاق عرض الويب الخاص بها، لأن WebView2 على Windows قد يُبقي الملفات مقفلة لحظات، ثم يُعاد فحصها عند كل تشغيل. وإذا تعذّر على Umang قراءة قاعدة بياناته في تلك اللحظة، فإنه لا يحذف شيئًا. فالحذف دون معرفة الأقسام المستخدمة فعلًا سيُخرجك من جميع حساباتك.
وكيل مستخدم لا يتقادم
يرفض واتساب وSlack العمل في المحرّكات التي ليست Chromium، وفي إصدارات Chrome القديمة. لذا يقدّم Umang نفسه على أنه Chrome — ولكن أي إصدار؟ الرقم المكتوب ثابتًا في الشيفرة سيتقادم بين إصداراتنا.
يُصدر Chrome نسخة مستقرة جديدة كل أربعة أسابيع، فيحسب Umang رقم الإصدار من التاريخ:
// Anchor: Chrome 141 stable on 2025-09-30
const ANCHOR: u64 = 1_759_190_400;
const CYCLE: u64 = 28 * 24 * 3600;
141 + unix_secs.saturating_sub(ANCHOR) / CYCLE - 1
وهو يبقى عمدًا متأخرًا إصدارًا واحدًا عن أحدث إصدار مستقر.
إشعارات تفتح المحادثة الصحيحة
ترسل تطبيقات الويب إشعاراتها عبر واجهة Notification في المتصفح، أو عبر عامل الخدمة (service worker) الخاص بها. يحقن Umang نصًا برمجيًا صغيرًا في كل صفحة خدمة يستبدل الطريقتين معًا ويمرّر الإشعار إلى Rust، التي تنظّف النص — بإزالة محارف التحكم وتحديد الطول — قبل عرض إشعار أصلي يحمل اسم الحساب ومساحة العمل.
ويتذكّر النص البرمجي أيضًا آخر 50 إشعارًا. وعند النقر على أحدها، يفتح Umang تلك الخدمة ويشغّل معالج النقر الخاص بالصفحة نفسها، فتصل إلى المحادثة التي أرسلت الإشعار بدلًا من الشاشة الرئيسية للتطبيق.
ويحتاج وضع «الإشارات فقط» إلى معرفة الرسائل المباشرة. يقرأ Umang وسم الإشعار: جهات اتصال واتساب تنتهي بـ @c.us بينما تنتهي المجموعات بـ @g.us، ومحادثات الرسائل المباشرة في Slack تبدأ بالحرف D.
وتأتي أعداد الرسائل غير المقروءة من عنوان الصفحة — فمعظم هذه التطبيقات تضع «(3)» في بدايته. تقرأ Rust العنوان مباشرةً، وتجمع أعداد الخدمات غير المكتومة، وتعرض المجموع على شريط Dock أو شريط المهام أو منطقة الإشعارات.
وثمة فجوة نعترف بها: الإشعار الذي يُطلقه عامل الخدمة بينما صفحة الخدمة غير مشغّلة لا يُمرَّر بعد.
تطبيقات ويب كثيرة وذاكرة محدودة
كل خدمة هي تطبيق ويب حقيقي، وخمس منها قد تستهلك الكثير من الذاكرة. لذا يضع Umang الخدمات في وضع السكون: افتراضيًا، تدخل الخدمة التي لم تفتحها منذ 30 دقيقة في السبات، ولا يبقى أكثر من ثلاث خدمات نشطة، ويبدأ الإسبات بالأقل استخدامًا مؤخرًا. ويمكنك تعيين خدمة على «لا تنم أبدًا»، فلا تُحتسب ضمن هذا الحد.
أما ما لم نفعله فهو ترك نظام التشغيل يبطّئ الصفحات المخفية من تلقاء نفسه. فعلى macOS، يعلّق WebKit الصفحة المخفية بعد نحو خمس دقائق، فينقطع اتصال واتساب وتنقطع إشعاراته معه. لذلك أوقفنا التبطيء في الخلفية، وصار قرار الإسبات بيدنا لا بيد المحرّك. وعلى Windows، تحصل الخدمات المخفية على هدف الذاكرة المنخفضة في WebView2، الذي يجعل Chromium يحرّر ذاكرته المؤقتة؛ أما macOS وLinux فلا يوفّران تحكمًا علنيًا كهذا.
وتستهلك واجهة التطبيق نفسها نحو 78 ميغابايت على macOS مقابل هدف قدره 80 ميغابايت. الهامش ضيّق، وملاحظاتنا الداخلية تقول ذلك صراحةً.
العروض الأصلية تبقى في الأعلى
تُرسم عروض الويب الأصلية دائمًا فوق واجهة HTML. وهذا يمنع حيل الويب المعتادة: لا يمكن لنافذة حوار أن تظهر ببساطة فوق واتساب. لذلك عندما تُفتح نافذة حوار، يُخفي Umang الخدمة النشطة، وقوائم النقر بزر الفأرة الأيمن قوائم أصلية.
وتسبّب ذلك أيضًا في خلل حقيقي. فالواجهة تقيس منطقة المحتوى وتخبر Rust بمكان وضع عرض الويب الخاص بالخدمة. وعند تغيير حجم النافذة بسرعة، كان من الممكن أن تصل عدة رسائل من هذا النوع بترتيب خاطئ، فتظهر الخدمة مقصوصة بحجم قديم. والحل: طلب واحد فقط لتغيير الحجم قيد التنفيذ في كل مرة، والحجم الأحدث هو الذي يُعتمد.
Linux، ومعرفة متى تتجمّد الصفحة
جاء Linux بمفاجآته الخاصة. لا يمكن تشغيل نافذة حفظ GTK داخل دالة رد التنزيل في WebKitGTK، لذا تطلب التنزيلات مكان الحفظ عبر zenity أو kdialog بدلًا منها. ولا يحصل Linux إلا على حزمة .deb: فحزمة AppImage تضم WebKit الخاص بها، وعادةً ما يتجاوز حجمها حد الملف البالغ 25 ميبيبايت لدى خدمة الاستضافة التي نوزّع منها. ويثبّت المحدِّث حزمة .deb الجديدة نيابةً عنك، ما يعني أن مستخدمي Linux يرون طلبًا لكلمة مرور المسؤول.
وقد تتجمّد تطبيقات الويب أيضًا. عندما تفتح خدمة تعمل بالفعل، يرسل إليها Umang إشارة تحمل قيمة تُستخدم مرة واحدة. وإذا لم يصل رد خلال خمس ثوانٍ، تُعلَّم الخدمة بأنها لا تستجيب، ويعيد زر «إعادة التحميل» إنشاء عرض الويب الخاص بها مع بقاء تسجيل دخولك.
حدود معروفة
قد ترفض Google تسجيل الدخول داخل عرض ويب مضمَّن، وهذا قد يؤثر في Gmail. ومُثبِّت Windows غير موقَّع رقميًا بعد، لذا يعرض Windows تحذير SmartScreen عند تشغيله أول مرة.
Umang متاح مجانًا على umang.kreasimaju.id.