Camera API

يتضمّن إطار عمل Android إمكانية استخدام مختلف الكاميرات وميزات الكاميرا المتوفّرة على الأجهزة، ما يتيح لك التقاط الصور والفيديوهات في تطبيقاتك. يناقش هذا المستند طريقة سريعة وبسيطة لالتقاط الصور والفيديوهات، ويقدّم طريقة متقدّمة لإنشاء تجارب كاميرا مخصّصة للمستخدمين.

ملاحظة: توضّح هذه الصفحة الفئة Camera، التي تم إيقافها نهائيًا. ننصحك باستخدام مكتبة CameraX Jetpack أو الفئة camera2 في حالات استخدام معيّنة. تعمل كلّ من CameraX وCamera2 على الإصدار 5.0 (المستوى 21 من واجهة برمجة التطبيقات) والإصدارات الأحدث من نظام التشغيل Android.

يُرجى الاطّلاع على المراجع ذات الصلة التالية:

الاعتبارات

قبل تفعيل تطبيقك لاستخدام الكاميرات على أجهزة Android، عليك التفكير في بعض الأسئلة حول كيفية استخدام تطبيقك لهذه الميزة.

  • متطلبات الكاميرا: هل استخدام الكاميرا مهم جدًا لتطبيقك إلى الحد الذي لا تريد فيه أن يتم تثبيت تطبيقك على جهاز لا يتضمّن كاميرا؟ في هذه الحالة، عليك توضيح متطلبات الكاميرا في ملف البيان.
  • التقاط صورة سريعة أو استخدام كاميرا مخصّصة: كيف سيستخدم تطبيقك الكاميرا؟ هل أنت مهتم فقط بالتقاط صورة أو مقطع فيديو سريع، أم أنّ تطبيقك سيوفر طريقة جديدة لاستخدام الكاميرات؟ لالتقاط صورة أو مقطع فيديو سريع، ننصحك باستخدام تطبيقات الكاميرا الحالية. لتطوير ميزة كاميرا مخصّصة، اطّلِع على قسم إنشاء تطبيق كاميرا.
  • متطلبات الخدمات التي تعمل في المقدّمة - متى يتفاعل تطبيقك مع الكاميرا؟ في نظام التشغيل Android 9 (المستوى 28 لواجهة برمجة التطبيقات) والإصدارات الأحدث، لا يمكن للتطبيقات التي تعمل في الخلفية الوصول إلى الكاميرا. لذلك، يجب استخدام الكاميرا إما عندما يكون تطبيقك في المقدّمة أو كجزء من خدمة تعمل في المقدّمة.
  • مساحة التخزين - هل من المفترض أن تكون الصور أو الفيديوهات التي ينشئها تطبيقك مرئية فقط لتطبيقك أو تتم مشاركتها حتى تتمكن تطبيقات أخرى، مثل "معرض الصور" أو تطبيقات الوسائط والتواصل الاجتماعي الأخرى، من استخدامها؟ هل تريد أن تظل الصور والفيديوهات متاحة حتى إذا تم إلغاء تثبيت تطبيقك؟ راجِع قسم حفظ ملفات الوسائط للتعرّف على كيفية تنفيذ هذه الخيارات.

الأساسيات

يتيح إطار عمل Android التقاط الصور والفيديوهات من خلال واجهة برمجة التطبيقات android.hardware.camera2 أو الكاميرا Intent. في ما يلي الفئات ذات الصلة:

android.hardware.camera2
هذه الحزمة هي واجهة برمجة التطبيقات الأساسية للتحكّم في كاميرات الأجهزة. ويمكن استخدامها لالتقاط صور أو فيديوهات عند إنشاء تطبيق كاميرا.
Camera
هذه الفئة هي واجهة برمجة التطبيقات القديمة المتوقّفة نهائيًا للتحكّم في كاميرات الأجهزة.
SurfaceView
يتم استخدام هذه الفئة لعرض معاينة مباشرة للكاميرا للمستخدم.
MediaRecorder
يتم استخدام هذه الفئة لتسجيل فيديو من الكاميرا.
Intent
يمكن استخدام نوع إجراء الهدف MediaStore.ACTION_IMAGE_CAPTURE أو MediaStore.ACTION_VIDEO_CAPTURE لالتقاط الصور أو الفيديوهات بدون استخدام العنصر Camera مباشرةً.

بيانات ملف البيان

