https://d226lax1qjow5r.cloudfront.net/blog/blogposts/how-to-make-outbound-calls-using-ios-callkit/ios-callkit_outbound-call.png

iOSのCallKitを使って発信電話をかける方法

最終更新日 October 18, 2023

所要時間:1 分

このチュートリアルでは、Vonage Client SDK と CallKit を使用して電話をかけることができる SwiftUI アプリケーションを作成します。CallKit を使うことで、iOS アプリケーションをシステムに統合することができます。発信電話をかけるとき、アプリケーションからの通話履歴は iOS の電話アプリで利用できるようになります。

前提条件

  • Vonage APIアカウント。まだお持ちでない方は 今すぐサインアップ.

  • Apple DeveloperアカウントとiOSデバイス

  • Xcode 12とSwift 5以上。

  • ココアポッドをクリックしてVonage Client SDK for iOSをインストールしてください。

概要

まず、Vonage Application、Applications、JWT Generation、Webhooksを作成するためのサーバをデプロイします。その後、Vonage Client SDKを使用して、CallKitを使用して呼び出しを行うiOSアプリケーションを適応させます。

サーバーの配置

このプロジェクトでは Vonage Cloud Runtime Marketplaceを使用します。を使用して、Vonage インフラストラクチャに Client SDK Voice サーバをデプロイします。を開きます。 Client SDK Voiceサンプルサーバー製品ページを開きます。Deploy Code "タブを開き、まだログインしていない場合は今すぐログインしてください。

配置の名前を入力し、地域を選択します。その後、"Deploy Code "ボタンをクリックしてください。

Client SDK Voice Sample Server "Deploy Code" pageClient SDK Voice Sample Server "Deploy Code" page

Voice APIを使用するには、Vonage番号を購入し、アプリケーションに割り当てる必要があります。Assign a number "をクリックして既存の番号を表示するか、新しい番号を購入してください。完了したら、"Continue "をクリックしてください。

Assign number popupAssign number popup

デプロイが完了したら、「Launch」ボタンをクリックします。ブラウザにサーバーアプリケーションが表示され、サーバーの動作についての詳細を読むことができます。チュートリアルを続けるには、ユーザを作成する必要があります。ユーザーとは、Vonage Client SDKをVonage APIで実行しているアプリケーションを識別するためのものです。

Client SDK Voice Sample Server landing pageClient SDK Voice Sample Server landing page

を作成します。 ユーザーAlice "というユーザーを作成し、JWTを生成します。クライアントSDKはJWTを使ってVonageと認証します。先ほどアプリケーションに割り当てたVonage番号に電話をかけると、Vonageはこのサーバにリクエストを行い、そのリクエストは コール・コントロール・オブジェクトを返します。

Generating a JWT for a user on the Client SDK Voice Sample ServerGenerating a JWT for a user on the Client SDK Voice Sample Server

スターター・プロジェクトのダウンロード

このチュートリアルは、既存のプロジェクトの上に構築されます。Vonage Client SDKを使用して発信通話をすることに慣れていない場合は、以下のチュートリアルを参照することをお勧めします。 SwiftUIで電話をかける方法ブログの投稿を参照することをお勧めします。準備ができたら、スタータープロジェクトを GitHubからスタータープロジェクトをクローンします:

git clone git@github.com:Vonage-Community/blog-clientsdk-ios_swift-swiftui_app_to_phone.git

次に、ディレクトリをプロジェクトのフォルダに移動し、以下のファイルをインストールする。 VonageClientSDKVoiceをインストールします:

cd blog-clientsdk-ios_swift-swiftui_app_to_phone
pod install

完成したら、このコマンドでプロジェクトを開くことができる:

xed .

スタータープロジェクトの更新

CallKitを使用して呼び出しを行うので、次のように loginIfNeeded関数を ContentView.swiftファイルの関数を更新して isUsingCallKitフラグを削除します。SDKのデフォルトはtrueです。ここで、先ほど作成したユーザー "Alice "のJWTを貼り付けることもできます:

func loginIfNeeded() {
    guard status != "Connected" else { return }
    client.createSession("ey...") { error, sessionId in
        if let error {
            self.updateStatus(error.localizedDescription)
        } else {
            self.updateStatus("Connected")
        }
    }
}

