Xamarin.iOS'ta CallKit

iOS 10'daki yeni CallKit API'si, VOIP uygulamalarının iPhone arabirimiyle tümleştirip son kullanıcıya tanıdık bir arabirim ve deneyim sağlamasını sağlar. Bu API ile kullanıcılar iOS cihazın Kilit Ekranından VOIP çağrılarını görüntüleyip etkileşimde bulunarak, Telefon sık kullanılanlar ve Son kullanılanlar görünümlerini kullanarak kişileri yönetebilir.

CallKit hakkında

Apple'a göre CallKit, 3. taraf IP üzerinden Ses (VOIP) uygulamalarını iOS 10'da 1. taraf deneyimine yükseltecek yeni bir çerçevedir. CallKit API'si, VOIP uygulamalarının iPhone arabirimiyle tümleştirilmelerini ve son kullanıcıya tanıdık bir arabirim ve deneyim sağlamalarını sağlar. Yerleşik Telefon uygulamasında olduğu gibi, bir kullanıcı iOS cihazın Kilit Ekranından VOIP çağrılarını görüntüleyip etkileşimde bulunarak Telefon uygulamasının Sık Kullanılanlar ve Son Kullanılanlar görünümlerini kullanarak kişileri yönetebilir.

Buna ek olarak, CallKit API'si bir telefon numarasını bir adla (Arayan Kimliği) ilişkilendirilen veya bir numaranın ne zaman engellenmesi gerektiğini (Çağrı Engellemesi) sisteme anlatan Uygulama Uzantıları oluşturma olanağı sağlar.

Mevcut VOIP uygulaması deneyimi

Yeni CallKit API'sini ve becerilerini tartışmadan önce, iOS 9'da 3. taraf VOIP uygulamasıyla (ve daha küçüktür) Ve daha küçük bir kullanıcı deneyimine göz atarak, MaymunCall adlı kurgusal BIR VOIP uygulamasını kullanın. MaymunCall, kullanıcının mevcut iOS API'lerini kullanarak VOIP çağrıları göndermesini ve almalarını sağlayan basit bir uygulamadır.

Şu anda kullanıcı, MaymunCall'ta gelen bir çağrı alıyorsa ve kullanıcının iPhone kilitliyse, Kilit ekranında alınan bildirim diğer bildirim türlerinden (örneğin İletiler veya Posta uygulamaları gibi) ayırt edilemez.

