إرسال المستخدم إلى تطبيق آخر

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

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

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

بناء هدف ضمني

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

ربط إجراءات النية بالشراء بالبيانات

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

إذا كانت بياناتك عبارة عن Uri، يمكنك استخدام دالة Intent() بسيطة لتعريف الإجراء والبيانات.

على سبيل المثال، إليك كيفية إنشاء هدف لبدء مكالمة هاتفية باستخدام بيانات Uri لتحديد رقم الهاتف:

Kotlin

val callIntent: Intent = Uri.parse("tel:5551234").let { number ->
    Intent(Intent.ACTION_DIAL, number)
}

Java

Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);

عندما يستدعي تطبيقك هذا الإجراء من خلال الاتصال برقم startActivity()، يبدأ تطبيق "الهاتف" مكالمة إلى رقم الهاتف المحدَّد.

في ما يلي هدفان آخران وإجراءاتهما وزوجَي بيانات Uri:

عرض خريطة

Kotlin

// Map point based on address
val mapIntent: Intent = Uri.parse(
        "geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California"
).let { location ->
    // Or map point based on latitude/longitude
    // val location: Uri = Uri.parse("geo:37.422219,-122.08364?z=14") // z param is zoom level
    Intent(Intent.ACTION_VIEW, location)
}

Java

// Map point based on address
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
// Or map point based on latitude/longitude
// Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);

الاطّلاع على صفحة ويب

Kotlin

val webIntent: Intent = Uri.parse("https://www.android.com").let { webpage ->
    Intent(Intent.ACTION_VIEW, webpage)
}

Java

Uri webpage = Uri.parse("https://www.android.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);

إضافة مزايا إضافية إلى هدف

تتطلب الأنواع الأخرى من الأغراض الضمنية بيانات "إضافية" توفر أنواع بيانات مختلفة، مثل السلسلة. يمكنك إضافة جزء واحد أو أكثر من البيانات الإضافية باستخدام طرق putExtra() المختلفة.

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

في ما يلي بعض الأغراض الأخرى التي تضيف بيانات إضافية لتحديد الإجراء المطلوب:

إرسال رسالة إلكترونية تحتوي على مرفق واحد

Kotlin

Intent(Intent.ACTION_SEND).apply {
    // The intent does not have a URI, so declare the "text/plain" MIME type
    type = "text/plain"
    putExtra(Intent.EXTRA_EMAIL, arrayOf("jan@example.com")) // recipients
    putExtra(Intent.EXTRA_SUBJECT, "Email subject")
    putExtra(Intent.EXTRA_TEXT, "Email message text")
    putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"))
    // You can also attach multiple items by passing an ArrayList of Uris
}

Java

Intent emailIntent = new Intent(Intent.ACTION_SEND);
// The intent does not have a URI, so declare the "text/plain" MIME type
emailIntent.setType(HTTP.PLAIN_TEXT_TYPE);
emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jan@example.com"}); // recipients
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject");
emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text");
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"));
// You can also attach multiple items by passing an ArrayList of Uris

إنشاء حدث في التقويم

ملاحظة: لا يتوفّر هذا الغرض لأي حدث في التقويم إلا مع المستوى 14 من واجهة برمجة التطبيقات والمستويات الأعلى.

Kotlin

// Event is on January 23, 2021 -- from 7:30 AM to 10:30 AM.
Intent(Intent.ACTION_INSERT, Events.CONTENT_URI).apply {
    val beginTime: Calendar = Calendar.getInstance().apply {
        set(2021, 0, 23, 7, 30)
    }
    val endTime = Calendar.getInstance().apply {
        set(2021, 0, 23, 10, 30)
    }
    putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.timeInMillis)
    putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.timeInMillis)
    putExtra(Events.TITLE, "Ninja class")
    putExtra(Events.EVENT_LOCATION, "Secret dojo")
}

Java

// Event is on January 23, 2021 -- from 7:30 AM to 10:30 AM.
Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI);
Calendar beginTime = Calendar.getInstance();
beginTime.set(2021, 0, 23, 7, 30);
Calendar endTime = Calendar.getInstance();
endTime.set(2021, 0, 23, 10, 30);
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis());
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis());
calendarIntent.putExtra(Events.TITLE, "Ninja class");
calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");

ملاحظة:من المهم تحديد Intent ليكون محددًا قدر الإمكان. على سبيل المثال، إذا كنت تريد عرض صورة باستخدام الغرض ACTION_VIEW، يجب تحديد نوع MIME لـ image/*. يمنع هذا التطبيقات التي يمكنها "عرض" أنواع أخرى من البيانات (مثل تطبيق الخرائط) من أن يتم تشغيلها بقصد.

بدء نشاط بقصد

بعد إنشاء Intent وإعداد المعلومات الإضافية، اتّصِل بـ startActivity() لإرسالها إلى النظام:

Kotlin

startActivity(intent)

Java

startActivity(intent);

التعامل مع الحالة التي لا يمكن فيها لأي تطبيق أن يتلقّى هدفًا

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

Kotlin

try {
    startActivity(intent)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

try {
    startActivity(intent);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

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

مربّع حوار التوضيح

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

تظهر لوحة
  بالقرب من أسفل الشاشة. وتسرد هذه اللوحة التطبيقات المختلفة التي يمكنها معالجة الغرض من ذلك.

الشكل 1. مثال لمربّع حوار الاختيار الذي يظهر عندما يمكن لأكثر من تطبيق واحد معالجة هدف معيّن.

مثال كامل

إليك مثال كامل يوضح كيفية إنشاء هدف لعرض خريطة، والتحقق من وجود تطبيق للتعامل مع الغرض، ثم بدء تشغيله:

Kotlin

// Build the intent.
val location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California")
val mapIntent = Intent(Intent.ACTION_VIEW, location)

// Try to invoke the intent.
try {
    startActivity(mapIntent)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

// Build the intent.
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);

// Try to invoke the intent.
try {
    startActivity(mapIntent);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

إظهار أداة اختيار التطبيقات

الشكل 2. مربّع حوار أداة الاختيار

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

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

لعرض أداة الاختيار، عليك إنشاء Intent باستخدام createChooser() وإرسالها إلى startActivity(). مثلاً:

Kotlin

val intent = Intent(Intent.ACTION_SEND)

// Create intent to show chooser
val chooser = Intent.createChooser(intent, /* title */ null)

// Try to invoke the intent.
try {
    startActivity(chooser)
} catch (e: ActivityNotFoundException) {
    // Define what your app should do if no activity can handle the intent.
}

Java

Intent intent = new Intent(Intent.ACTION_SEND);

// Create intent to show chooser
Intent chooser = Intent.createChooser(intent, /* title */ null);

// Try to invoke the intent.
try {
    startActivity(chooser);
} catch (ActivityNotFoundException e) {
    // Define what your app should do if no activity can handle the intent.
}

ويؤدي ذلك إلى عرض مربّع حوار يتضمّن قائمة بالتطبيقات التي تستجيب للقصد الذي تم تمريره إلى طريقة createChooser(). يمكن توفير المَعلمة title إذا لم يكن الإجراء ACTION_SEND أو ACTION_SEND_MULTIPLE