VoIPバックグラウンドモードの追加

CallKit を使用するには、VoIP バックグラウンドモードを追加する必要があります。Xcodeの環境設定からApple開発者アカウントにログインしていることを確認してください。そうであれば、ターゲットを選択し 署名と機能:

Add capability button in XcodeAdd capability button in Xcode

次に、ケイパビリティの追加ボタンとBackground Modesケイパビリティを選択します。バックグラウンド・モード機能で ボイスオーバーIP:

Adding the VoIP background mode in XcodeAdding the VoIP background mode in Xcode

CallKitフレームワークのリンク

CallKit フレームワークをプロジェクトにリンクします。 フレームワーク、ライブラリ、組み込みコンテンツの下に追加します。 一般:

Adding the CallKit framework in XcodeAdding the CallKit framework in Xcode

プロバイダー・マネージャーの作成

次に、クラスを作成する、 ProviderManager.CallKitは、アプリとシステム間の通信を CXProvider.という名前の新しいSwiftファイル(CMD + N)を作成します。 ProviderManager:

import CallKit
import Foundation
import VonageClientSDKVoice

protocol ProviderManagerDelegate: AnyObject {
    func callReported(_ providerManager: ProviderManager, callUUID: UUID)
    func providerReset()
}

final class ProviderManager: NSObject {
    private static var providerConfiguration: CXProviderConfiguration = {
        let providerConfiguration = CXProviderConfiguration()
        providerConfiguration.maximumCallsPerCallGroup = 1
        providerConfiguration.supportedHandleTypes = [.generic, .phoneNumber]
        return providerConfiguration
    }()
    
    private let provider = CXProvider(configuration: ProviderManager.providerConfiguration)
    weak var delegate: ProviderManagerDelegate?
    
    override init() {
        super.init()
        provider.setDelegate(self, queue: nil)
    }
    
    public func reportOutgoingCall(callUUID: UUID) {
        provider.reportOutgoingCall(with: callUUID, connectedAt: .now)
    }
    
    public func reportFailedCall(callUUID: UUID) {
        provider.reportCall(with: callUUID, endedAt: .now, reason: .failed)
    }
    
    public func reportEndedCall(callUUID: UUID) {
        provider.reportCall(with: callUUID, endedAt: .now, reason: .remoteEnded)
    }
}

上記のコードには CXProviderの作成と、システムに対する呼び出しのステータスを報告するヘルパー関数の作成が含まれている。また ProviderManagerDelegateもここで定義されている。

を実施する。CXProviderDelegate

CXProviderDelegateは、通話に関するシステムからの最新情報を提供する。同じファイルにデリゲートを実装する ProviderManagerを追加します:

extension ProviderManager: CXProviderDelegate {
    func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
        provider.reportOutgoingCall(with: action.callUUID, startedConnectingAt: .now)
        delegate?.callReported(self, callUUID: action.callUUID)
        action.fulfill()
    }
    
    func providerDidReset(_ provider: CXProvider) {
        delegate?.providerReset()
    }
    
    func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
        VGVoiceClient.enableAudio(audioSession)
    }
    
    func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
        VGVoiceClient.disableAudio(audioSession)
    }
}

ユーザーが番号を入力して通話を開始すると、アプリはCallKitに通話開始をリクエストする。このリクエストが成功すると CXStartCallActionデリゲート関数が呼び出され、発信が報告されます。ここで非常に重要なのは VGVoiceClient.enableAudio/VGVoiceClient.disableAudioがCallKitによって提供されたオーディオ・セッションで呼び出されていることに注意してください。 CXProviderDelegate.

更新CallModel

これで ProviderManagerがセットアップされたので CallModelクラスを更新します。ファイルを開き ContentView.swiftファイルの先頭にある変数を置き換える。 CallModelクラスの先頭にある変数を置き換えます:

final class CallModel: NSObject, ObservableObject, VGVoiceClientDelegate {

    @Published var status: String = ""
    @Published var isCalling: Bool = false
    private let client = VGVoiceClient()
    var number: String = ""


    private var callId: (vonage: String?, callkit: UUID?)
    private let callController = CXCallController()
    private let providerManager = ProviderManager()
    private let audioSession = AVAudioSession.sharedInstance()