قبل بدء تطوير تطبيقك باستخدام Camera API، عليك التأكّد من أنّ بيانك يتضمّن التصريحات المناسبة للسماح باستخدام أجهزة الكاميرا والميزات الأخرى ذات الصلة.

  • إذن الوصول إلى الكاميرا: يجب أن يطلب تطبيقك الإذن باستخدام كاميرا الجهاز.
    <uses-permission android:name="android.permission.CAMERA" />

    ملاحظة: إذا كنت تستخدم الكاميرا من خلال استدعاء تطبيق كاميرا حالي، لن يحتاج تطبيقك إلى طلب هذا الإذن.

  • ميزات الكاميرا: يجب أن يوضّح تطبيقك أيضًا استخدام ميزات الكاميرا، على سبيل المثال:
    <uses-feature android:name="android.hardware.camera" />

    للاطّلاع على قائمة بميزات الكاميرا، يُرجى الرجوع إلى مرجع الميزات في ملف البيان.

    تؤدي إضافة ميزات الكاميرا إلى ملف البيان إلى منع Google Play تثبيت تطبيقك على الأجهزة التي لا تتضمّن كاميرا أو لا تتوافق مع ميزات الكاميرا التي تحدّدها. لمزيد من المعلومات حول استخدام الفلترة المستندة إلى الميزات مع Google Play، يُرجى الاطّلاع على مقالة Google Play والفلترة المستندة إلى الميزات.

    إذا كان تطبيقك يمكنه استخدام كاميرا أو ميزة كاميرا ليعمل بشكل سليم، ولكنّه لا يتطلّب ذلك، عليك تحديد ذلك في ملف البيان من خلال تضمين السمة android:required وضبطها على false:

    <uses-feature android:name="android.hardware.camera" android:required="false" />
  • إذن التخزين: يمكن لتطبيقك حفظ الصور أو الفيديوهات في وحدة التخزين الخارجية للجهاز (بطاقة SD) إذا كان يستهدف الإصدار Android 10 (المستوى 29 من واجهة برمجة التطبيقات) أو إصدارًا أقدم ويحدّد ما يلي في البيان.
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  • إذن تسجيل الصوت: لتسجيل الصوت أثناء التقاط الفيديو، يجب أن يطلب تطبيقك إذن تسجيل الصوت.
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
  • إذن تحديد الموقع الجغرافي: إذا كان تطبيقك يضع علامات على الصور تتضمّن معلومات الموقع الجغرافي حسب نظام تحديد المواقع العالمي (GPS)، عليك طلب الإذن ACCESS_FINE_LOCATION. يُرجى العِلم أنّه إذا كان تطبيقك يستهدف الإصدار 5.0 من نظام التشغيل Android (المستوى 21 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث، عليك أيضًا الإفصاح عن أنّ تطبيقك يستخدم نظام تحديد المواقع العالمي (GPS) في الجهاز:

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    ...
    <!-- Needed only if your app targets Android 5.0 (API level 21) or higher. -->
    <uses-feature android:name="android.hardware.location.gps" />

    لمزيد من المعلومات حول الحصول على الموقع الجغرافي للمستخدم، يُرجى الاطّلاع على استراتيجيات تحديد الموقع الجغرافي.

استخدام تطبيقات الكاميرا الحالية

تتمثّل إحدى الطرق السريعة لتفعيل التقاط الصور أو الفيديوهات في تطبيقك بدون الحاجة إلى الكثير من الرموز البرمجية الإضافية في استخدام Intent لاستدعاء أحد تطبيقات الكاميرا الحالية على Android. يمكنك الاطّلاع على التفاصيل في درسَي التدريب التقاط الصور بسهولة و تسجيل الفيديوهات بسهولة.

إنشاء تطبيق كاميرا

قد يحتاج بعض المطوّرين إلى واجهة مستخدم للكاميرا مخصّصة لتناسب شكل تطبيقاتهم أو توفّر ميزات خاصة. يمكن أن يؤدي كتابة رمز التقاط الصور الخاص بك إلى توفير تجربة أكثر جاذبية للمستخدمين.

ملاحظة: الدليل التالي مخصّص لواجهة برمجة التطبيقات القديمة التي تم إيقافها نهائيًا Camera. بالنسبة إلى تطبيقات الكاميرا الجديدة أو المتقدّمة، يُنصح باستخدام android.hardware.camera2 واجهة برمجة التطبيقات الأحدث.

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

  • الرصد والوصول إلى الكاميرا: إنشاء رمز للتحقّق من توفّر الكاميرات وطلب الوصول إليها
  • إنشاء فئة معاينة: أنشئ فئة معاينة للكاميرا توسّع SurfaceView وتنفّذ واجهة SurfaceHolder. تعرض هذه الفئة معاينة للصور المباشرة من الكاميرا.
  • إنشاء تخطيط معاينة: بعد الحصول على فئة معاينة الكاميرا، أنشئ تخطيط عرض يتضمّن المعاينة وعناصر التحكّم في واجهة المستخدم التي تريدها.
  • إعداد أدوات معالجة الأحداث لعملية الالتقاط: يمكنك ربط أدوات معالجة الأحداث بعناصر التحكّم في واجهتك لبدء عملية التقاط الصور أو الفيديوهات استجابةً لإجراءات المستخدم، مثل الضغط على زر.
  • التقاط الصور والفيديوهات وحفظها: يمكنك إعداد الرمز البرمجي لالتقاط الصور أو الفيديوهات وحفظ الناتج.
  • إيقاف استخدام الكاميرا: بعد استخدام الكاميرا، يجب أن يوقف تطبيقك استخدامها بشكل صحيح لكي تتمكّن التطبيقات الأخرى من استخدامها.

أجهزة الكاميرا هي موارد مشترَكة يجب إدارتها بعناية حتى لا يتعارض تطبيقك مع التطبيقات الأخرى التي قد تريد استخدامها أيضًا. تتناول الأقسام التالية كيفية رصد أجهزة الكاميرا وكيفية طلب إذن الوصول إلى الكاميرا وكيفية التقاط الصور أو الفيديو وكيفية إيقاف الكاميرا عندما ينتهي تطبيقك من استخدامها.

تنبيه: تذكَّر تحرير الكائن Camera من خلال استدعاء Camera.release() عند انتهاء تطبيقك من استخدامه. إذا لم يحرر تطبيقك الكاميرا بشكل صحيح، ستفشل جميع محاولات الوصول إلى الكاميرا اللاحقة، بما في ذلك تلك التي يجريها تطبيقك، وقد يؤدي ذلك إلى إغلاق تطبيقك أو تطبيقات أخرى.

اكتشاف أجهزة الكاميرا

إذا كان تطبيقك لا يتطلّب استخدام كاميرا بشكل محدّد من خلال بيان في ملف البيان، عليك التحقّق مما إذا كانت الكاميرا متاحة أثناء التشغيل. لإجراء عملية التحقّق هذه، استخدِم طريقة PackageManager.hasSystemFeature()، كما هو موضّح في مثال الرمز البرمجي أدناه:

Kotlin

/** Check if this device has a camera */
private fun checkCameraHardware(context: Context): Boolean {
    if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
        // this device has a camera
        return true
    } else {
        // no camera on this device
        return false
    }
}

