Widget هو عنصر واجهة مستخدم مصغر على الشاشة الرئيسية لنظام iOS أو Android يعرض معلومات محدثة دون فتح التطبيق. ظهرت الأدوات في iOS 14 (2020) مع إطار عمل WidgetKit على SwiftUI وهي موجودة في Android منذ الإصدار 1.5 عبر AppWidgetProvider على Kotlin أو Java. تتيح للمستخدم رؤية الطقس وأسعار العملات والتقويم والملاحظات أو حالة المهام مباشرة على الشاشة الرئيسية، مما يوفر الوقت ويبسط التفاعل. وفقًا لـ Apple، يتفاعل المستخدمون مع الأدوات في المتوسط 4–6 مرات يوميًا، ووضع أداة على الشاشة الرئيسية يزيد التفاعل مع التطبيق بنسبة 20–30%. بالنسبة لنظام Android، هذه الأرقام متقاربة. دعنا نستعرض كيفية عمل الأدوات على كلا النظامين مع أمثلة كود.
أهم النقاط
Widget هو عنصر واجهة مستخدم مصغر يوضع على الشاشة الرئيسية لجهاز محمول لعرض معلومات محدثة من تطبيق. على عكس التطبيق الكامل، لا تتطلب الأداة التشغيل — يرى المستخدم البيانات فور فتح الشاشة. المفهوم نشأ من أنظمة سطح المكتب (macOS Dashboard، Windows Sidebar)، وفي البيئة المحمولة، أضاف Android دعم الأدوات منذ إصداره الأول (Android 1.5 Cupcake، 2009)، بينما أضافتها Apple فقط في iOS 14.
التنفيذ التقني يختلف بين المنصات. أداة iOS هي target منفصل في Xcode، يتم تجميعه كـ Widget Extension، يعمل في عملية خاصة به. أداة Android هي BroadcastReceiver يمدد AppWidgetProvider، ويعرض التخطيط عبر RemoteViews. تفرض كلتا المنصتين قيودًا صارمة على الأداء والذاكرة: يمكن للنظام إزالة الأداة عند تجاوز الحدود. يحد iOS الأدوات بـ 30–50 MB ووقت إنشاء timeline بـ 10 ثوانٍ. Android — فترة تحديث لا تزيد عن 30 دقيقة عبر updatePeriodMillis وإنهاء إجباري إذا توقف onUpdate.
Smart Stack على iOS والأكوام على Android تسمح للمستخدم بتجميع عدة أدوات في فتحة واحدة على الشاشة الرئيسية. يبدل الجهاز تلقائيًا الأداة المعروضة حسب الوقت من اليوم أو الموقع أو نشاط المستخدم. على سبيل المثال، في الصباح يظهر التقويم، أثناء النهار — الطقس، في المساء — الملاحظات. بالنسبة للمطورين، هذا يعني أن الأداة يجب أن تعمل بشكل صحيح كجزء من كومة وألا تعتمد على العرض المستمر.
WidgetKit هو إطار عمل Apple لإنشاء الأدوات على iOS 14+ وiPadOS 14+ وmacOS 11+. تُكتب الأدوات بلغة Swift باستخدام SwiftUI وآلية TimelineProvider لتحديث المحتوى. تتضمن بنية WidgetKit ثلاثة مكونات: TimelineProvider — مصدر بيانات يشكل خطًا زمنيًا بإدخالات؛ Widget Entry View — عرض SwiftUI يعرض المحتوى بناءً على إدخال؛ Widget Configuration — وصف لنوع الأداة وأحجامها وعائلاتها.
يدير WidgetKit التحديثات تلقائيًا — لا يمكن للمطور فرض تحديث الأداة أكثر مما يسمح به النظام. تستخدم Apple ميزانية تحديث موزعة بين جميع الأدوات على الجهاز. الحد الأدنى للفاصل الزمني هو 15–30 دقيقة. للبيانات الحرجة (مثل حالة التسليم)، يُستخدم push-to-refresh — إرسال إشعار دفع بتاريخ مستقبلي ذي صلة، وبعد ذلك يطلب WidgetKit خطًا زمنيًا جديدًا. بدءًا من iOS 17، تدعم الأدوات التفاعل عبر App Intents — يمكن للمستخدم الضغط على أزرار داخل الأداة دون فتح التطبيق.
| الحجم | iOS (pt) | المحتوى |
|---|---|---|
| Small | 170 × 170 | 1–2 مؤشرات: درجة الحرارة، سعر العملة |
| Medium | 360 × 170 | 2–4 مؤشرات: توقعات 5 أيام، قائمة |
| Large | 360 × 380 | 5–10 مؤشرات: التقويم، تغذية الأخبار |
AppWidgetProvider هو الفئة الأساسية لإنشاء الأدوات على Android، وهي جزء من Android SDK منذ API level 3. أداة Android هي BroadcastReceiver تستقبل أحداث التحديث والتمكين والتعطيل من النظام. على عكس iOS، حيث يتم عرض الأداة باستخدام SwiftUI على محركها الخاص، يستخدم Android RemoteViews — مجموعة محدودة من مكونات View يتم عرضها في عملية النظام (launcher). لا يمكن استخدام Views مخصصة أو رسوم متحركة معقدة أو مكتبات واجهة مستخدم.
سير عمل أداة Android يتضمن أربع مراحل. التهيئة — عند إضافة الأداة إلى الشاشة، قد يقوم النظام بتشغيل Activity تهيئة حيث يختار المستخدم الإعدادات. التحديث — يستدعي النظام onUpdate() على فاصل زمني محدد (30 دقيقة كحد أدنى) أو بإشارة من التطبيق عبر WorkManager. العرض — ينشئ المزود RemoteViews بالبيانات الحالية ويمررها عبر AppWidgetManager. معالجة اللمس — تدعم الأداة PendingIntent للأزرار: يؤدي النقر إلى فتح Activity أو تنفيذ إجراء. بدءًا من Android 12، حصلت الأدوات على دعم الزوايا الدائرية والألوان المتكيفة Material You والتغيير الديناميكي للحجم.
لننشئ أداة طقس بلغة Swift باستخدام WidgetKit وSwiftUI. يجب أن يتضمن المشروع target Widget Extension، يُضاف في Xcode عبر File → New → Target → Widget Extension.
import WidgetKit
import SwiftUI
// 1. نموذج بيانات للأداة
struct WeatherEntry: TimelineEntry {
let date: Date
let temperature: Int
let condition: String
}
// 2. TimelineProvider — مزود البيانات
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> WeatherEntry {
WeatherEntry(date: Date(), temperature: 22, condition: "مشمس")
}
func getSnapshot(in context: Context, completion: @escaping (WeatherEntry) -> Void) {
let entry = WeatherEntry(date: Date(), temperature: 22, condition: "مشمس")
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<WeatherEntry>) -> Void) {
let now = Date()
let entry = WeatherEntry(date: now, temperature: 20, condition: "غائم")
let nextUpdate = Calendar.current.date(byAdding: .hour, value: 3, to: now)!
let timeline = Timeline(entries: [entry], policy: .after(nextUpdate))
completion(timeline)
}
}
// 3. عرض SwiftUI للعرض
struct WeatherWidgetEntryView: View {
var entry: WeatherEntry
var body: some View {
VStack(alignment: .leading) {
Text("الطقس").font(.caption).foregroundColor(.secondary)
HStack {
Text("\(entry.temperature)°").font(.largeTitle).fontWeight(.bold)
Spacer()
Text(entry.condition).font(.body)
}
}.padding()
}
}
// 4. تكوين الأداة
@main
struct WeatherWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(kind: "WeatherWidget", provider: Provider()) { entry in
WeatherWidgetEntryView(entry: entry)
}
.configurationDisplayName("الطقس")
.description("يعرض درجة الحرارة الحالية")
.supportedFamilies([.systemSmall, .systemMedium])
}
}
النقاط الرئيسية: TimelineProvider يحدد متى وأي البيانات يتم عرضها؛ getTimeline ينشئ خطًا زمنيًا بسياسة التحديث .after(nextUpdate)؛ StaticConfiguration يربط المزود بـ View. للبيانات الديناميكية، يُستخدم IntentConfiguration مع معلمات مخصصة.
لننفذ أداة طقس مماثلة بلغة Kotlin باستخدام AppWidgetProvider وRemoteViews.
// WeatherWidgetProvider.kt
class WeatherWidgetProvider : AppWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
for (appWidgetId in appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId)
}
}
override fun onAppWidgetOptionsChanged(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int,
newOptions: Bundle
) {
updateAppWidget(context, appWidgetManager, appWidgetId)
}
companion object {
fun updateAppWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int
) {
val temperature = 20
val condition = "غائم"
val views = RemoteViews(
context.packageName, R.layout.widget_weather
).apply {
setTextViewText(R.id.tv_temperature, "$temperature°")
setTextViewText(R.id.tv_condition, condition)
setOnClickPendingIntent(
R.id.widget_root, PendingIntent.getActivity(
context, 0,
Intent(context, MainActivity::class.java),
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
)
}
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
}
// AndroidManifest — تسجيل المزود
<receiver android:name=".WeatherWidgetProvider" android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_weather_info" />
</receiver>
يحدد ملف widget_weather_info.xml الأحجام الدنيا والفاصل الزمني والتخطيط: minWidth 160dp، minHeight 80dp، updatePeriodMillis 3600000 (ساعة واحدة). يستخدم RemoteViews فقط المكونات المدعومة: LinearLayout، TextView، ImageView. Views المخصصة وConstraintLayout متاحة منذ Android 5.0. GlanceLayout — نهج تجريبي قائم على Compose لـ RemoteViews — ظهر في Android 15.
الأسئلة الشائعة
يقدم iOS WidgetKit ثلاثة أحجام ثابتة (small، medium، large) وتحديثًا عبر TimelineProvider بميزانية النظام. Android AppWidgetProvider يستخدم أحجامًا مرنة قائمة على الخلايا، وRemoteViews للعرض، وتحديثًا عبر updatePeriodMillis أو WorkManager.
على iOS، يتحكم النظام في التحديثات — الحد الأدنى للفاصل الزمني 15–30 دقيقة، للبيانات الحرجة يُستخدم push-to-refresh. على Android، يُحدد الفاصل في updatePeriodMillis (30 دقيقة كحد أدنى) أو عبر WorkManager للمهام الخلفية.
يدعم iOS small (170x170pt)، medium (360x170pt)، وlarge (360x380pt). يستخدم Android شبكة خلايا مرنة: من 2x1 إلى 5x5، يعتمد الحجم على launcher وإصدار نظام التشغيل.
على iOS، الرسوم المتحركة داخل الأدوات غير متاحة — إنها عناصر ثابتة. Android RemoteViews يدعم الرسوم المتحركة الأساسية عبر setFloat() وViewPropertyAnimator، لكن الرسوم المتحركة المعقدة غير متاحة.
مع التنفيذ الصحيح — لا. يحد النظام بصرامة من موارد الأداة: على iOS — ميزانية التحديث والذاكرة (30–50 MB)، على Android — الحد الأدنى لفاصل التحديث. الأدوات التي تسبب مشاكل يتم إنهاؤها إجبارياً بواسطة النظام.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا