أساسيات أندرويد بجافا

ملف AndroidManifest

18 دقيقة الدرس 6 من 12

ملف AndroidManifest

لكل تطبيق Android ملف واحد بالضبط يُسمى AndroidManifest.xml، يقع في جذر كل وحدة (module). يدمج نظام بناء Android ملفات manifest لجميع الوحدات في ملف manifest نهائي واحد قبل تحزيم ملف APK. عند وقت التشغيل، يقرأ نظام Android هذا الملف قبل تشغيل سطر واحد من كود Java الخاص بك. إذا لم يُعلَن عن مكوّن هنا، فلن يستطيع النظام تشغيله. وإذا لم تُدرج صلاحية هنا، فسيرفضها نظام التشغيل. فكّر في ملف manifest على أنه العقد بين تطبيقك ومنصة Android.

العنصر الجذري واسم الحزمة

العنصر الجذري للملف هو <manifest>. أهم سماته هي package، التي تُعدّ المعرّف الفريد لتطبيقك على الجهاز وفي متجر Play. وفقًا للاتفاقية تعكس حزمة Java الخاصة بك، مثلًا com.example.myapp.

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.taskmanager"> <!-- إعلانات الصلاحيات، كتلة التطبيق، ... --> </manifest>
package مقابل applicationId: في بنيات Gradle الحديثة، قيمة applicationId في ملف build.gradle هي ما ينتهي فعليًا في APK وفي متجر Play. إذا اختلفا، تُقدَّم قيمة Gradle. احرص على إبقائهما متزامنَين تجنبًا للإرباك.

الإعلان عن مكوّنات التطبيق

يجب الإعلان عن كل مكوّن يُقدّمه تطبيقك — الأنشطة (Activities) والخدمات (Services) ومستقبلات البث (Broadcast Receivers) ومزوّدي المحتوى (Content Providers) — داخل عنصر <application>. سيفشل النظام بصمت في تشغيل أي مكوّن غير مُعلَن.

الأنشطة (Activities)

يُسجّل عنصر <activity> شاشة واحدة. تحمل السمة android:name اسم الفئة الكامل؛ يمكنك استخدام نقطة بادئة كاختصار لبادئة اسم الحزمة.

<application android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:exported="true" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".DetailActivity" android:exported="false" android:parentActivityName=".MainActivity" /> </application>

يُشكّل عنصر <intent-filter> في MainActivity مع الإجراء MAIN والفئة LAUNCHER ما يضع أيقونة تطبيقك في مشغّل الشاشة الرئيسية. يجب أن يمتلك التطبيق فلترًا واحدًا بالضبط من هذا النوع. سمة android:exported إلزامية على API 31 وما فوق وتتحكم في ما إذا كانت التطبيقات الأخرى يمكنها تشغيل هذا النشاط مباشرةً.

تُوصّل سمة android:parentActivityName في DetailActivity زرّ أعلى في شريط الإجراءات تلقائيًا — دون الحاجة لأي كود Java للتنقل الأساسي.

الخدمات (Services)

يُعلن عنصر <service> عن مكوّن خلفي. ضع android:exported="false" ما لم يكن يجب على تطبيقات أخرى الارتباط به.

<service android:name=".SyncService" android:exported="false" />

مستقبلات البث (Broadcast Receivers)

تُشغَّل المستقبلات الثابتة (المُعلَنة في الملف manifest) حتى عندما لا يعمل التطبيق. انتبه أن Android 8.0 والإصدارات الأحدث تُقيّد عمليات البث الضمنية التي يمكن استقبالها بهذه الطريقة؛ يجب تسجيل معظم المستقبلات في وقت التشغيل باستخدام registerReceiver() عوضًا عن ذلك.

<receiver android:name=".BootReceiver" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver>

مزوّدو المحتوى (Content Providers)

<provider android:name=".TaskProvider" android:authorities="com.example.taskmanager.provider" android:exported="false" />

يجب أن تكون سلسلة android:authorities فريدة عالميًا عبر جميع التطبيقات على الجهاز، لذا استخدام اسم حزمتك كبادئة أمر إلزامي.

الإعلان عن الصلاحيات

يُطبّق Android نموذج صلاحيات من خطوتين. أولًا، تُعلن في الملف manifest الصلاحيات التي قد يستخدمها تطبيقك. ثانيًا، للصلاحيات الخطرة (تلك التي تمسّ بيانات المستخدم الحساسة أو أجهزة الجهاز)، يجب أيضًا طلبها في وقت التشغيل في كود Java باستخدام ActivityCompat.requestPermissions().