Java

/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
    if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
        // this device has a camera
        return true;
    } else {
        // no camera on this device
        return false;
    }
}

يمكن أن تتضمّن أجهزة Android كاميرات متعددة، مثل كاميرا خلفية للتصوير وكاميرا أمامية لمكالمات الفيديو. يتيح لك الإصدار 2.3 من نظام التشغيل Android (المستوى 9 من واجهة برمجة التطبيقات) والإصدارات الأحدث التحقّق من عدد الكاميرات المتوفّرة على الجهاز باستخدام الطريقة Camera.getNumberOfCameras().

الوصول إلى الكاميرات

إذا تبيّن لك أنّ الجهاز الذي يتم تشغيل تطبيقك عليه يتضمّن كاميرا، عليك طلب الوصول إليها من خلال الحصول على مثيل من Camera (إلا إذا كنت تستخدم Intent للوصول إلى الكاميرا).

للوصول إلى الكاميرا الأساسية، استخدِم طريقة Camera.open() وتأكَّد من رصد أي استثناءات، كما هو موضّح في الرمز البرمجي أدناه:

Kotlin

/** A safe way to get an instance of the Camera object. */
fun getCameraInstance(): Camera? {
    return try {
        Camera.open() // attempt to get a Camera instance
    } catch (e: Exception) {
        // Camera is not available (in use or does not exist)
        null // returns null if camera is unavailable
    }
}

Java

/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(){
    Camera c = null;
    try {
        c = Camera.open(); // attempt to get a Camera instance
    }
    catch (Exception e){
        // Camera is not available (in use or does not exist)
    }
    return c; // returns null if camera is unavailable
}

تنبيه: تحقَّق دائمًا من الاستثناءات عند استخدام Camera.open(). سيؤدي عدم التحقّق من الاستثناءات في حال كانت الكاميرا قيد الاستخدام أو غير متوفّرة إلى إيقاف النظام لتطبيقك.

