تعمل مكتبة Core-Telecom
على تبسيط عملية دمج تطبيق الاتصال
بنظام Android من خلال توفير مجموعة قوية ومتسقة
من واجهات برمجة التطبيقات.
إذا كنت تريد استكشاف عمليات التنفيذ العملية، يمكنك العثور على نماذج التطبيقات على GitHub:
- نموذج تطبيق خفيف الوزن: مثال بسيط
يوضّح استخدام واجهة برمجة التطبيقات
Core-Telecom
. مثالية لفهم أساسيات التسويق الرقمي بسرعة - نموذج تطبيق شامل (تم تطويره من قِبل فريق الاتصالات الأساسية): تطبيق يتضمّن ميزات أكثر ويعرض وظائف الاتصالات المتقدّمة وأفضل الممارسات. هذا مصدر رائع لفهم سيناريوهات الدمج المعقدة.
إعداد Core-Telecom
أضِف التبعية androidx.core:core-telecom
إلى ملف build.gradle
في تطبيقك:
dependencies {
implementation ("androidx.core:core-telecom:1.0.0")
}
أدرِج الإذن MANAGE_OWN_CALLS
في AndroidManifest.xml
:
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
تسجيل التطبيق
سجِّل تطبيق الاتصال على Android باستخدام CallsManager
لبدء إضافة
المكالمات إلى النظام. عند التسجيل، حدِّد إمكانات تطبيقك (مثل
إمكانية تشغيل الصوت والفيديو):
val callsManager = CallsManager(context)
val capabilities: @CallsManager.Companion.Capability Int =
(CallsManager.CAPABILITY_BASELINE or
CallsManager.CAPABILITY_SUPPORTS_VIDEO_CALLING)
callsManager.registerAppWithTelecom(capabilities)
إدارة المكالمات
استخدِم واجهات برمجة التطبيقات Core-Telecom لإنشاء دورة حياة المكالمات وإدارتها.
إنشاء مكالمة
يحدّد عنصر CallAttributesCompat
سمات مكالمة فريدة،
التي يمكن أن تتضمّن الخصائص التالية:
displayName
: اسم المتصلaddress
: عنوان الاتصال (على سبيل المثال، رقم الهاتف أو رابط الاجتماع)direction
: واردة أو صادرةcallType
: ملف صوتي أو فيديو-
callCapabilities
: تتيح هذه الميزة نقل البيانات والاحتفاظ بها.
في ما يلي مثال على كيفية إنشاء مكالمة واردة:
fun createIncomingCallAttributes(
callerName: String,
callerNumber: String,
isVideoCall: Boolean): CallAttributesCompat {
val addressUri = Uri.parse("YourAppScheme:$callerNumber")
// Define capabilities supported by your call.
val callCapabilities = CallAttributesCompat.CallCapability(
supportsSetInactive = CallAttributesCompat.SUPPORTS_SET_INACTIVE // Call can be made inactive (implies hold)
)
return CallAttributesCompat(
displayName = callerName,
address = addressUri,
direction = CallAttributesCompat.DIRECTION_INCOMING,
callType = if (isVideoCall) CallAttributesCompat.CALL_TYPE_VIDEO_CALL else CallAttributesCompat.CALL_TYPE_AUDIO_CALL,
callCapabilitiesCompat = callCapabilities
)
}
إضافة مكالمة
استخدِم callsManager.addCall
مع CallAttributesCompat
وطلبات إعادة الاتصال لإضافة
طلب جديد إلى النظام وإدارة تعديلات السطح عن بُعد. يسمح العنصر callControlScope
ضمن العنصر addCall
لتطبيقك في المقام الأول بتغيير حالة المكالمة
وتلقّي آخر المعلومات الصوتية:
try {
callsManager.addCall(
INCOMING_CALL_ATTRIBUTES,
onAnswerCall, // Watch needs to know if it can answer the call.
onSetCallDisconnected,
onSetCallActive,
onSetCallInactive
) {
// The call was successfully added once this scope runs.
callControlScope = this
}
}
catch(addCallException: Exception){
// Handle the addCall failure.
}
الرد على مكالمة
الرد على مكالمة واردة خلال CallControlScope
:
when (val result = answer(CallAttributesCompat.CALL_TYPE_AUDIO_CALL)) {
is CallControlResult.Success -> { /* Call answered */ }
is CallControlResult.Error -> { /* Handle error */ }
}
رفض مكالمة
رفض مكالمة باستخدام disconnect()
مع DisconnectCause.REJECTED
ضمن
CallControlScope
:
disconnect(DisconnectCause(DisconnectCause.REJECTED))
تنشيط مكالمة صادرة
اضبط المكالمة الصادرة على "نشطة" بعد أن يردّ الطرف البعيد:
when (val result = setActive()) {
is CallControlResult.Success -> { /* Call active */ }
is CallControlResult.Error -> { /* Handle error */ }
}
تعليق مكالمة
يمكنك استخدام setInactive()
لوضع مكالمة في انتظار:
when (val result = setInactive()) {
is CallControlResult.Success -> { /* Call on hold */ }
is CallControlResult.Error -> { /* Handle error */ }
}
إنهاء مكالمة
يمكنك إنهاء مكالمة باستخدام disconnect()
مع DisconnectCause
:
disconnect(DisconnectCause(DisconnectCause.LOCAL))
إدارة نقاط نهاية الصوت في المكالمات
مراقبة نقاط نهاية الصوت وإدارتها باستخدام currentCallEndpoint
availableEndpoints
وisMuted
Flow
ضمن CallControlScope
fun observeAudioStateChanges(callControlScope: CallControlScope) {
with(callControlScope) {
launch { currentCallEndpoint.collect { /* Update UI */ } }
launch { availableEndpoints.collect { /* Update UI */ } }
launch { isMuted.collect { /* Handle mute state */ } }
}
}
تغيير الجهاز الصوتي النشط باستخدام requestEndpointChange()
:
coroutineScope.launch {
callControlScope.requestEndpointChange(callEndpoint)
}
الدعم أثناء ظهور التطبيق على الشاشة
تستخدِم المكتبة ConnectionService
(المستوى 33 لواجهة برمجة التطبيقات في Android 13 والإصدارات الأقدم) أو
foregroundtypes (المستوى 34 لواجهة برمجة التطبيقات في Android 14 والإصدارات الأحدث) لتمكين
العرض في المقدّمة.
كجزء من متطلبات التشغيل في المقدّمة، يجب أن ينشر التطبيق إشعارًا ليتمكّن المستخدمون من معرفة أنّ التطبيق يعمل في المقدّمة.
لضمان حصول تطبيقك على الأولوية في التنفيذ في المقدّمة، أنشئ إعلامًا عند إضافة طلب الاتصال بالنظام الأساسي. تتم إزالة الأولوية في المقدّمة عندما ينهي تطبيقك المكالمة أو عندما يصبح الإشعار غير صالح.
مزيد من المعلومات عن الخدمات التي تعمل في المقدّمة
دعم Surface عن بُعد
يمكن للأجهزة البعيدة (الساعات الذكية وسماعات الرأس التي تعمل بالبلوتوث وAndroid Auto)
إدارة المكالمات بدون التفاعل المباشر مع الهاتف. يجب أن ينفذ تطبيقك دالات lambda لطلبات إعادة الاتصال (onAnswerCall
وonSetCallDisconnected
وonSetCallActive
onSetCallInactive
) المقدَّمة إلى CallsManager.addCall
لمعالجة الإجراءات التي تبدأها هذه الأجهزة.
عند حدوث إجراء عن بُعد، يتمّ استدعاء دالة lambda المقابلة.
يشير اكتمال دالة lambda بنجاح إلى أنّه تمت معالجة الأمر. إذا تعذّر تنفيذ الأمر، من المفترض أن تُلقي دالة lambda استثناءً.
يضمن التنفيذ السليم التحكّم السلس في المكالمات على مختلف الأجهزة. اختبِر التطبيق بدقة باستخدام مساحات عرض مختلفة عن بُعد.
إضافات المكالمات
بالإضافة إلى إدارة حالة المكالمات ومسار الصوت فيها، تتيح المكتبة أيضًا استخدام الإضافات الخاصة بالمكالمات، وهي ميزات اختيارية يمكن لتطبيقك تنفيذها للحصول على تجربة اتصال أكثر إثارة على مساحات العرض البعيدة، مثل Android Auto. وتشمل هذه الميزات غرف الاجتماعات وكتم صوت المكالمات ورموًز مكالمات إضافية. عندما ينفِّذ تطبيقك إضافة، تتم مزامنة المعلومات التي يقدّمها التطبيق مع جميع الأجهزة المتصلة التي تتيح أيضًا عرض هذه الإضافات في واجهة المستخدم. وهذا يعني أنّ هذه الميزات ستكون متاحة أيضًا على الأجهزة البعيدة ليتفاعل معها المستخدمون.
إنشاء مكالمة تتضمّن إضافات
عند إنشاء مكالمة، بدلاً من استخدام CallManager#addCall
لإنشاء المكالمة،
يمكنك بدلاً من ذلك استخدام CallManager#addCallWithExtensions، ما يمنح
التطبيق إذن الوصول إلى نطاق مختلف يُسمى ExtensionInitializationScope
. يسمح هذا
النطاق للتطبيق بإعداد مجموعة الإضافات الاختيارية التي
يستخدِمها. بالإضافة إلى ذلك، يوفّر هذا النطاق طريقة إضافية، وهي onCall
،
التي تقدّم CallControlScope
إلى التطبيق بعد اكتمال تبادل قدرات الإضافة
وبدء التشغيل.
scope.launch {
mCallsManager.addCallWithExtensions(
attributes,
onAnswer,
onDisconnect,
onSetActive,
onSetInactive
) {
// Initialize extension-specific code...
// After the call has been initialized, perform in-call actions
onCall {
// Example: process call state updates
callStateFlow.onEach { newState ->
// handle call state updates and notify telecom
}.launchIn(this)
// Use initialized extensions...
}
}
}
دعم المشاركين في المكالمة
إذا كان تطبيقك يتيح للمشاركين في المكالمات الانضمام إلى الاجتماعات أو المكالمات الجماعية، استخدِم
addParticipantExtension
للإشارة إلى توفّر هذه الإضافة
واستخدِم واجهات برمجة التطبيقات ذات الصلة لتعديل مساحات العرض البعيدة عند تغيير المشاركين.
mCallsManager.addCallWithExtensions(...) {
// Initialize extensions...
// Notifies Jetpack that this app supports the participant
// extension and provides the initial participants state in the call.
val participantExtension = addParticipantExtension(
initialParticipants,
initialActiveParticipant
)
// After the call has been initialized, perform in-call control actions
onCall {
// other in-call control and extension actions...
// Example: update remote surfaces when the call participants change
participantsFlow.onEach { newParticipants ->
participantExtension.updateParticipants(newParticipants)
}.launchIn(this)
}
}
بالإضافة إلى إرسال إشعارات إلى مساحات العرض البعيدة بالمشاركين في المكالمة،
يمكن أيضًا تعديل حالة المشارك النشط باستخدام
ParticipantExtension#updateActiveParticipant
.
تتوفّر أيضًا إجراءات اختيارية مرتبطة بمشاركي المكالمة.
يمكن للتطبيق استخدام ParticipantExtension#addRaiseHandSupport
للإشارة إلى أنّه تم رفع يد أحد المشاركين في المكالمة والاطّلاع على المشاركين الآخرين الذين رفعوا أيديهم أيضًا.
mCallsManager.addCallWithExtensions(...) {
// Initialize extensions...
// Notifies Jetpack that this app supports the participant
// extension and provides the initial list of participants in the call.
val participantExtension = addParticipantExtension(initialParticipants)
// Notifies Jetpack that this app supports the notion of participants
// being able to raise and lower their hands.
val raiseHandState = participantExtension.addRaiseHandSupport(
initialRaisedHands
) { onHandRaisedStateChanged ->
// handle this user's raised hand state changed updates from
// remote surfaces.
}
// After the call has been initialized, perform in-call control actions
onCall {
// other in-call control and extension actions...
// Example: update remote surfaces when the call participants change
participantsFlow.onEach { newParticipants ->
participantExtension.updateParticipants(newParticipants)
}.launchIn(this)
// notify remote surfaces of which of the participants have their
// hands raised
raisedHandsFlow.onEach { newRaisedHands ->
raiseHandState.updateRaisedHands(newRaisedHands)
}.launchIn(this)
}
}
إتاحة ميزة "كتم صوت المكالمة"
يتيح خيار كتم صوت المكالمات للمستخدم طلب كتم صوت مكالمة قيد الإجراء بدون كتم صوت الميكروفون في الجهاز. تتم إدارة هذه الميزة لكل مكالمة، لذا تتعامل Jetpack مع تعقيد إدارة حالة كتم الصوت العالمي للمكالمات الخلوية الجارية أثناء إجراء مكالمة عبر بروتوكول الإنترنت الصوتي (VOIP). ويؤدي ذلك إلى تقليل احتمال حدوث أخطاء عند كتم الصوت الصادر في سيناريوهات المكالمات المتعدّدة، كما يتيح أيضًا استخدام ميزات مفيدة، مثل مؤشرات "هل أنت تتحدّث؟" عندما يتحدّث العميل بدون أن يدرك أنّه تم تفعيل ميزة كتم الصوت في المكالمة.
mCallsManager.addCallWithExtensions(...) {
// Initialize extensions...
// Add support for locally silencing the call's outgoing audio and
// register a handler for when the user changes the call silence state
// from a remote surface.
val callSilenceExtension = addLocalCallSilenceExtension(
initialCallSilenceState = false
) { newCallSilenceStateRequest ->
// handle the user's request to enable/disable call silence from
// a remote surface
}
// After the call has been initialized, perform in-call control actions
onCall {
// other in-call control and extension actions...
// When the call's call silence state changes, update remote
// surfaces of the new state.
callSilenceState.onEach { isSilenced ->
callSilenceExtension.updateIsLocallySilenced(isSilenced)
}.launchIn(this)
}
}
رموز المكالمات مع فريق الدعم
يسمح رمز المكالمة للتطبيق بتحديد رمز مخصّص يمثّل المكالمة التي سيتم عرضها على مساحات العرض البعيدة أثناء المكالمة. يمكن أيضًا تعديل هذا الرمز على مدار مدة المكالمة.
mCallsManager.addCallWithExtensions(...) {
// Initialize extensions...
// Add support for a custom call icon to be displayed during the
// lifetime of the call.
val callIconExtension = addCallIconExtension(
initialCallIconUri = initialUri
)
// After the call has been initialized, perform in-call control actions
onCall {
// other in-call control and extension actions...
// When the call's icon changes, update remote surfaces by providing
// the new URI.
callIconUri.onEach { newIconUri ->
callIconExtension.updateCallIconUri(newIconUri)
}.launchIn(this)
}
}