[{"data":1,"prerenderedAt":332},["ShallowReactive",2],{"news-item-\u002Fja\u002Fnews\u002Fvideochat-twilio":3},{"id":4,"title":5,"body":6,"category":317,"created by":320,"date":321,"description":322,"extension":323,"meta":324,"navigation":325,"path":326,"sections":327,"seo":328,"stem":329,"thumbnail":330,"__hash__":331},"content_ja\u002Fja\u002Fnews\u002Fvideochat-twilio.md","Twilio SDKを使った音声通話アプリ開発",{"type":7,"value":8,"toc":311},"minimark",[9,13,22,25,32,38,47,51,59,67,75,78,88,91,95,98,104,111,114,119,126,129,133,137,141,149,152,156,161,164,174,177,183,186,192,197,204,210,213,231,250,256,263,267,270,276,287,290,293,298,305],[10,11,12],"h2",{"id":12},"はじめに",[14,15,16,21],"p",{},[17,18,20],"a",{"href":19},"videochat-skyway","前回の記事","で述べた通りに、今日はTwilio Video SDKを使用してiOS版音声通話アプリを開発する方法を説明させていただきます。",[14,23,24],{},"概して言えば、Twilio Videoは、リアルタイムビデオチャット機能や音声通話機能、画面共有機能などを作るための色々なサービスを提供するプラットフォームとして知られており、世界で高く評価されています。",[14,26,27],{},[17,28,29],{"href":29,"rel":30},"https:\u002F\u002Fwww.g2.com\u002Fproducts\u002Ftwilio\u002Freviews",[31],"nofollow",[14,33,34],{},[17,35,36],{"href":36,"rel":37},"https:\u002F\u002Fwww.trustradius.com\u002Fproducts\u002Ftwilio-video\u002Freviews",[31],[14,39,40,41,46],{},"この記事では",[17,42,45],{"href":43,"rel":44},"https:\u002F\u002Fwww.twilio.com\u002Fdocs\u002Fvideo",[31],"Video API","を使用して音声通話アプリを開発してみましょう。",[10,48,50],{"id":49},"twilioでのプロジェクト作成","Twilioでのプロジェクト作成",[14,52,53,58],{},[17,54,57],{"href":55,"rel":56},"https:\u002F\u002Fwww.twilio.com\u002Ftry-twilio",[31],"Twillo","でアカウントを登録します。",[14,60,61,66],{},[17,62,65],{"href":63,"rel":64},"https:\u002F\u002Fwww.twilio.com\u002Fconsole",[31],"コンソールページ","を開きます。",[14,68,69,74],{},[17,70,73],{"href":71,"rel":72},"https:\u002F\u002Fwww.twilio.com\u002Fconsole\u002Fprojects\u002Fcreate",[31],"こちら","で「TwilioDemoChat」という名前または任意の名前のプロジェクトを作成します。",[14,76,77],{},"プロジェクト作成が終わったら、ウェルカムページが表示されます。",[79,80],"img",{"className":81,"alt":85,"src":86,"style":87},[82,83,84],"block","mx-auto","mb-4","","https:\u002F\u002Fhomepage-media.s3.ap-southeast-1.amazonaws.com\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002F17150511\u002FScreen-Shot-2020-07-17-at-15.03.20-1024x528.png","width: 100%;",[14,89,90],{},"「Other」を選択し、ダッシュボードページに遷移して、プロジェクトの作成手順を完了しましょう。",[79,92],{"className":93,"alt":85,"src":94,"style":87},[82,83,84],"https:\u002F\u002Fhomepage-media.s3.ap-southeast-1.amazonaws.com\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002F17150844\u002FScreen-Shot-2020-07-17-at-15.07.58-1024x396.png",[14,96,97],{},"後で使用できるように、アカウントSIDと認証トークンをファイルに保存しておきます。",[14,99,100],{},[101,102,103],"strong",{},"APIキー作成",[14,105,106,110],{},[17,107,73],{"href":108,"rel":109},"https:\u002F\u002Fwww.twilio.com\u002Fconsole\u002Fvideo\u002Fproject\u002Fapi-keys\u002Fcreate",[31],"で参照してください。",[14,112,113],{},"新しいAPIキーは、1回だけ表示されるので、慎重に保管しておいてください。",[14,115,116],{},[101,117,118],{},"アクセストークン作成",[14,120,121,125],{},[17,122,73],{"href":123,"rel":124},"https:\u002F\u002Fwww.twilio.com\u002Fconsole\u002Fvideo\u002Fproject\u002Ftesting-tools",[31],"で2つの新しいアクセストークンを作成します。その理由としては、2人のユーザー（TwilioDemoChatRoomUser1およびTwilioDemoChatRoomUser2）がTwilioDemoChatRoomという同じルームに参加するケースを検証するためです。「Generate Access Token」ボタンをクリックしてアクセストークンを取得し、iOSアプリに使用するために保存しておきます。",[14,127,128],{},"注意事項：リリース環境では、これがサーバー側によって実施されます。サーバー側でルームに参加するユーザーにつきアクセストークンを生成します。そのアクセストークンは、Twilioサーバーに対してユーザーを認証するための短期認証です。",[79,130],{"className":131,"alt":85,"src":132,"style":87},[82,83,84],"https:\u002F\u002Fhomepage-media.s3.ap-southeast-1.amazonaws.com\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002F17165611\u002FScreen-Shot-2020-07-17-at-16.55.26-1024x279.png",[79,134],{"className":135,"alt":85,"src":136,"style":87},[82,83,84],"https:\u002F\u002Fhomepage-media.s3.ap-southeast-1.amazonaws.com\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002F17165657\u002FScreen-Shot-2020-07-17-at-16.56.39-1024x240.png",[10,138,140],{"id":139},"iosでの音声通話アプリ開発","iOSでの音声通話アプリ開発",[14,142,143,148],{},[17,144,147],{"href":145,"rel":146},"https:\u002F\u002Fgithub.com\u002Ftwilio\u002Ftwilio-video-app-ios",[31],"チュートリアル","を参照してください。",[14,150,151],{},"TwilioDemoChatという新しいプロジェクトを作成します。",[79,153],{"className":154,"alt":85,"src":155,"style":87},[82,83,84],"https:\u002F\u002Fhomepage-media.s3.ap-southeast-1.amazonaws.com\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002F17153400\u002FScreen-Shot-2020-07-17-at-15.33.09-1024x754.png",[14,157,158],{},[101,159,160],{},"CocoaPods構成",[14,162,163],{},"プロジェクトのルートディレクトリにPodFileという空ファイルを作成し、以下のコードを入れます。",[165,166,171],"pre",{"className":167,"code":169,"language":170},[168],"language-text","platform :ios,'11.0'\nuse_frameworks!\n\ndef install_pods\n  pod 'TwilioVideo'\n  pod 'MBProgressHUD'\nend\n\ntarget 'TwilioDemoChat' do\n  install_pods\nend\n","text",[172,173,169],"code",{"__ignoreMap":85},[14,175,176],{},"ターミナルアプリを開き、プロジェクトルートで次のコマンドを実行することでTwilioVideo SDKをインストールします。",[165,178,181],{"className":179,"code":180,"language":170},[168],"pod install\n",[172,182,180],{"__ignoreMap":85},[14,184,185],{},"アプリ側は音声通話のため端末のマイクロを使用するので、端末のマイクにアクセスする権限をinfo.plistファイルに追加する必要があります。",[165,187,190],{"className":188,"code":189,"language":170},[168],"NSMicrophoneUsageDescription\nこのサンプルにて音声通話機能に端末のマイクロを使います。\n",[172,191,189],{"__ignoreMap":85},[14,193,194],{},[101,195,196],{},"Twilio導入",[14,198,199,200,203],{},"まず、ルームへの参加を処理する",[101,201,202],{},"TwilioController.swift","コントローラーを作成します。",[165,205,208],{"className":206,"code":207,"language":170},[168],"import UIKit\nimport TwilioVideo\nimport MBProgressHUD\n\nlet TWILIO_TEST_ROOM = \"TwilioDemoChatRoom\"\n\nlet TWILIO_ACCESS_TOKEN_1 = \"「アクセストークン作成」で作成されたアクセストークン\"\nlet TWILIO_ACCESS_TOKEN_2 = \"「アクセストークン作成」で作成されたアクセストークン\"\n\nlet kTwilioController = TwilioController.shared\n\npublic enum RoomStatus{\n    case Connected\n    case Disconnected\n    case ParticipantConnected\n    case ParticipantDisconnected\n    case Error\n}\n\npublic typealias RoomStatusUpdatedHandler = (RoomStatus) -> (Void)\n\nclass TwilioController: NSObject {\n    static let shared = TwilioController()\n    \n    var room:Room? = nil\n    var connected = false\n    var roomStatusHandler:RoomStatusUpdatedHandler?\n    \n    private var localAudioTrack = LocalAudioTrack()\n\n    \u002F\u002FTWILIO_TEST_ROOM定数でルームへ接続を行ないます。\n    func  connectToRoom(handler:RoomStatusUpdatedHandler?) {\n        roomStatusHandler = handler \n        \u002F\u002F各端末ごとにアクセストークンを変更します。\n        let connectOptions = ConnectOptions(token: TWILIO_ACCESS_TOKEN_2) { (builder) in\n            builder.roomName = TWILIO_TEST_ROOM\n            \n            \u002F\u002Fcấu hình âm thanh\n            if let audioTrack = self.localAudioTrack {\n                builder.audioTracks = [ audioTrack ]\n            }\n        }\n        room = TwilioVideoSDK.connect(options: connectOptions, delegate: self)\n    }\n    \n    func disconnectFromRoom()  {\n        room?.disconnect()\n    }\n    \n    \u002F\u002F MARK: プライベートメソッド\n    private func toastMessage(message:String){\n        print(\"toastMessage \\(message)\")\n        DispatchQueue.main.asyncAfter(deadline: .now() ) {\n            let hud = MBProgressHUD.showAdded(to: UIApplication.shared.keyWindow!, animated: true)\n            hud.mode = .text\n            hud.label.text = message\n            hud.removeFromSuperViewOnHide = true\n            hud.hide(animated: true, afterDelay: 2)\n        }\n    }\n}\n\nextension TwilioController : RoomDelegate{\n    \n    \u002F\u002Fユーザーがルームに接続した時のイベント\n    func roomDidConnect(room: Room) {\n        connected = true\n        roomStatusHandler?(.Connected)\n    }\n    \n    \u002F\u002Fユーザーがルームを出た時のイベント\n    func roomDidDisconnect(room: Room, error: Error?) {\n        connected = false\n        roomStatusHandler?(.Disconnected)\n    }\n    \n    \u002F\u002Fネットワーク接続エラーまたはタイムアウト等でルームに参加できない時のイベント\n    func roomDidFailToConnect(room: Room, error: Error) {\n        connected = false\n        roomStatusHandler?(.Error)\n    }\n    \n    \u002F\u002F他者がルームに参加した時のイベント\n    func participantDidConnect(room: Room, participant: RemoteParticipant) {\n        let message = \"participant \\(participant.identity) connected\"\n        toastMessage(message: message)\n        roomStatusHandler?(.ParticipantConnected)\n    }\n    \n    \u002F\u002F参加者がルームを出た時のイベント\n    func participantDidDisconnect(room: Room, participant: RemoteParticipant) {\n        let message = \"participant \\(participant.identity) disconnected\"\n        toastMessage(message: message)\n        roomStatusHandler?(.ParticipantDisconnected)\n    }\n}\n",[172,209,207],{"__ignoreMap":85},[14,211,212],{},"このコントローラーには、主な関数が二つあります。",[14,214,215,218,219,222,223,226,227,230],{},[101,216,217],{},"connectToRoom","()は",[101,220,221],{},"TWILIO_TEST_ROOM","定数とアクセストークン（",[101,224,225],{},"TWILIO_ACCESS_TOKEN_1","または",[101,228,229],{},"TWILIO_ACCESS_TOKEN_2","）で指定された特定のルームに接続します。 端末で実行する場合は、端末ごとに異なるアクセストークンを設定してください。また、この関数は次のイベント処理をも行ないます。",[232,233,234,238,241,244,247],"ul",{},[235,236,237],"li",{},"Connected：ユーザーがルームに接続した時のイベント",[235,239,240],{},"Disconnected：ユーザーがルームを出たときのイベント",[235,242,243],{},"ParticipantConnected：他者がルームに参加した時のイベント",[235,245,246],{},"ParticipantDisconnected：参加者がルームを出た時のイベント",[235,248,249],{},"roomDidFailToConnect：ネットワーク接続エラーまたはタイムアウト等でルームに参加できない時のイベント",[14,251,252,255],{},[101,253,254],{},"disconnectFromRoom","()はルームを出ます",[14,257,258,259,262],{},"つぎに、以下のような簡単な画面の",[101,260,261],{},"CallViewController","ビューコントローラーを作成します。",[79,264],{"className":265,"alt":85,"src":266,"style":87},[82,83,84],"https:\u002F\u002Fhomepage-media.s3.ap-southeast-1.amazonaws.com\u002Fwp-content\u002Fuploads\u002F2020\u002F07\u002F20110441\u002Ftwilio_chat.png",[14,268,269],{},"次のコードをCallViewController.swiftファイルに入れます。",[165,271,274],{"className":272,"code":273,"language":170},[168],"import UIKit\nimport MBProgressHUD\n\nclass CallViewController: UIViewController {\n    \n    @IBOutlet weak var joinButton: UIButton!\n    @IBOutlet weak var roomTxt: UITextField!\n        \n    \u002F\u002Fルームの参加ステータスが変わったら、ボタンの名前が更新されます。\n    private var joined = false{\n        didSet{\n            if joined {\n                joinButton.setTitle(\"End call\", for: .normal)\n            }else{\n                joinButton.setTitle(\"Join\", for: .normal)\n            }\n        }\n    }\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        roomTxt.text = TWILIO_TEST_ROOM\n                \n    }\n    \n    @IBAction func joinRoom(_ sender: Any) {\n        if !joined{\n            MBProgressHUD.showAdded(to: self.view, animated: true)\n            kTwilioController.connectToRoom { (status) -> (Void) in\n                if status == .Connected {\n                    self.joined = true\n                }\n                if status == .Disconnected{\n                    self.joined = false\n                }\n                MBProgressHUD.hide(for: self.view, animated: true)\n            }\n            \n        }else{\n            kTwilioController.disconnectFromRoom()\n        }\n\n    }\n        \n}\n",[172,275,273],{"__ignoreMap":85},[14,277,278,279,282,283,286],{},"ユーザーが参加したいルームの名前を入力するためのテキストフィールドと、ルームに参加または退出するためのボタンがあります。このテキストフィールドは",[101,280,281],{},"TwilioDemoChatRoom","と命名し、変更不可とします。このボタンは参加ステータスによって名前が変更され、**connectToRoom()",[101,284,285],{},"か","disconnectFromRoom()**を呼び出します。",[14,288,289],{},"では、２台のiOS端末で実行して動作を確認しましょう。尚、このアプリはシミュレーターに対応していません。",[14,291,292],{},"実行にあたって端末ごとにアクセストークンを必ず変更しておいてください。",[14,294,295],{},[101,296,297],{},"参照元：",[14,299,300],{},[17,301,304],{"href":302,"rel":303},"http:\u002F\u002Ftwilio.com\u002Fdocs\u002Fvideo\u002Fios-v1-getting-started",[31],"Twilio Video iOS Tutorial",[14,306,307],{},[17,308,310],{"href":63,"rel":309},[31],"Twilio Console",{"title":85,"searchDepth":312,"depth":312,"links":313},2,[314,315,316],{"id":12,"depth":312,"text":12},{"id":49,"depth":312,"text":50},{"id":139,"depth":312,"text":140},[318,319],"tech talk","mobile","Briswell Vietnam Co Ltd","2020-08-13","前回の記事で述べた通りに、今日はTwilio Video SDKを使用してiOS版音声通話アプリを開発する方法を説明させていただきます。","md",{},true,"\u002Fja\u002Fnews\u002Fvideochat-twilio",null,{"title":5,"description":322},"ja\u002Fnews\u002Fvideochat-twilio","https:\u002F\u002Fhomepage-media.s3.ap-southeast-1.amazonaws.com\u002Fwp-content\u002Fuploads\u002F2020\u002F08\u002F13161934\u002Ftwilio.png","XkrfU9-Xp1lZxmliQvlYPNxA5hBATh6vz3n2qXjRENg",1785320533890]