على الأجهزة التي تعمل بالإصدار 2.3 من نظام التشغيل Android (المستوى 9 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث، يمكنك الوصول إلى كاميرات معيّنة باستخدام Camera.open(int). سيصل رمز المثال أعلاه إلى الكاميرا الأولى الخلفية على جهاز يحتوي على أكثر من كاميرا واحدة.

التحقّق من ميزات الكاميرا

بعد الحصول على إذن الوصول إلى الكاميرا، يمكنك الحصول على مزيد من المعلومات حول إمكاناتها باستخدام طريقة Camera.getParameters() والتحقّق من عنصر Camera.Parameters الذي تم عرضه لمعرفة الإمكانات المتوافقة. عند استخدام المستوى 9 من واجهة برمجة التطبيقات أو مستوى أعلى، استخدِم Camera.getCameraInfo() لتحديد ما إذا كانت الكاميرا في مقدّمة الجهاز أو خلفه، وتحديد اتجاه الصورة.

إنشاء فئة معاينة

لكي يتمكّن المستخدمون من التقاط الصور أو تسجيل الفيديوهات بفعالية، يجب أن يتمكّنوا من رؤية ما تراه كاميرا الجهاز. فئة معاينة الكاميرا هي SurfaceView يمكنها عرض بيانات الصورة المباشرة الواردة من الكاميرا، ما يتيح للمستخدمين تأطير صورة أو فيديو والتقاطهما.

يوضّح نموذج الرمز البرمجي التالي كيفية إنشاء فئة معاينة أساسية للكاميرا يمكن تضمينها في تخطيط View. تنفِّذ هذه الفئة SurfaceHolder.Callback من أجل تسجيل أحداث معاودة الاتصال لإنشاء العرض وتدميره، وهي الأحداث اللازمة لتعيين إدخال معاينة الكاميرا.

Kotlin

/** A basic Camera preview class */
class CameraPreview(
        context: Context,
        private val mCamera: Camera
) : SurfaceView(context), SurfaceHolder.Callback {

    private val mHolder: SurfaceHolder = holder.apply {
        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        addCallback(this@CameraPreview)
        // deprecated setting, but required on Android versions prior to 3.0
        setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS)
    }

    override fun surfaceCreated(holder: SurfaceHolder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        mCamera.apply {
            try {
                setPreviewDisplay(holder)
                startPreview()
            } catch (e: IOException) {
                Log.d(TAG, "Error setting camera preview: ${e.message}")
            }
        }
    }

    override fun surfaceDestroyed(holder: SurfaceHolder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.
        if (mHolder.surface == null) {
            // preview surface does not exist
            return
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview()
        } catch (e: Exception) {
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        mCamera.apply {
            try {
                setPreviewDisplay(mHolder)
                startPreview()
            } catch (e: Exception) {
                Log.d(TAG, "Error starting camera preview: ${e.message}")
            }
        }
    }
}

Java

/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder mHolder;
    private Camera mCamera;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        mCamera = camera;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        if (mHolder.getSurface() == null){
          // preview surface does not exist
          return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
          // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

        } catch (Exception e){
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }
}

إذا أردت ضبط حجم معيّن لمعاينة الكاميرا، يمكنك ضبط ذلك في طريقة surfaceChanged() كما هو موضّح في التعليقات أعلاه. عند ضبط حجم المعاينة، يجب استخدام قيم من getSupportedPreviewSizes(). لا تضبط قيمًا عشوائية في طريقة setPreviewSize().

ملاحظة: مع طرح ميزة النوافذ المتعددة في الإصدار 7.0 من نظام التشغيل Android (المستوى 24 من واجهة برمجة التطبيقات) والإصدارات الأحدث، لم يعُد بإمكانك افتراض أنّ نسبة العرض إلى الارتفاع للمعاينة هي نفسها نسبة العرض إلى الارتفاع للنشاط حتى بعد استدعاء setDisplayOrientation(). استنادًا إلى حجم النافذة ونسبة العرض إلى الارتفاع، قد تحتاج إلى ملاءمة معاينة الكاميرا العريضة مع تخطيط عمودي، أو العكس، باستخدام تخطيط letterbox.

وضع المعاينة في تخطيط

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

يوفر رمز التنسيق التالي عرضًا أساسيًا جدًا يمكن استخدامه لعرض معاينة الكاميرا. في هذا المثال، من المفترض أن يكون العنصر FrameLayout هو الحاوية لفئة معاينة الكاميرا. يتم استخدام نوع التنسيق هذا حتى يمكن عرض معلومات أو عناصر تحكّم إضافية في الصور المعروضة في معاينة الكاميرا المباشرة.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
  <FrameLayout
    android:id="@+id/camera_preview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1"
    />

  <Button
    android:id="@+id/button_capture"
    android:text="Capture"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    />
</LinearLayout>

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

<activity android:name=".CameraActivity"
          android:label="@string/app_name"

          android:screenOrientation="landscape">
          <!-- configure this activity to use landscape orientation -->

          <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

ملاحظة: ليس من الضروري أن تكون معاينة الكاميرا في الوضع الأفقي. بدءًا من الإصدار 2.2 من نظام التشغيل Android (المستوى 8 من واجهة برمجة التطبيقات)، يمكنك استخدام طريقة