Kullanıcı çağrıyı yanıtlamak isterse, çağrıyı kabul etmek ve konuşmayı başlatmak için önce uygulamayı açmak ve geçiş kodunu (veya kullanıcı Touch ID'sini) girmek için MaymunCall bildirimini kaydırarak telefonu açması gerekir.

Telefon kilidi açıksa deneyim de aynı derecede zahmetli olur. Yine gelen MaymunCall çağrısı, ekranın üst kısmından gelen standart bir bildirim başlığı olarak görüntülenir. Bildirim geçici olduğu için, kullanıcı Tarafından Notification Center'ı açmaya zorlayarak ve yanıtlamak için belirli bir bildirimi bulup Ardından, MaymunCall uygulamasını el ile çağırarak veya bulup başlatmaya zorlayarak kolayca gözden kaçabilir.

CallKit VOIP uygulama deneyimi

Yeni CallKit API'lerini MaymunCall uygulamasında uygulayan kullanıcının gelen VOIP çağrısı deneyimi, iOS 10'da büyük ölçüde geliştirilebilirsiniz. Telefonu yukarıdan kilitlenirken VOIP çağrısı alan kullanıcının örneğini örnek olarak alalım. CallKit uygulanarak çağrı, tam ekran, yerel kullanıcı arabirimi ve standart yanıt verme işleviyle yerleşik Telefon uygulamasından alınan çağrı gibi iPhone'nin Kilit ekranında görünür.

Tekrarlamak gerekirse, bir MaymunCall VOIP çağrısı geldiğinde iPhone'nin kilidi açılırsa, yerleşik Telefon uygulamasının aynı tam ekran, yerel kullanıcı arabirimi ve standart çekme-cevap ve dokunma-reddetme işlevleri gösterilir ve MaymunCall özel bir ses çalma seçeneğine sahip olur.

CallKit, MaymunCall'a ek işlevsellik sağlar ve VOIP çağrılarının diğer çağrı türleriyle etkileşim kurmasına, yerleşik Son kullanılanlar ve Sık Kullanılanlar listelerinde görünmesine, yerleşik Rahatsız Etmeyin ve Engelleme özelliklerini kullanmasına olanak sağlar, Siri'den MaymunCall çağrılarını başlatarak kullanıcıların Kişiler uygulamasındaki kullanıcılara MaymunCall çağrıları atamasına olanak sağlar.

Aşağıdaki bölümler CallKit mimarisini, gelen ve giden çağrı akışlarını ve CallKit API'sini ayrıntılı olarak ele almaktadır.

CallKit mimarisi

iOS 10'da Apple, CarPlay'de yapılan çağrıların CallKit aracılığıyla Sistem kullanıcı arabirimi tarafından bilindiği gibi tüm Sistem Hizmetlerde CallKit'i benimsedi. Aşağıdaki örnekte, MaymunCall CallKit'i benimsediği için Sistem tarafından bu yerleşik System Services ile aynı şekilde bilinir ve tüm aynı özellikleri alır:

CallKit Hizmet Yığını

Yukarıdaki diyagramda Yer alan MaymunCall Uygulamasına daha yakından bakın. Uygulama kendi ağıyla iletişim kurmak için tüm kodunu içerir ve kendi Kullanıcı Arabirimlerini içerir. Sistemle iletişim kurmak için CallKit'te bağlantı kurar:

MaymunCall Uygulama Mimarisi

CallKit'te uygulamanın kullandığı iki ana arabirim vardır:

  • CXProvider - Bu, MaymunCall uygulamasının sisteme meydana gelen bant dışı bildirimleri bildirmesi için izin verir.
  • CXCallController - MaymunCall uygulamasının sisteme yerel kullanıcı eylemlerini bildirmesi için izin verir.

The CXProvider

Yukarıda belirtildiği gibi, bir uygulamanın sisteme meydana gelen bant dışı CXProvider bildirimleri bildirmesi için izin verir. Bunlar, yerel kullanıcı eylemleri nedeniyle meydana gelen ancak gelen çağrılar gibi dış olaylar nedeniyle oluşan bildirimdir.

Bir uygulama, aşağıdakiler CXProvider için kullandır:

  • Sisteme gelen çağrıyı bildirme.
  • Giden çağrının Sisteme bağlı olduğunu bildirme.
  • Uzak kullanıcının Çağrıyı Sistem'e sonlandırarak bildirme.

Uygulama sistemle iletişim kurmak istiyorsa sınıfını kullanır ve Sistem'in uygulamayla iletişim CXCallUpdate kurması gerekirken sınıfını CXAction kullanır:

CXProvider aracılığıyla sistemle iletişim kurma

The CXCallController

, CXCallController bir uygulamanın voIP çağrısı başlatan kullanıcı gibi yerel kullanıcı eylemlerini sisteme bildirmesine olanak sağlar. Uygulamanın CXCallController uygulanması, sistemde diğer çağrı türleriyle etkileşime geçen bir uygulamadır. Örneğin, devam eden etkin bir telefon çağrısı zaten varsa, VOIP uygulamasının bu çağrıyı basılı tutmasına ve bir VOIP çağrısı başlatmasına veya CXCallController yanıtlamasına izin verir.

Bir uygulama, aşağıdakiler CXCallController için kullandır:

  • Kullanıcının Sisteme giden çağrıyı ne zaman başlatt olduğunu raporla.
  • Kullanıcı Sisteme gelen bir çağrıyı yanıtlana kadar raporla.
  • Kullanıcı Sistem çağrısının sona erdiğinde raporla.

Uygulama, yerel kullanıcı eylemlerini sisteme iletirken sınıfını CXTransaction kullanır:

CXCallController kullanarak sisteme raporlama

CallKit Uygulama

Aşağıdaki bölümlerde bir Xamarin.iOS VOIP uygulamasında CallKit'in nasıl uygulanıp uygulanmayacakları liste ve açıklama gelecektir. Örneğin, bu belge kurgusal MaymunCall VOIP uygulamasından kod kullanıyor olacaktır. Burada sunulan kod çeşitli destekleyen sınıfları temsil eder, CallKit'e özgü bölümler aşağıdaki bölümlerde ayrıntılı olarak ele arilmektedir.

ActiveCall sınıfı

sınıfı, Şu anda etkin olan bir VOIP çağrısıyla ilgili tüm bilgileri tutmak için Aşağıdaki gibi ActiveCall MaymunCall uygulaması tarafından kullanılır:

using System;
using CoreFoundation;
using Foundation;

namespace MonkeyCall
{
    public class ActiveCall
    {
        #region Private Variables
        private bool isConnecting;
        private bool isConnected;
        private bool isOnhold;
        #endregion

        #region Computed Properties
        public NSUuid UUID { get; set; }
        public bool isOutgoing { get; set; }
        public string Handle { get; set; }
        public DateTime StartedConnectingOn { get; set;}
        public DateTime ConnectedOn { get; set;}
        public DateTime EndedOn { get; set; }

        public bool IsConnecting {
            get { return isConnecting; }
            set {
                isConnecting = value;
                if (isConnecting) StartedConnectingOn = DateTime.Now;
                RaiseStartingConnectionChanged ();
            }
        }

        public bool IsConnected {
            get { return isConnected; }
            set {
                isConnected = value;
                if (isConnected) {
                    ConnectedOn = DateTime.Now;
                } else {
                    EndedOn = DateTime.Now;
                }
                RaiseConnectedChanged ();
            }
        }

        public bool IsOnHold {
            get { return isOnhold; }
            set {
                isOnhold = value;
            }
        }
        #endregion

        #region Constructors
        public ActiveCall ()
        {
        }

        public ActiveCall (NSUuid uuid, string handle, bool outgoing)
        {
            // Initialize
            this.UUID = uuid;
            this.Handle = handle;
            this.isOutgoing = outgoing;
        }
        #endregion

        #region Public Methods
        public void StartCall (ActiveCallbackDelegate completionHandler)
        {
            // Simulate the call starting successfully
            completionHandler (true);

            // Simulate making a starting and completing a connection
            DispatchQueue.MainQueue.DispatchAfter (new DispatchTime(DispatchTime.Now, 3000), () => {
                // Note that the call is starting
                IsConnecting = true;

                // Simulate pause before connecting
                DispatchQueue.MainQueue.DispatchAfter (new DispatchTime (DispatchTime.Now, 1500), () => {
                    // Note that the call has connected
                    IsConnecting = false;
                    IsConnected = true;
                });
            });
        }

        public void AnswerCall (ActiveCallbackDelegate completionHandler)
        {
            // Simulate the call being answered
            IsConnected = true;
            completionHandler (true);
        }

        public void EndCall (ActiveCallbackDelegate completionHandler)
        {
            // Simulate the call ending
            IsConnected = false;
            completionHandler (true);
        }
        #endregion

        #region Events
        public delegate void ActiveCallbackDelegate (bool successful);
        public delegate void ActiveCallStateChangedDelegate (ActiveCall call);

        public event ActiveCallStateChangedDelegate StartingConnectionChanged;
        internal void RaiseStartingConnectionChanged ()
        {
            if (this.StartingConnectionChanged != null) this.StartingConnectionChanged (this);
        }

        public event ActiveCallStateChangedDelegate ConnectedChanged;
        internal void RaiseConnectedChanged ()
        {
            if (this.ConnectedChanged != null) this.ConnectedChanged (this);
        }
        #endregion
    }
}

ActiveCall , çağrının durumunu tanımlayan çeşitli özellikleri ve çağrı durumu değiştiklerde ortaya çıkarilebilecek iki olay içerir. Bu yalnızca bir örnek olduğu için çağrıyı başlatma, yanıtlama ve sonlandırma simülasyonu yapmak için kullanılan üç yöntem vardır.

StartCallRequest sınıfı

statik StartCallRequest sınıfı, giden çağrılarla çalışırken kullanılacak birkaç yardımcı yöntem sağlar:

using System;
using Foundation;
using Intents;

namespace MonkeyCall
{
    public static class StartCallRequest
    {
        public static string URLScheme {
            get { return "monkeycall"; }
        }

        public static string ActivityType {
            get { return INIntentIdentifier.StartAudioCall.GetConstant ().ToString (); }
        }

        public static string CallHandleFromURL (NSUrl url)
        {
            // Is this a MonkeyCall handle?
            if (url.Scheme == URLScheme) {
                // Yes, return host
                return url.Host;
            } else {
                // Not handled
                return null;
            }
        }

        public static string CallHandleFromActivity (NSUserActivity activity)
        {
            // Is this a start call activity?
            if (activity.ActivityType == ActivityType) {
                // Yes, trap any errors
                try {
                    // Get first contact
                    var interaction = activity.GetInteraction ();
                    var startAudioCallIntent = interaction.Intent as INStartAudioCallIntent;
                    var contact = startAudioCallIntent.Contacts [0];

                    // Get the person handle
                    return contact.PersonHandle.Value;
                } catch {
                    // Error, report null
                    return null;
                }
            } else {
                // Not handled
                return null;
            }
        }
    }
}

ve sınıfları, giden çağrıda çağrılan kişinin kişi tanıtıcısını almak CallHandleFromURLCallHandleFromActivity için AppDelegate içinde kullanılır. Daha fazla bilgi için lütfen aşağıdaki Giden Çağrıları İşleme bölümüne bakın.

ActiveCallManager sınıfı

sınıfı, ActiveCallManager MaymunCall uygulamasındaki tüm açık çağrıları işler.

using System;
using System.Collections.Generic;
using Foundation;
using CallKit;

namespace MonkeyCall
{
    public class ActiveCallManager
    {
        #region Private Variables
        private CXCallController CallController = new CXCallController ();
        #endregion

        #region Computed Properties
        public List<ActiveCall> Calls { get; set; }
        #endregion

        #region Constructors
        public ActiveCallManager ()
        {
            // Initialize
            this.Calls = new List<ActiveCall> ();
        }
        #endregion

        #region Private Methods
        private void SendTransactionRequest (CXTransaction transaction)
        {
            // Send request to call controller
            CallController.RequestTransaction (transaction, (error) => {
                // Was there an error?
                if (error == null) {
                    // No, report success
                    Console.WriteLine ("Transaction request sent successfully.");
                } else {
                    // Yes, report error
                    Console.WriteLine ("Error requesting transaction: {0}", error);
                }
            });
        }
        #endregion

        #region Public Methods
        public ActiveCall FindCall (NSUuid uuid)
        {
            // Scan for requested call
            foreach (ActiveCall call in Calls) {
                if (call.UUID.Equals(uuid)) return call;
            }

            // Not found
            return null;
        }

        public void StartCall (string contact)
        {
            // Build call action
            var handle = new CXHandle (CXHandleType.Generic, contact);
            var startCallAction = new CXStartCallAction (new NSUuid (), handle);

            // Create transaction
            var transaction = new CXTransaction (startCallAction);

            // Inform system of call request
            SendTransactionRequest (transaction);
        }

        public void EndCall (ActiveCall call)
        {
            // Build action
            var endCallAction = new CXEndCallAction (call.UUID);

            // Create transaction
            var transaction = new CXTransaction (endCallAction);

            // Inform system of call request
            SendTransactionRequest (transaction);
        }

        public void PlaceCallOnHold (ActiveCall call)
        {
            // Build action
            var holdCallAction = new CXSetHeldCallAction (call.UUID, true);

            // Create transaction
            var transaction = new CXTransaction (holdCallAction);

            // Inform system of call request
            SendTransactionRequest (transaction);
        }

        public void RemoveCallFromOnHold (ActiveCall call)
        {
            // Build action
            var holdCallAction = new CXSetHeldCallAction (call.UUID, false);

            // Create transaction
            var transaction = new CXTransaction (holdCallAction);

            // Inform system of call request
            SendTransactionRequest (transaction);
        }
        #endregion
    }
}

Yine, bu yalnızca bir benzetim olduğu için yalnızca bir nesne koleksiyonunu bulundurmaktadır ve özelliğine göre verilen bir çağrıyı bulma ActiveCallManagerActiveCallUUID yordamına sahiptir. Ayrıca giden çağrının başlatma, bitiş ve tutma durumunu değiştirme yöntemlerini de içerir. Daha fazla bilgi için lütfen aşağıdaki Giden Çağrıları İşleme bölümüne bakın.

ProviderDelegate sınıfı

Yukarıda da belirtildiği gibi, bant dışı bildirimler için uygulama CXProvider ile Sistem arasında çift yol iletişim sağlar. Geliştiricinin bir özel değer sağlaması ve bant dışında CallKit olaylarını CXProviderDelegateCXProvider işlemesi için uygulamaya eklemesi gerekir. MaymunCall aşağıdakini CXProviderDelegate kullanır:

using System;
using Foundation;
using CallKit;
using UIKit;

namespace MonkeyCall
{
    public class ProviderDelegate : CXProviderDelegate
    {
        #region Computed Properties
        public ActiveCallManager CallManager { get; set;}
        public CXProviderConfiguration Configuration { get; set; }
        public CXProvider Provider { get; set; }
        #endregion

        #region Constructors
        public ProviderDelegate (ActiveCallManager callManager)
        {
            // Save connection to call manager
            CallManager = callManager;

            // Define handle types
            var handleTypes = new [] { (NSNumber)(int)CXHandleType.PhoneNumber };

            // Get Image Template
            var templateImage = UIImage.FromFile ("telephone_receiver.png");

            // Setup the initial configurations
            Configuration = new CXProviderConfiguration ("MonkeyCall") {
                MaximumCallsPerCallGroup = 1,
                SupportedHandleTypes = new NSSet<NSNumber> (handleTypes),
                IconTemplateImageData = templateImage.AsPNG(),
                RingtoneSound = "musicloop01.wav"
            };

            // Create a new provider
            Provider = new CXProvider (Configuration);

            // Attach this delegate
            Provider.SetDelegate (this, null);

        }
        #endregion

        #region Override Methods
        public override void DidReset (CXProvider provider)
        {
            // Remove all calls
            CallManager.Calls.Clear ();
        }

        public override void PerformStartCallAction (CXProvider provider, CXStartCallAction action)
        {
            // Create new call record
            var activeCall = new ActiveCall (action.CallUuid, action.CallHandle.Value, true);

            // Monitor state changes
            activeCall.StartingConnectionChanged += (call) => {
                if (call.isConnecting) {
                    // Inform system that the call is starting
                    Provider.ReportConnectingOutgoingCall (call.UUID, call.StartedConnectingOn.ToNSDate());
                }
            };

            activeCall.ConnectedChanged += (call) => {
                if (call.isConnected) {
                    // Inform system that the call has connected
                    provider.ReportConnectedOutgoingCall (call.UUID, call.ConnectedOn.ToNSDate ());
                }
            };

            // Start call
            activeCall.StartCall ((successful) => {
                // Was the call able to be started?
                if (successful) {
                    // Yes, inform the system
                    action.Fulfill ();

                    // Add call to manager
                    CallManager.Calls.Add (activeCall);
                } else {
                    // No, inform system
                    action.Fail ();
                }
            });
        }

        public override void PerformAnswerCallAction (CXProvider provider, CXAnswerCallAction action)
        {
            // Find requested call
            var call = CallManager.FindCall (action.CallUuid);

            // Found?
            if (call == null) {
                // No, inform system and exit
                action.Fail ();
                return;
            }

            // Attempt to answer call
            call.AnswerCall ((successful) => {
                // Was the call successfully answered?
                if (successful) {
                    // Yes, inform system
                    action.Fulfill ();
                } else {
                    // No, inform system
                    action.Fail ();
                }
            });
        }

        public override void PerformEndCallAction (CXProvider provider, CXEndCallAction action)
        {
            // Find requested call
            var call = CallManager.FindCall (action.CallUuid);

            // Found?
            if (call == null) {
                // No, inform system and exit
                action.Fail ();
                return;
            }

            // Attempt to answer call
            call.EndCall ((successful) => {
                // Was the call successfully answered?
                if (successful) {
                    // Remove call from manager's queue
                    CallManager.Calls.Remove (call);

                    // Yes, inform system
                    action.Fulfill ();
                } else {
                    // No, inform system
                    action.Fail ();
                }
            });
        }

        public override void PerformSetHeldCallAction (CXProvider provider, CXSetHeldCallAction action)
        {
            // Find requested call
            var call = CallManager.FindCall (action.CallUuid);

            // Found?
            if (call == null) {
                // No, inform system and exit
                action.Fail ();
                return;
            }

            // Update hold status
            call.isOnHold = action.OnHold;

            // Inform system of success
            action.Fulfill ();
        }

        public override void TimedOutPerformingAction (CXProvider provider, CXAction action)
        {
            // Inform user that the action has timed out
        }

        public override void DidActivateAudioSession (CXProvider provider, AVFoundation.AVAudioSession audioSession)
        {
            // Start the calls audio session here
        }

        public override void DidDeactivateAudioSession (CXProvider provider, AVFoundation.AVAudioSession audioSession)
        {
            // End the calls audio session and restart any non-call
            // related audio
        }
        #endregion

        #region Public Methods
        public void ReportIncomingCall (NSUuid uuid, string handle)
        {
            // Create update to describe the incoming call and caller
            var update = new CXCallUpdate ();
            update.RemoteHandle = new CXHandle (CXHandleType.Generic, handle);

            // Report incoming call to system
            Provider.ReportNewIncomingCall (uuid, update, (error) => {
                // Was the call accepted
                if (error == null) {
                    // Yes, report to call manager
                    CallManager.Calls.Add (new ActiveCall (uuid, handle, false));
                } else {
                    // Report error to user here
                    Console.WriteLine ("Error: {0}", error);
                }
            });
        }
        #endregion
    }
}

Bu temsilcinin bir örneği oluşturulduğunda, herhangi bir çağrı ActiveCallManager etkinliğini işlemek için kullanabileceği örneği geçirildi. Ardından, tarafından yanıt verilen tanıtıcı türlerini ( CXHandleType ) CXProvider tanımlar:

// Define handle types
var handleTypes = new [] { (NSNumber)(int)CXHandleType.PhoneNumber };

Ayrıca, bir çağrı devam eden uygulamanın simgesine uygulanacak şablon görüntüsünü alır:

// Get Image Template
var templateImage = UIImage.FromFile ("telephone_receiver.png");

Bu değerler, yapılandırmak için CXProviderConfiguration kullanılacak bir içinde paket haline gelecektir: CXProvider

// Setup the initial configurations
Configuration = new CXProviderConfiguration ("MonkeyCall") {
    MaximumCallsPerCallGroup = 1,
    SupportedHandleTypes = new NSSet<NSNumber> (handleTypes),
    IconTemplateImageData = templateImage.AsPNG(),
    RingtoneSound = "musicloop01.wav"
};

Temsilci daha sonra bu CXProvider yapılandırmalarla yeni bir oluşturur ve kendisini buna iliştirer:

// Create a new provider
Provider = new CXProvider (Configuration);

// Attach this delegate
Provider.SetDelegate (this, null);

CallKit kullanılırken uygulama artık kendi ses oturumlarını oluşturmaz ve işlemez, bunun yerine Sistem tarafından oluşturulacak ve işlen bir ses oturumu yapılandıracak ve kullanmayacak.

Bu gerçek bir uygulama olsaydı, sistem tarafından sağlanan önceden yapılandırılmış bir çağrıyı başlatmak DidActivateAudioSessionAVAudioSession için yöntemi kullanılır:

public override void DidActivateAudioSession (CXProvider provider, AVFoundation.AVAudioSession audioSession)
{
    // Start the call's audio session here...
}

Ayrıca yöntemini kullanarak Sistem tarafından sağlanan ses oturumuna bağlantısını son olarak serbest DidDeactivateAudioSession bırakabilirsiniz:

public override void DidDeactivateAudioSession (CXProvider provider, AVFoundation.AVAudioSession audioSession)
{
    // End the calls audio session and restart any non-call
    // releated audio
}

Kodun geri kalanı, aşağıdaki bölümlerde ayrıntılı olarak ele alır.

AppDelegate sınıfı

MaymunCall, AppDelegate'i kullanarak uygulamanın her ActiveCallManager yerinde kullanılacak ve örneklerini CXProviderDelegate tutar:

using Foundation;
using UIKit;
using Intents;
using System;

namespace MonkeyCall
{
    [Register ("AppDelegate")]
    public class AppDelegate : UIApplicationDelegate
    {
        #region Constructors
        public override UIWindow Window { get; set; }
        public ActiveCallManager CallManager { get; set; }
        public ProviderDelegate CallProviderDelegate { get; set; }
        #endregion

        #region Override Methods
        public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
        {
            // Initialize the call handlers
            CallManager = new ActiveCallManager ();
            CallProviderDelegate = new ProviderDelegate (CallManager);

            return true;
        }

        public override bool OpenUrl (UIApplication app, NSUrl url, NSDictionary options)
        {
            // Get handle from url
            var handle = StartCallRequest.CallHandleFromURL (url);

            // Found?
            if (handle == null) {
                // No, report to system
                Console.WriteLine ("Unable to get call handle from URL: {0}", url);
                return false;
            } else {
                // Yes, start call and inform system
                CallManager.StartCall (handle);
                return true;
            }
        }

        public override bool ContinueUserActivity (UIApplication application, NSUserActivity userActivity, UIApplicationRestorationHandler completionHandler)
        {
            var handle = StartCallRequest.CallHandleFromActivity (userActivity);

            // Found?
            if (handle == null) {
                // No, report to system
                Console.WriteLine ("Unable to get call handle from User Activity: {0}", userActivity);
                return false;
            } else {
                // Yes, start call and inform system
                CallManager.StartCall (handle);
                return true;
            }
        }

        ...
        #endregion
    }
}

Ve OpenUrlContinueUserActivity geçersiz kılma yöntemleri, uygulama bir giden çağrıyı işlerken kullanılır. Daha fazla bilgi için lütfen aşağıdaki Giden Çağrıları İşleme bölümüne bakın.

Gelen çağrıları işleme

Gelen BIR VOIP çağrısının tipik bir gelen çağrı iş akışı sırasında geçenin çeşitli durumları ve işlemleri vardır, örneğin:

  • Kullanıcıya (ve Sisteme) gelen bir çağrının var olduğunu bildirme.
  • Kullanıcı çağrıyı yanıtlamak ve çağrıyı diğer kullanıcıyla başlatmayı isterse bildirim alma.
  • Kullanıcı geçerli çağrıyı sona ererken Sistemi ve İletişim Ağına bildirme.

Aşağıdaki bölümlerde, örnek olarak yine MaymunCall VOIP uygulamasını kullanarak bir uygulamanın gelen çağrı iş akışını işlemek için CallKit'i nasıl kullanabileceğine ilişkin ayrıntılı bir bakış yer alır.

Kullanıcıya gelen çağrıyı bildirme

Uzak bir kullanıcı yerel kullanıcıyla BIR VOIP görüşmesi başlattı mı, aşağıdakiler gerçekleşir:

Uzak bir kullanıcı VOIP konuşma başlattı

  1. Uygulama, İletişim Ağı'dan gelen bir VOIP çağrısı olduğunu bildirer.
  2. Uygulama, çağrısı CXProvider hakkında bilgi için CXCallUpdate Sistem'e bir göndermek için kullanır.
  3. Sistem, CallKit kullanarak çağrıyı Sistem kullanıcı arabirimine, Sistem Hizmetleri'ne ve diğer VOIP uygulamalarına yayımlar.

Örneğin, CXProviderDelegate içinde:

public void ReportIncomingCall (NSUuid uuid, string handle)
{
    // Create update to describe the incoming call and caller
    var update = new CXCallUpdate ();
    update.RemoteHandle = new CXHandle (CXHandleType.Generic, handle);

    // Report incoming call to system
    Provider.ReportNewIncomingCall (uuid, update, (error) => {
        // Was the call accepted
        if (error == null) {
            // Yes, report to call manager
            CallManager.Calls.Add (new ActiveCall (uuid, handle, false));
        } else {
            // Report error to user here
            Console.WriteLine ("Error: {0}", error);
        }
    });
}

Bu kod yeni bir CXCallUpdate örnek oluşturur ve çağıranı tanımacak tanıtıcıyı buna iliştirer. Ardından, çağrı ReportNewIncomingCall sistemini bilgilendirmek CXProvider için sınıfının yöntemini kullanır. Başarılı olursa, çağrı uygulamanın etkin çağrı koleksiyonuna eklenir, eklenmezse, hatanın kullanıcıya bildiriliyor olması gerekir.

Gelen çağrıyı yanıtlayan kullanıcı

Kullanıcı gelen VOIP çağrısını yanıtlamak istiyorsa aşağıdakiler gerçekleşir:

Kullanıcı gelen VOIP çağrısını yanıtlar

  1. Sistem kullanıcı arabirimi, sisteme kullanıcının VOIP çağrısını yanıtlamak istediğini bildirmektedir.
  2. Sistem, CXAnswerCallAction uygulamanın yanıt amacı hakkında CXProvider bilgi vermek için uygulamaya bir gönderir.
  3. Uygulama, İletişim Ağına kullanıcının çağrıyı yanıtlayarak VOIP çağrısının her zamanki gibi ilerler olduğunu bildirer.

Örneğin, CXProviderDelegate içinde:

public override void PerformAnswerCallAction (CXProvider provider, CXAnswerCallAction action)
{
    // Find requested call
    var call = CallManager.FindCall (action.CallUuid);

    // Found?
    if (call == null) {
        // No, inform system and exit
        action.Fail ();
        return;
    }

    // Attempt to answer call
    call.AnswerCall ((successful) => {
        // Was the call successfully answered?
        if (successful) {
            // Yes, inform system
            action.Fulfill ();
        } else {
            // No, inform system
            action.Fail ();
        }
    });
}

Bu kod önce etkin çağrı listesinde verilen çağrıyı arar. Çağrı bulunamazsa sistem bilgili olur ve yöntemden çıkar. Bulunursa, çağrıyı başlatmak için sınıfının yöntemi çağrılır ve başarılı veya başarısız olursa AnswerCallActiveCall Sistem bilgidir.

Gelen çağrıyı sonlandıran kullanıcı

Kullanıcı çağrıyı uygulamanın kullanıcı arabiriminden sonlandırmak isterse, aşağıdakiler gerçekleşir:

Kullanıcı, çağrıyı uygulamanın kullanıcı arabiriminden sonlandırılır

  1. Uygulama, CXEndCallAction çağrının sona eriyor olduğunu CXTransaction bildirmek için Sisteme gönderilen bir içinde paket haline gelen bir oluşturur.
  2. Sistem, Çağrı Amacını Doğrular ve aracılığıyla CXEndCallAction uygulamayı uygulamaya geri CXProvider gönderir.
  3. Uygulama daha sonra İletişim Ağına çağrının sona eriyor olduğunu bildirer.

Örneğin, CXProviderDelegate içinde:

public override void PerformEndCallAction (CXProvider provider, CXEndCallAction action)
{
    // Find requested call
    var call = CallManager.FindCall (action.CallUuid);

    // Found?
    if (call == null) {
        // No, inform system and exit
        action.Fail ();
        return;
    }

    // Attempt to answer call
    call.EndCall ((successful) => {
        // Was the call successfully answered?
        if (successful) {
            // Remove call from manager's queue
            CallManager.Calls.Remove (call);

            // Yes, inform system
            action.Fulfill ();
        } else {
            // No, inform system
            action.Fail ();
        }
    });
}

Bu kod önce etkin çağrı listesinde verilen çağrıyı arar. Çağrı bulunamazsa sistem bilgili olur ve yöntemden çıkar. Bulunursa, çağrıyı sona ertk için sınıfının yöntemi çağrılır ve başarılı veya başarısız olursa Sistem EndCallActiveCall bilgidir. Başarılı olursa, çağrı etkin çağrı koleksiyonundan kaldırılır.

Birden çok çağrıyı yönetme

Çoğu VOIP uygulaması aynı anda birden çok çağrıyı işebilir. Örneğin, şu anda etkin bir VOIP çağrısı varsa ve uygulama yeni bir gelen çağrı olduğunu bildirse, kullanıcı ikinci çağrıyı yanıtlamak için ilk çağrıda duraklatabilir veya kapatabilir.

Yukarıdaki durumda Sistem, birden çok eylemin (ve gibi) listesini içerecek CXTransaction uygulamaya bir CXEndCallActionCXAnswerCallAction gönderir. Sistemin kullanıcı arabirimini uygun şekilde güncelleştirene kadar tüm bu eylemlerin tek tek yerine getirilmesi gerekir.

Giden çağrıları işleme

Kullanıcı Son Bulunanlar listesinden (Telefon uygulamasında) bir girişe dokunsa (örneğin, uygulamaya ait bir çağrıdan gelen) sistem tarafından Bir Başlatma Çağrısı Amacı gönderilir:

Başlangıç Çağrısı Amacı Alma

  1. Uygulama, Sistemden aldığı Başlatma Çağrısı Amacını temel alan bir Başlatma Çağrısı Eylemi oluşturacak.
  2. Uygulama, sistemden CXCallController ÇağrıYı Başlat Eylemlerini talep etmek için kullanır.
  3. Sistem Eylemi kabul ederse, temsilci aracılığıyla uygulamaya XCProvider döndürülür.
  4. Uygulama giden çağrıyı İletişim Ağı ile başlatır.

Intents (Amaç) hakkında daha fazla bilgi için lütfen Intents and Intents UI Extensions (Amaç ve Amaç Kullanıcı Arabirimi Uzantıları) belgelerimize bakın.

Giden çağrı yaşam döngüsü

CallKit ve giden çağrı ile çalışırken, uygulamanın Sistem'e aşağıdaki yaşam döngüsü olaylarını bildirmesi gerekir:

  1. Başlangıç - Sisteme giden çağrının başlamak üzere olduğunu bildirin.
  2. Başlatıldı - Sisteme giden çağrının başlat olduğunu bildirme.
  3. Bağlanma - Sisteme giden çağrının bağlanıyor olduğunu bildirin.
  4. Bağlandı - Giden çağrının bağlandı ve her iki taraf da şimdi konuşasın.

Örneğin, aşağıdaki kod bir giden çağrı başlatacak:

private CXCallController CallController = new CXCallController ();
...

private void SendTransactionRequest (CXTransaction transaction)
{
    // Send request to call controller
    CallController.RequestTransaction (transaction, (error) => {
        // Was there an error?
        if (error == null) {
            // No, report success
            Console.WriteLine ("Transaction request sent successfully.");
        } else {
            // Yes, report error
            Console.WriteLine ("Error requesting transaction: {0}", error);
        }
    });
}

public void StartCall (string contact)
{
    // Build call action
    var handle = new CXHandle (CXHandleType.Generic, contact);
    var startCallAction = new CXStartCallAction (new NSUuid (), handle);

    // Create transaction
    var transaction = new CXTransaction (startCallAction);

    // Inform system of call request
    SendTransactionRequest (transaction);
}

bir oluşturur ve sınıf yöntemi kullanılarak Sisteme gönderilen bir içinde paketlenmiş bir CXHandleCXStartCallAction yapılandırmak için CXTransactionRequestTransactionCXCallController kullanır. Sistem, yöntemini çağırarak, kaynak RequestTransaction (Telefon app, FaceTime, VOIP vb.) fark etmez, mevcut çağrıları yeni çağrı başlamadan önce basılı tutabilir.

Giden VOIP çağrısı başlatma isteği Siri, Kişi kartında bir giriş (Kişiler uygulamasında) veya Son Çıkanlar listesinden (Telefon uygulamasında) gibi birkaç farklı kaynaktan gelebilir. Bu durumlarda, uygulamanın içinde bir Başlangıç Çağrısı Amacı gönderilir ve NSUserActivity AppDelegate'in bunu işlemesi gerekir:

public override bool ContinueUserActivity (UIApplication application, NSUserActivity userActivity, UIApplicationRestorationHandler completionHandler)
{
    var handle = StartCallRequest.CallHandleFromActivity (userActivity);

    // Found?
    if (handle == null) {
        // No, report to system
        Console.WriteLine ("Unable to get call handle from User Activity: {0}", userActivity);
        return false;
    } else {
        // Yes, start call and inform system
        CallManager.StartCall (handle);
        return true;
    }
}

Burada yardımcı sınıfının yöntemi çağrılan kişiye tanıtıcıyı almak için kullanılır CallHandleFromActivityStartCallRequest (yukarıdaki CallHandleFromActivity bakın).

PerformStartCallActionPerformStartCallAction olarak gerçek giden çağrıyı başlatmak ve Sistem'e yaşam döngüsünü bildirmek için kullanılır:

public override void PerformStartCallAction (CXProvider provider, CXStartCallAction action)
{
    // Create new call record
    var activeCall = new ActiveCall (action.CallUuid, action.CallHandle.Value, true);

    // Monitor state changes
    activeCall.StartingConnectionChanged += (call) => {
        if (call.IsConnecting) {
            // Inform system that the call is starting
            Provider.ReportConnectingOutgoingCall (call.UUID, call.StartedConnectingOn.ToNSDate());
        }
    };

    activeCall.ConnectedChanged += (call) => {
        if (call.IsConnected) {
            // Inform system that the call has connected
            Provider.ReportConnectedOutgoingCall (call.UUID, call.ConnectedOn.ToNSDate ());
        }
    };

    // Start call
    activeCall.StartCall ((successful) => {
        // Was the call able to be started?
        if (successful) {
            // Yes, inform the system
            action.Fulfill ();

            // Add call to manager
            CallManager.Calls.Add (activeCall);
        } else {
            // No, inform system
            action.Fail ();
        }
    });
}

Sınıfının bir örneğini oluşturur (devam eden çağrıyla ilgili bilgileri tutmak için) ve ActiveCall çağrıyı yapılan kişi ile doldurmak için. ve StartingConnectionChangedConnectedChanged olayları, giden çağrı yaşam döngüsünü izlemek ve rapor etmek için kullanılır. Çağrı başlatıldı ve Sistem Eylemin karşılandı olduğunu bildirdi.

Giden çağrıyı sonlandırma

Kullanıcı bir giden çağrıyı tamamlasa ve sona erer isterse, aşağıdaki kod kullanılabilir:

private CXCallController CallController = new CXCallController ();
...

private void SendTransactionRequest (CXTransaction transaction)
{
    // Send request to call controller
    CallController.RequestTransaction (transaction, (error) => {
        // Was there an error?
        if (error == null) {
            // No, report success
            Console.WriteLine ("Transaction request sent successfully.");
        } else {
            // Yes, report error
            Console.WriteLine ("Error requesting transaction: {0}", error);
        }
    });
}

public void EndCall (ActiveCall call)
{
    // Build action
    var endCallAction = new CXEndCallAction (call.UUID);

    // Create transaction
    var transaction = new CXTransaction (endCallAction);

    // Inform system of call request
    SendTransactionRequest (transaction);
}

Bitiş çağrısının UUID'sinde bir oluşturursa, sınıfın yöntemi kullanılarak Sisteme gönderilen bir CXEndCallActionCXTransaction içinde RequestTransactionCXCallController paketler.

Ek CallKit ayrıntıları

Bu bölümde, geliştiricinin CallKit ile çalışırken göz önünde bulundurulması gereken bazı ek ayrıntılar yer alır, örneğin:

  • Sağlayıcı Yapılandırması
  • Eylem Hataları
  • Sistem Kısıtlamaları
  • VOIP Ses

Sağlayıcı yapılandırması

Sağlayıcı yapılandırması, iOS 10 VOIP uygulamasının CallKit ile çalışırken kullanıcı deneyimini özelleştirmesi (yerel In-Call kullanıcı arabirimi içinde) sağlar.

Bir uygulama aşağıdaki özelleştirme türlerini gerçekleştirebilirsiniz:

  • Yerelleştirilmiş bir ad görüntüler.
  • Video çağrısı desteğini etkinleştirin.
  • Kendi şablon görüntüsünü In-Call kullanıcı arabirimi üzerindeki düğmeleri özelleştirin. Özel düğmelerle kullanıcı etkileşimi doğrudan işlenecek uygulamaya gönderilir.

Eylem hataları

CallKit kullanan iOS 10 VOIP uygulamalarının, başarısız olan eylemleri doğru şekilde işlemesi ve kullanıcıya her zaman Eylem durumu hakkında bilgi vermesi gerekir.

Aşağıdaki örneği göz önünde bulundurarak:

  1. Uygulama bir Çağrı Başlatma Eylemi aldı ve İletişim Ağı ile yeni bir VOIP çağrısı başlatma işlemini başlattı.
  2. Sınırlı veya hiçbir ağ iletişimi özelliği nedeniyle bu bağlantı başarısız olur.
  3. Uygulamanın, Sistemi hata hakkında bilgilendirmek için ÇağrıYı Başlat Eylemine ( ) Yeniden Başarısız Oldu iletisi göndermesi gerekir.
  4. Bu, Sistem'in kullanıcıya çağrının durumunu bildirmesi için izin verir. Örneğin, Çağrı Hatası kullanıcı arabirimini görüntülemek için.

Buna ek olarak, bir iOS 10 VOIP uygulamasının beklenen bir Eylem belirli bir süre içinde işlenemediklerinde ortaya çıkabilir Zaman Aşımı Hatalarına yanıt vermesi gerekir. CallKit tarafından sağlanan her Eylem Türü ile ilişkili en yüksek Zaman Aşımı değeri vardır. Bu Zaman Aşımı değerleri, kullanıcı tarafından istenen tüm CallKit Eyleminin yanıt veren bir şekilde işlenerek işletim sistemi akıcı ve hızlı yanıt veren bir şekilde olmasını sağlar.

Sağlayıcı Temsilcisinde ( ) bu Zaman Aşımı durumlarını da uygun bir şekilde işlemek için geçersiz CXProviderDelegate kılınacak çeşitli yöntemler vardır.

Sistem kısıtlamaları

iOS 10 VOIP uygulamasını çalıştıran iOS cihazın geçerli durumuna bağlı olarak bazı sistem kısıtlamaları uygulanabilir.

Örneğin, aşağıdaki gibi bir durumda gelen VOIP çağrısı Sistem tarafından kısıtlanabilir:

  1. Çağıran kişi kullanıcının Engellenen Çağıran Listesi'ne eklenir.
  2. Kullanıcının iOS cihazı, Rahatsız Etmeyin modundadır.

VoIP çağrısı bu durumlardan herhangi biri tarafından kısıtlanmışsa, bunu işlemek için aşağıdaki kodu kullanın:

public class ProviderDelegate : CXProviderDelegate
{
...

    public void ReportIncomingCall (NSUuid uuid, string handle)
    {
        // Create update to describe the incoming call and caller
        var update = new CXCallUpdate ();
        update.RemoteHandle = new CXHandle (CXHandleType.Generic, handle);

        // Report incoming call to system
        Provider.ReportNewIncomingCall (uuid, update, (error) => {
            // Was the call accepted
            if (error == null) {
                // Yes, report to call manager
                CallManager.Calls.Add (new ActiveCall (uuid, handle, false));
            } else {
                // Report error to user here
                if (error.Code == (int)CXErrorCodeIncomingCallError.CallUuidAlreadyExists) {
                    // Handle duplicate call ID
                } else if (error.Code == (int)CXErrorCodeIncomingCallError.FilteredByBlockList) {
                    // Handle call from blocked user
                } else if (error.Code == (int)CXErrorCodeIncomingCallError.FilteredByDoNotDisturb) {
                    // Handle call while in do-not-disturb mode
                } else {
                    // Handle unknown error
                }
            }
        });
    }

}

VOIP sesi

CallKit, bir iOS 10 VOIP uygulamasının canlı VOIP çağrısı sırasında gerektirecek ses kaynaklarını işlemeye çeşitli avantajlar sağlar. En büyük avantajlarından biri, uygulamanın ses oturumunun iOS 10'da çalıştırıldıklarında yükseltilmiş önceliklere sahip olmasıdır. Bu, yerleşik Telefon ve FaceTime uygulamalarıyla aynı öncelik düzeyidir ve bu gelişmiş öncelik düzeyi, çalışan diğer uygulamaların VOIP uygulamasının ses oturumunu kesintiye uğratmasını önlemektedir.

Ayrıca CallKit, performansı geliştiren ve kullanıcı tercihlerine ve cihaz durumlarına göre canlı arama sırasında VOIP seslerini belirli çıkış cihazlarına akıllı bir şekilde yönlendiren diğer ses yönlendirme ipuçlarına da erişim sağlar. Örneğin, Bluetooth bluetooth bluetooth bluetooth bluetooth cihazları, canlı bir CarPlay bağlantısı veya Erişilebilirlik ayarları gibi bağlı cihazlara göre.

CallKit kullanan tipik bir VOIP çağrısının yaşam döngüsü sırasında, uygulamanın CallKit'in bu çağrıyı sağlaycı Ses Akışını yapılandırması gerekir. Aşağıdaki örneği göz atarak:

Başlatma Çağrısı Eylem Sırası

  1. Uygulama tarafından gelen bir çağrıyı yanıtlamak için Bir Çağrı Başlatma Eylemi alınmıştır.
  2. Bu Eylem uygulama tarafından yerine getirilmeden önce, için gerekli olan yapılandırmayı AVAudioSession sağlar.
  3. Uygulama, sisteme eylemin karşılandığını bildirir.
  4. Çağrı bağlanmadan önce, CallKit, AVAudioSession uygulamanın istediği yapılandırmayla eşleşen yüksek öncelikli bir yapılandırma sağlar. Uygulamasına uygulamasının yöntemi aracılığıyla bildirim alınacaktır DidActivateAudioSessionCXProviderDelegate .

Arama dizini uzantılarıyla çalışma

CallKit ile çalışırken, çağrı dizini uzantıları , engellenen çağrı numaralarını eklemek ve belırlı bir VoIP uygulamasına özgü sayıları IOS cihazında kişi uygulamasındaki kişilere göre tanımlamak için bir yol sağlar.

Çağrı dizini uzantısı uygulama

Bir Xamarin. iOS uygulamasında bir çağrı dizini uzantısı uygulamak için aşağıdakileri yapın:

  1. uygulamanın çözümünü Mac için Visual Studio açın.

  2. Çözüm Gezgini çözüm adına sağ tıklayın ve ekle yeni Projectekle ' yi seçin.

  3. İOSuzantılarıçağrı dizini uzantıları ' nı seçin ve İleri düğmesine tıklayın:

    Yeni bir arama dizini uzantısı oluşturma

  4. Uzantı için bir ad girin ve İleri düğmesine tıklayın:

    Uzantı için bir ad girme

  5. gerekirse Project adı ve/veya çözüm adını ayarlayın ve oluştur düğmesine tıklayın:

    Projeyi oluşturma

Bu, CallDirectoryHandler.cs projeye aşağıdaki gibi görünen bir sınıf ekler:

using System;

using Foundation;
using CallKit;

namespace MonkeyCallDirExtension
{
    [Register ("CallDirectoryHandler")]
    public class CallDirectoryHandler : CXCallDirectoryProvider, ICXCallDirectoryExtensionContextDelegate
    {
        #region Constructors
        protected CallDirectoryHandler (IntPtr handle) : base (handle)
        {
            // Note: this .ctor should not contain any initialization logic.
        }
        #endregion

        #region Override Methods
        public override void BeginRequest (CXCallDirectoryExtensionContext context)
        {
            context.Delegate = this;

            if (!AddBlockingPhoneNumbers (context)) {
                Console.WriteLine ("Unable to add blocking phone numbers");
                var error = new NSError (new NSString ("CallDirectoryHandler"), 1, null);
                context.CancelRequest (error);
                return;
            }

            if (!AddIdentificationPhoneNumbers (context)) {
                Console.WriteLine ("Unable to add identification phone numbers");
                var error = new NSError (new NSString ("CallDirectoryHandler"), 2, null);
                context.CancelRequest (error);
                return;
            }

            context.CompleteRequest (null);
        }
        #endregion

        #region Private Methods
        private bool AddBlockingPhoneNumbers (CXCallDirectoryExtensionContext context)
        {
            // Retrieve phone numbers to block from data store. For optimal performance and memory usage when there are many phone numbers,
            // consider only loading a subset of numbers at a given time and using autorelease pool(s) to release objects allocated during each batch of numbers which are loaded.
            //
            // Numbers must be provided in numerically ascending order.

            long [] phoneNumbers = { 14085555555, 18005555555 };

            foreach (var phoneNumber in phoneNumbers)
                context.AddBlockingEntry (phoneNumber);

            return true;
        }

        private bool AddIdentificationPhoneNumbers (CXCallDirectoryExtensionContext context)
        {
            // Retrieve phone numbers to identify and their identification labels from data store. For optimal performance and memory usage when there are many phone numbers,
            // consider only loading a subset of numbers at a given time and using autorelease pool(s) to release objects allocated during each batch of numbers which are loaded.
            //
            // Numbers must be provided in numerically ascending order.

            long [] phoneNumbers = { 18775555555, 18885555555 };
            string [] labels = { "Telemarketer", "Local business" };

            for (var i = 0; i < phoneNumbers.Length; i++) {
                long phoneNumber = phoneNumbers [i];
                string label = labels [i];
                context.AddIdentificationEntry (phoneNumber, label);
            }

            return true;
        }
        #endregion

        #region Public Methods
        public void RequestFailed (CXCallDirectoryExtensionContext extensionContext, NSError error)
        {
            // An error occurred while adding blocking or identification entries, check the NSError for details.
            // For Call Directory error codes, see the CXErrorCodeCallDirectoryManagerError enum.
            //
            // This may be used to store the error details in a location accessible by the extension's containing app, so that the
            // app may be notified about errors which occurred while loading data even if the request to load data was initiated by
            // the user in Settings instead of via the app itself.
        }
        #endregion
    }
}

BeginRequestÇağrı Dizin Işleyicisindeki yöntemin, gerekli işlevselliği sağlamak için değiştirilmesi gerekir. Yukarıdaki örnek söz konusu olduğunda, VOıP uygulamasının kişiler veritabanındaki engellenen ve kullanılabilir sayıların listesini ayarlamaya çalışır. Her türlü istek herhangi bir nedenle başarısız olursa, NSError hatayı betimleyen ve sınıfın yöntemine geçiren bir oluşturma işlemi oluşturun CancelRequestCXCallDirectoryExtensionContext .

Engellenen sayıları ayarlamak için AddBlockingEntry sınıfının yöntemini kullanın CXCallDirectoryExtensionContext . Yöntemine girilen sayılar sayısal olarak artan düzende olmalıdır. Çok sayıda telefon numarası olduğunda en iyi performans ve bellek kullanımı için, yalnızca belirli bir zamanda bir sayı alt kümesini yüklemeyi düşünün ve yüklenen her bir numara kümesi için ayrılan nesneleri serbest bırakma Havuzu (ler) i kullanın.

VOıP uygulamasıyla bilinen kişi numaralarının uygulamasıyla Iletişim kurmak için, AddIdentificationEntry sınıfının yöntemini kullanın CXCallDirectoryExtensionContext ve hem numarayı hem de bir tanımlayıcı etiketi sağlayın. Yine, yönteme girilen sayıların sayısal olarak artan sırada olması gerekir . Çok sayıda telefon numarası olduğunda en iyi performans ve bellek kullanımı için, yalnızca belirli bir zamanda bir sayı alt kümesini yüklemeyi düşünün ve yüklenen her bir numara kümesi için ayrılan nesneleri serbest bırakma Havuzu (ler) i kullanın.

Özet

Bu makalede, Apple 'ın iOS 10 ' da piyasaya sürülen ve Xamarin. iOS VOıP uygulamalarında nasıl uygulanacağı yeni CallKit API 'SI ele alınmıştır. callkit 'in bir uygulamanın ios sistemiyle nasıl tümleştirileceğini, yerleşik uygulamalarla nasıl özellik eşliği sağladığını (Telefon gibi) ve bir uygulamanın, kilit ve giriş ekranları, Siri etkileşimleri ve kişiler uygulamaları aracılığıyla, bir uygulamanın ios genelinde görünürlüğünü nasıl artıracağını göstermiştir.