IOS編程--VoIP解密
一般來說, IOS很少給App后台運行的權限. 僅有的方式就是 VoIP. IOS少有的為VoIP應用提供了后台socket連接,定期喚醒並且隨開機啟動的權限.而這些就是IOS上實現VoIP App的關鍵. 蘋果官方文檔對於的描述就短短的一頁(點擊這里),很多細節沒有提及. 這篇微博通過具體實現和查閱資料,補充了這些細節.並且列舉出了在實現過程中可能遇到的問題, 作為參考.
- 博客: http://www.cnblogs.com/jhzhu
- 郵箱: jhzhuustc@gmail.com
- 作者: 知明所以
- 時間: 2013-11-10
官方文檔描述如是:
PS:此節純用來占座.如果你你E文不好或者想直接切入正題, 請看下一標題.
There are several requirements for implementing a VoIP app:
- Add the UIBackgroundModes key to your app’s Info.plist file. Set the value of this key to an array that includes the voip string.
- Configure one of the app’s sockets for VoIP usage.
- Before moving to the background, call the setKeepAliveTimeout:handler: method to install a handler to be executed periodically. Your app can use this handler to maintain its service connection.
- Configure your audio session to handle transitions to and from active use.
- To ensure a better user experience on iPhone, use the Core Telephony framework to adjust your behavior in relation to cell-based phone calls; see Core Telephony Framework Reference.
- To ensure good performance for your VoIP app, use the System Configuration framework to detect network changes and allow your app to sleep as much as possible.
我的翻譯:
關於IOS為VoIP應用提供的特殊權限和實現方法,我的描述如下. 我盡可能的涉及到voip實現的各種細節, 這樣你能對這個運作機制有一個更好的理解,我覺得這遠比單單貼幾行代碼有意義. 因為一個開發者在實際實現過程中遇到的千難險阻很少會體現在最終代碼上, 就如你永遠不知道台上的角兒在台下的挫折.
- IOS允許App的一個Socket在App切換到后台后仍然保持連接. 這樣,當有通話請求的時候,App能及時處理. 這個
socket
需要在應用第一次啟動的時候創建, 並標記為"此socket
用於VoIP服務". 這樣當App切換到后台的時候,IOS會接管這個標記為"用於VoIP服務"的socket
. 這個socket
的響應函數(比如,一個delegate
,或者是個block
)會正常的響應, 就像App還在前台一樣. - 10s魔咒. 當
socket
有任何數據從服務端傳來, 你在app里為socket
寫的響應函數都會做處理.但是, 你只有最多10s的時間來干你想干的事情. 也就意味着你在響應函數里新建一個大於10s的timer
是沒有意義的. 並且IOS並不保證給你足夠10s的時間,視系統情況而定. - 在
socket
的響應函數里, 你能通過NSLocalNotification
來通知用戶"電話來了". 除此之外, 你沒法做其他任何視覺上的動作來提醒用戶, 因為你的app還處於某個不知道的次元, 甚至連window
都還沒創建. - 你永遠也沒有辦法知道或者決定
NSLocalNotification
的樣式是banner
還是alert
. 你也許鍾愛后者, 但是決定權在用戶手里. - 允許在后台定期執行一段代碼. 你可以設定一個大於等於10分鍾的時間
t
, 和一個定期執行的handler
, IOS系統會在每次經過t
時間的時候調用一次這個handler
. 但是IOS不保證這個handler
會准時運行, 只保證在時間t
范圍內的某個點會執行一次. - 我們通常用樓上的
handler
處理socket的斷線重連操作. 因為網絡不穩定, 或者用戶開啟飛行模式等原因, 我們用於voip服務的socket
會斷開連接. 在這個handler
里,如果發現連接斷開,我們只需要跟條目1一樣的創建socket
,設置一樣的socket
響應函數,一切又會恢復正常. - 不建議這個
handler
做太多事情, 因為它也有10s魔咒.(據不完全統計,蘋果所有的后台處理都有這個10s限制. 不保證絕對正確哈, 僅供參考) - 自啟服務. 當IOS重新啟動, 或者你的app因為其他原因退出時, IOS會馬上啟動你注冊為voip的app, 你可以很迅速的恢復
socket
連接. 但是, 從底部多任務欄中手動關閉應用除外.更"code"的說明是:當程序退出的exitcode != 0
,IOS會重啟你的app.經試驗發現,從底部多任務欄關閉的時候,程序的exitcode == 0
. - 如果你親愛的用戶是一個典型的"app終結者",那么你還剩最后一條路來通知來電提醒:
NSRemoteNotification
. 你也許會被NSRemoteNotification
的可靠性和實時性折騰的抓狂, 但是, 誰讓你選了IOS? 你享受了封閉帶來的傳世體驗, 也得承受封閉的限制. - 當條目8描述的情況發生之后,app的
application:didFinishLaunchingWithOptions:
會被調用. 但是,請時刻提醒自己我們的app仍然處於后台. 我們以前總在這里創建window
創建rootController
, 但現在不必了. 現在我們需要的就是把可愛的socket
連上, 像在條目1里一樣,讓一切回歸正常(我不去寫歌詞真浪費了^_^). - 在
application:didFinishLaunchingWithOptions:
里你能通過[application applicationState] == UIApplicationStateBackground
來判斷是正常啟動應用還是系統自動啟動, 然后決定該創建window
還是創建voip的socket
. - 如果你看完上面一頭霧水. 請回爐重造, 傳送門:Programming with Objective-C, iOS Develop Library.