    ...
}

callIdは、VonageコールIDからCallKitコールUUIDへのマッピングを管理するためのタプルに変更されました、 providerManagerが追加されました。 callController. callControllerのインスタンスです。 CXCallControllerのインスタンスである。

更新startCall機能

この startCall関数で呼び出しを要求するように更新しなければならない。 callControllerを介して呼び出しを要求するように更新する必要があります。既存の関数を新しい関数に置き換えてください:

func startCall() {
    isCalling = true
    let handle = CXHandle(type: .phoneNumber, value: number)
    self.callId.callkit = UUID()
    
    let startCallAction = CXStartCallAction(call: self.callId.callkit!, handle: handle)
    let transaction = CXTransaction(action: startCallAction)
    callController.request(transaction) { _ in }
}

CallKitはコールを識別する方法を必要とするため、この新しい関数はUUIDを作成しますが、SDKがコールをかけるまでVonageコールIDは取得できません。その後 CXStartCallActionCXTransactionを使用して通話をリクエストします。これは CXStartCallAction関数を呼び出します。 CXProviderDelegate関数を呼び出します。

更新endCall機能

同様に endCall関数も CallKit 用に更新する必要があります。既存の関数を新しい関数に置き換えてください:

func endCall() {
    client.hangup(callId.vonage!) { error in
        if error == nil {
            if let callkitUUID = self.callId.callkit {
                let transaction = CXTransaction(action: CXEndCallAction(call: callkitUUID))
                self.callController.request(transaction) { _ in }
            }
        }
    }
}

この新しい関数は CXEndCallActionアクションを作成した。 CXTransactionで使用される。通話終了をリクエストすることで、システムは通話時間を正確に計算できる。また、リモートで通話が終了した場合の処理も必要です。を更新する。 didReceiveHangupForCall関数を更新する。 VGVoiceClientDelegate関数を更新する:

func voiceClient(_ client: VGVoiceClient, didReceiveHangupForCall callId: VGCallId, withQuality callQuality: VGRTCQuality, reason: VGHangupReason) {
    if let callkitUUID = self.callId.callkit {
        providerManager.reportEndedCall(callUUID: callkitUUID)
    }
    resetState()
}

この場合も、通話終了が providerManagerを介して通話終了がシステムに報告されるため、通話時間を正確に計算できる。

を実施する。ProviderManagerDelegate

最後に ProviderManagerDelegateを実装する。 providerManagerに変更を伝えることができるようにする。 CallModel:

extension CallModel: ProviderManagerDelegate {
    func callReported(_ providerManager: ProviderManager, callUUID: UUID) {
        client.serverCall(["to": number]) { error, callId in
            if error == nil {
                providerManager.reportOutgoingCall(callUUID: callUUID)
                self.callId.vonage = callId
            } else {
                providerManager.reportFailedCall(callUUID: callUUID)
            }
        }
    }
    
    func providerReset() {
        resetState()
    }
}

このデリゲート関数は providerManagerが正常にシステムにコールを報告した場合、このデリゲート関数はVonage Client SDKを使用してコールを作成します。成功時とエラー時の両方で providerManagerは、通話ステータスをシステムに報告するために使用される。これで、物理デバイス上でXcodeプロジェクトを実行することで、アプリで通話を行うことができる。iOSの電話アプリで最近の通話を見ると、通話とアプリ名が表示されているはずだ。情報アイコンをクリックすると、通話時間も表示されます。

Call log from phone appCall log from phone app

次はどうする?

完成したプロジェクトは GitHub.Client SDKとCallKitを使うことで、さらに多くのことができるようになります。Client SDKの詳細については以下をご覧ください。 Vonage Client SDKの概要およびCallKitについては developer.apple.comでご覧いただけます。.

シェア:

https://a.storyblok.com/f/270183/400x400/19c02db2d3/abdul-ajetunmobi.png
Abdul AjetunmobiVonage 元チームメンバー

アブドゥルはVonageのデベロッパー・アドボケイト。iOSエンジニアとして消費者向け製品に携わった経歴を持つ。余暇には、サイクリング、音楽鑑賞、技術者としての道を歩み始めたばかりの人々の指導を楽しんでいる。