2014年5月25日

在iOS應用程式中判斷使用者是否正在撥打電話 - 使用CoreTelephony framework的CTCallCenter

前言

當手機App正在前景執行時,總難避免正好有人打了一通電話過來。因此,手機App是否能在當下執行適當的處理,像是:主動幫使用者儲存編輯到一半的資料、暫時中斷已經進行到一半的VOIP通話...等等,是每個手機應用程式開發者都應該審慎面對的課題。
而在iOS系統中,當某個App正在前景執行時遇到了一通來電,則該應用程式會進入Inactive狀態
(關於應用程式的狀態,可參考我先前寫的一篇文章:淺談iOS應用程式背景執行(一) - 在有限時間內在背景執行任意工作)
然而這樣或許不夠;iOS上的手機App在前景執行時,有許多狀況都會使手機App進入Inactive狀態,你也許會想要明確地區分出,什麼時候才是遇到了一通來電。
iOS系統提供了CoreTelephony framework,能夠輕易地幫iOS應用程式開發者處理這個問題。

使用CoreTelephony framework的CTCallCenter

CTCallCenter類別除了能夠取得當前手機的通話狀態,也能夠註冊特定的事件處理函式,讓應用程式在通話狀態變更時,執行特定的程式碼。
CTCallCenter類別位於CoreTelephony framework。在開始使用CTCallCenter類別之前,務必記得將之加入專案中。
之後,在程式中import需要用到的類別即可。

取得當前通話狀態

以下範例是取得當前使用者是否正在進行通話:
#import <CoreTelephony/CTCallCenter.h>
#import <CoreTelephony/CTCall.h>

CTCallCenter *callCenter = [[CTCallCenter alloc] init];
for (CTCall *call in callCenter.currentCalls)  {
    if (call.callState == CTCallStateConnected) {
        //目前有通話正在進行中
    }
}
CTCallCenter的 currentCalls property表示當前的所有通話。
為一個由CTCall物件所組成的陣列。
而一個CTCall物件實例表示了一通電話。
CTCall類別有兩個property: callIDcallState
callID是這通通話的唯一識別碼,callState則是這通通話目前的狀態。兩者皆為NSString*型態。
其中callState可能的內容如下:
1. CTCallStateDialing:撥號中。
2. CTCallStateIncoming:有來電。
3. CTCallStateConnected:正在通話中。
4. CTCallStateDisconnected:通話節數。

為通話狀態變更時,註冊事件處理函式

除了在程式中主動偵測目前的通話狀態之外,
為通話狀態變更時,註冊事件處理函式,
讓程式能在通話狀態變更時,執行特定的處理,
往往更為實用,範例如下:
#import <CoreTelephony/CTCallCenter.h>
#import <CoreTelephony/CTCall.h>

@implementation SomeViewController {
    CTCallCenter *callCenter;
}

- (void)viewDidLoad
{
    self.callCenter = [[CTCallCenter alloc] init];
    self.callCenter.callEventHandler = ^(CTCall* ctcall) {
        // do something, for example ...
        if (call.callState == CTCallStateConnected) {
            //目前有通話正在進行中
        }
    };
}
以上範例,能在Callback函式中取得通話狀態發生變化的CTCall物件,
此時,再由該物件取得通話狀態,並進行對應的處理即可。

結語

撰寫手機App,與PC應用程式上的及網頁應用程式,
最大的不同,莫過於,除了有限的硬體設備外,還需要處理手機App執行時遇到一通來電的狀況。

在iOS系統上有簡潔易用的CoreTelephony framework可以幫助iOS App開發者處理這個狀況,務必花上一點時間學習了解如何使用。