الصلاحيات العادية

تُمنح الصلاحيات العادية تلقائيًا وقت التثبيت. تشمل أشياء مثل الوصول إلى الشبكة أو تشغيل الاهتزاز — إجراءات منخفضة المخاطر.

<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

الصلاحيات الخطرة

تتطلب الصلاحيات الخطرة موجّه وقت التشغيل. ومع ذلك، يجب تسجيلها في الملف manifest أيضًا — بدون إعلان الملف manifest سيُرفض طلب وقت التشغيل دائمًا، بغض النظر عن كود Java الذي تكتبه.

<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />

تُخبر سمة android:maxSdkVersion في READ_EXTERNAL_STORAGE النظامَ بالتوقف عن تطبيقها فوق API 32، لأن Android 13 قدّم صلاحيات وسائط دقيقة (READ_MEDIA_IMAGES وما شابهها) تحلّ محلّها.

الإعلان عن صلاحيات مخصصة

إذا كشف تطبيقك عن مكوّن يجب أن يصله شركاء موثوقون فقط، عرّف صلاحية مخصصة وطبّقها على ذلك المكوّن:

<!-- تعريف الصلاحية المخصصة --> <permission android:name="com.example.taskmanager.permission.READ_TASKS" android:protectionLevel="signature" /> <!-- حماية المزوّد بها --> <provider android:name=".TaskProvider" android:authorities="com.example.taskmanager.provider" android:exported="true" android:readPermission="com.example.taskmanager.permission.READ_TASKS" />

يعني protectionLevel="signature" أن التطبيقات الموقّعة بنفس مفتاح المطوّر فقط يمكن منحها هذه الصلاحية — أقوى بكثير من normal أو dangerous.

متطلبات الأجهزة والميزات

استخدم <uses-feature> للإعلان عن أن تطبيقك يتطلب أجهزة محددة. يستخدم متجر Play هذا لتصفية الأجهزة غير المتوافقة.

<uses-feature android:name="android.hardware.camera" android:required="true" /> <uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />

تعيين android:required="false" يعني أن تطبيقك يمكنه العمل بدون الميزة لكنه سيستخدمها إذا توفّرت — يجب عندها التحقق في وقت التشغيل باستخدام PackageManager.hasSystemFeature().

الصلاحية لا تعني اشتراط الميزة. يُضيف الإعلان عن صلاحية CAMERA ضمنيًا اشتراط ميزة الكاميرا. إذا كان تطبيقك يستخدم الكاميرا كميزة اختيارية، أضف صراحةً <uses-feature android:name="android.hardware.camera" android:required="false" /> لمنع متجر Play من تصفية الأجهزة التي لا تحتوي على كاميرا.

الصورة الكاملة: الجمع معًا

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.taskmanager"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" android:required="false" /> <application android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/Theme.TaskManager" android:allowBackup="true" android:supportsRtl="true"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".TaskDetailActivity" android:exported="false" android:parentActivityName=".MainActivity" /> <service android:name=".SyncService" android:exported="false" /> </application> </manifest>
حافظ على الملف manifest نظيفًا. كل صلاحية تطلبها مرئية للمستخدم وخاضعة لمراجعة سياسة متجر Play. لا تُعلن إلا عن الصلاحيات التي تستخدمها فعلًا. الصلاحيات غير المستخدمة تزيد من انعدام ثقة المستخدم وقد تُسبّب رفضات متجر Play. احذف الصلاحيات عند إعادة هيكلة الكود الذي لم يعد يحتاجها.

الخلاصة

يُعدّ AndroidManifest.xml العقد على مستوى نظام التشغيل لتطبيقك. أعلن عن كل Activity وService وBroadcastReceiver وContentProvider داخل <application> — المكوّنات غير المُعلَنة ببساطة لا وجود لها بالنسبة للنظام. أدرج كل صلاحية يستدعيها كودك تحت <uses-permission>؛ الصلاحيات الخطرة تحتاج إضافةً إلى طلب وقت التشغيل في Java. استخدم <uses-feature> للتحكم في تصفية أجهزة متجر Play. مع ملف manifest جيد الصياغة في متناولك، أنت جاهز لتوصيل الـ Intents وبناء تدفقات متعددة الشاشات في الدرس القادم.