https://d226lax1qjow5r.cloudfront.net/blog/blogposts/make-app-to-phone-call-using-ios-and-flutter/flutter_inapp-call-2_1200x600.png

iOSとFlutterを使ってアプリから電話へ電話をかける

最終更新日 April 1, 2021

所要時間:3 分

今日は iOSアプリケーションを アプリケーションを構築します。を使ってアプリケーションを構築し Vonage Client SDKを利用します。を使ってモバイルアプリケーションから電話をかける。 Vonage Conversation APIを使う。.アプリケーションには3つの画面(3つのUI状態)があります:

UI states: logon, make a call, and end call

前提条件

このアプリケーションのソースコードは Flutter iOSアプリケーションのソースコードは GitHub.

アプリケーションの構築を始める前に Flutterアプリケーションの iOSデバイス用のアプリケーションを作り始める前に、以下の前提条件を準備する必要がある:

  • コール・コントロール・オブジェクト(NCCO)

  • を取り付ける。 Vonage CLI(以前は Nexmo CLI)

  • を設定する。 Vonage application

  • をインストールします。 Flutter SDK

  • を作成する。 Flutterプロジェクト

Vonageアプリケーション

NCCOの設立

A コール・コントロール・オブジェクト(NCCO)JSONのフローを制御するために使用する配列である。 Voice API call.

そのためには NCCOは公開され、インターネットからアクセスできる必要があります。そのために、このチュートリアルでは GitHub Gistを使います。新しいGistを追加しよう:

  1. 次のサイトへ https://gist.github.com/(Githubにログインする必要があります)

  2. 新しいgistを ncco.jsonをファイル名として

  3. 以下の JSONオブジェクトをgistに貼り付ける:

[
    {
        "action": "talk",
        "text": "Please wait while we connect you."
    },
    {
        "action": "connect",
        "endpoint": [
            {
                "type": "phone",
                "number": "PHONE_NUMBER"
            }
        ]
    }
]
  1. 置き換える PHONE_NUMBERを電話番号に置き換えてください。Vonageの電話番号はE.164形式です。, +であり -は無効です。電話番号を入力する際は、必ず国番号を指定してください:14155550100 および UK:447700900001)

  2. をクリックしてください。 Create secret gistボタン

  3. をクリックしてください。 Rawボタン

  4. ブラウザに表示されたURLをメモしておく。

Vonage CLIをインストールする

Vonage CLI Vonage CLIを使用すると、コマンドラインを使用して多くの操作を実行できます。アプリケーションの作成、会話の作成、Vonage Numbersの購入などのタスクを実行したい場合は、Vonage CLIをインストールする必要があります。

Vonage CLIには Node.jsが必要なので をインストールする必要があります。.

npmを使ってCLIのベータ版をインストールするには、以下のコマンドを実行する:

npm install nexmo-cli@beta -g

を設定します。 Vonage CLIを設定します。 API KeyAPI Secret.これらは 設定ページダッシュボードの

ターミナルで以下のコマンドを実行する。 API_KEYAPI_SECRETダッシュボード:

nexmo setup API_KEY API_SECRET

Vonageアプリケーションのセットアップ

  1. プロジェクト・ディレクトリを作成する。ターミナルで以下のコマンドを実行する:

mkdir vonage-tutorial
  1. プロジェクト・ディレクトリに移動する:

cd vonage-tutorial
  1. 以下のコマンドをターミナルにコピー&ペーストしてVonageアプリケーションを作成する。引数の --voice-answer-url引数の GIST-URLを前のステップの gist URL に置き換えてください。

nexmo app:create "App to Phone Tutorial" --capabilities=voice --keyfile=private.key --voice-event-url=https://example.com/ --voice-answer-url=GIST-URL

をメモしておくこと。 Application IDをメモしておいてください。

注:プロジェクト・ディレクトリに .nexmo-appという名前の隠しファイルがプロジェクト・ディレクトリに作成されます。 Vonage Application IDと秘密鍵が含まれます。という名前の秘密鍵ファイルが作成されます。 private.keyという名前の秘密鍵ファイルも現在のフォルダに作成されます。

ユーザー作成

各参加者は ユーザーオブジェクトで表され Client SDK.本番アプリケーションでは、通常このユーザー情報をデータベースに保存します。

というユーザーを作成するために以下のコマンドを実行する。 Alice:

nexmo user:create name="Alice"

JWTの生成

はユーザー認証に使用される。 JWTはユーザーの認証に使われる。ターミナルで以下のコマンドを実行して JWTを生成する。 Alice.以下のコマンドの APPLICATION_IDをアプリケーションのIDに置き換えてください:

nexmo jwt:generate sub=Alice exp=$(($(date +%s)+86400)) acl='{"paths":{"/*/users/**":{},"/*/conversations/**":{},"/*/sessions/**":{},"/*/devices/**":{},"/*/image/**":{},"/*/media/**":{},"/*/push/**":{},"/*/knocking/**":{},"/*/legs/**":{}}}' application_id=APPLICATION_ID

上記のコマンドでは JWTの有効期限を1日後に設定する。

をメモしておいてください。 JWTに対して生成した Alice.

注:本番環境では、アプリケーションは各クライアントからのリクエストに対して JWTを生成するエンドポイントを公開する必要があります。

Xcodeをインストールする

AppStoreを開き、インストールする Xcode.

フラッターセットアップ

Flutter SDKをインストールする

ダウンロードとインストール Flutter SDK.

このステップは MacOS, WinLinuxによって異なるが、一般的には Flutter SDKをダウンロードし Flutter SDKファイルを解凍し sdk\binフォルダをシステム PATH変数に追加することである。全プラットフォームの詳しい説明は こちら.

幸いなことに、 FlutterをVerifyできるツールが付属している。 SDKとすべての必要な "コンポーネント "が存在し、正しく設定されているかどうかを確認できるツールがある。次のコマンドを実行する:

flutter doctor

Flutter DoctorはVerifyする。 Flutter SDKがインストールされているか、その他のコンポーネントが正しくインストールされ、設定されているかを確認します。

Flutterプロジェクトの作成

ターミナルを使って Flutterプロジェクトを作成します:

flutter create app_to_phone_flutter

上記のコマンドは app_to_phone_flutterフォルダが作成されます。 Flutterプロジェクトを含むフォルダを作成します。

Flutterプロジェクトには iosフォルダが含まれています。 iOSプロジェクトが含まれます; androidプロジェクトを含む Androidプロジェクトを含む webプロジェクトを含む webプロジェクト。

ファイルを開き pubspec.yamlファイルを開き permission_handlerを追加する。 sdk: flutter):

dependencies:
  flutter:
    sdk: flutter
  
  permission_handler: ^6.0.1+1

ファイルではインデントが重要です。 yamlファイルではインデントが重要なので permission_handlerと同じインデント・レベルであることを確認してください。 flutter:項目と同じインデントレベルであることを確認してください。

次のコマンドを実行する(パスはプロジェクトのルート)。 Flutterプロジェクトのルート)を実行し、上記の依存関係をダウンロードする:

flutter pub get

上記のコマンドは Podfileを作成します。 iosサブフォルダーにも作成されます。開く ios\Podfile行を開き platform行を開き、プラットフォームのバージョンを 11:

platform :ios, '11.0'

同じファイルの最後に pod 'NexmoClient':

target 'Runner' do
  use_frameworks!
  use_modular_headers!
  pod 'NexmoClient'

開く app_to_phone_flutter/iosフォルダを開き、ポッドをインストールする:

pod install

上記のコマンドは、以下を含むすべての必要な依存関係をダウンロードする。 Flutterパーミッションハンドラー Client SDK.

オープン Runner.xcworkspaceXcodeで開き、アプリを実行して、上記のセットアップが正しく行われたことを確認する。

FlutterとiOSの双方向通信

現在 Client SDKFlutterパッケージとして提供されていないため AndroidネイティブClient SDKiOSFlutterの間で通信する必要があります。 メソッドチャネル- を使用します、 FlutterはAndroidのメソッドを呼び出します、 iOSFlutterメソッドを呼び出します。

Flutterのコードは lib/main.dartファイルに格納され iOSネイティブコードは ios/Runner/AppDelegate.swiftファイルに格納される。

Flutterアプリケーションの初期化

Flutterアプリケーションは、以下のプログラミング言語を使って構築される。 ダート.

ファイルを開き lib/main.dartファイルを開き、すべての内容を以下のコードに置き換える:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: CallWidget(title: 'app-to-phone-flutter'),
    );
  }
}

class CallWidget extends StatefulWidget {
  CallWidget({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _CallWidgetState createState() => _CallWidgetState();
}

class _CallWidgetState extends State<CallWidget> {
  SdkState _sdkState = SdkState.LOGGED_OUT;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            SizedBox(height: 64),
            _updateView()
          ],
        ),
      ),
    );
  }

  Widget _updateView() {
    if (_sdkState == SdkState.LOGGED_OUT) {
      return ElevatedButton(
          child: Text("LOGIN AS ALICE")
      );
    }
  }

  Future<void> _loginUser() async {
      // Login user
  }

  Future<void> _makeCall() async {
      // Make call
  }

  Future<void> _endCall() async {
      // End call
  }
}

enum SdkState {
  LOGGED_OUT,
  LOGGED_IN,
  WAIT,
  ON_CALL,
  ERROR
}

上記のコードには、アプリケーションの状態を管理するカスタム CallWidgetが含まれており、アプリケーションの状態(ユーザーのログ記録と呼び出しの管理)を管理します。この SdkStateenumはVonageの可能な状態を表します。 Client SDK.このenumは2回定義される。 DartiOSSwift を使う場合です。ウィジェットには _updateViewメソッドが含まれています。 SdkState値に基づいてUIを変更するメソッドが含まれています。

からアプリケーションを実行する。 Xcode:

Running the application from xcode

ボタンが表示されるはずです。 Login as Aliceボタンが表示される:

Logged out screen showing Login as Alice button

ログイン画面

ボタンが無効になっています。 Login as Aliceボタンは無効になっているので onPressedハンドラを ElevatedButtonを追加します:

Widget _updateView() {
    if (_sdkState == SdkState.LOGGED_OUT) {
      return ElevatedButton(
          onPressed: () { _loginUser(); },
          child: Text("LOGIN AS ALICE")
      );
    }
  }

の本体を更新する。 _loginUserメソッド本体を更新し、ネイティブコードと通信してユーザーにログインする:

Future<void> _loginUser() async {
    String token = "ALICE_TOKEN";

    try {
      await platformMethodChannel.invokeMethod('loginUser', <String, dynamic>{'token': token});
    } on PlatformException catch (e) {
      print(e);
    }
  }

ALICE_TOKENJWTトークンに置き換えてください。 Vonage CLIから取得したトークンに置き換えてください。 Aliceに置き換えてください。 FlutterloginUserメソッドを呼び出し、引数として tokenを引数として渡します。メソッドは loginUserメソッドは MainActivityクラスで定義されています。からこのメソッドを呼び出すには Flutterからこのメソッドを呼び出すには MethodChannel.フィールドを定義しなければなりません。 platformMethodChannelフィールドを定義しなければならない。 _CallWidgetStateフィールドを追加します:

追加 platformMethodChannelフィールドを _CallWidgetStateクラスの先頭にフィールドを追加する:

class _CallWidgetState extends State<CallWidget> {
  SdkState _sdkState = SdkState.LOGGED_OUT;
  static const platformMethodChannel = const MethodChannel('com.vonage');

この com.vonage文字列は一意なチャンネル ID を表し、ネイティブの iOSコード (AppDelegateクラス)にも参照される。ここで、ネイティブ側でこのメソッド呼び出しを処理する必要があります。 iOS側でこのメソッド呼び出しを処理する必要があります。

オープン ios/Runner/AppDelegateクラスと vonageChannelプロパティへの参照を保持する。 FlutterMethodChannel:

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  var vonageChannel: FlutterMethodChannel?
    
...

から発信されるメソッドコールをリッスンする Flutterを追加します。 addFlutterChannelListenerメソッド AppDelegateクラス(上記の applicationメソッドと同じレベル):

func addFlutterChannelListener() {
        let controller = window?.rootViewController as! FlutterViewController
        
        vonageChannel = FlutterMethodChannel(name: "com.vonage",
                                             binaryMessenger: controller.binaryMessenger)
        vonageChannel?.setMethodCallHandler({ [weak self]
            (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
            guard let self = self else { return }
            
            switch(call.method) {
            case "loginUser":
                if let arguments = call.arguments as? [String: String],
                   let token = arguments["token"] {
                    self.loginUser(token: token)
                }
                result("")
            default:
                result(FlutterMethodNotImplemented)
            }
        })
    }

上記のメソッドは Flutterメソッド呼び出しを AppDelegateクラスで定義されているメソッドに loginUser今のところは)。

そして loginUser同じクラス内のメソッドも欠落している:

func loginUser(token: String) {

}

ここで addFlutterChannelListenerメソッドを追加します。 applicationメソッドを追加します:

override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        addFlutterChannelListener()
        
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }

コードは所定の位置にある。 Login As Aliceボタンを押すと、Flutterアプリは _loginUserメソッドを呼び出します。プラットフォームチャンネルを通して Flutterプラットフォームチャネルを通して loginUserクラスで定義された AppDelegateクラスで定義されたメソッドを呼び出します。

アプリケーションを Xcodeからアプリケーションを実行し、コンパイルされていることを確認する。

ユーザーをログインさせる前に、初期化する必要があります。 Vonage SDK Client.

クライアントの初期化

開く AppDelegateクラスを開き NexmoClientインポートをファイルの先頭に追加する:

import NexmoClient

同じファイルに clientプロパティを追加する。 Vonage Client.

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    var vonageChannel: FlutterMethodChannel?
    let client = NXMClient.shared

...

ここで initClientメソッドを追加する:

func initClient() {
        client.setDelegate(self)
    }

既存の initClientメソッドを呼び出すには applicationメソッドを呼び出すには、以下の例のように initClient()行を追加する必要がある:

override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        initClient()
        addFlutterChannelListener()
        
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }

会話を許可する前に、ユーザーが正しくログインしていることを知る必要がある。そのために AppDelegateファイルに Vonage Client SDKデリゲートを追加します:

extension AppDelegate: NXMClientDelegate {
    func client(_ client: NXMClient, didChange status: NXMConnectionStatus, reason: NXMConnectionStatusReason) {
        switch status {
        case .connected:
            notifyFlutter(state: .loggedIn)
        case .disconnected:
            notifyFlutter(state: .loggedOut)
        case .connecting:
            notifyFlutter(state: .wait)
        @unknown default:
            notifyFlutter(state: .error)
        }
    }
}

最後に notifyFlutterメソッドを同じクラスに追加する必要がある:

func client(_ client: NXMClient, didReceiveError error: Error) {
        notifyFlutter(state: .error)
    }
}

ログイン

メソッド本体を修正する loginUserメソッド本体を修正して loginを呼び出すように修正する:

func loginUser(token: String) {
        self.client.login(withAuthToken: token)
    }

この方法では、ユーザー(Alice)にログインできるようになります。 Client SDKを使用して会話にアクセスします。

Client SDKの状態変更をFlutterに通知する

通知 Flutterを通知するために Client SDKの状態を表す enumを追加する必要がある。 Client SDK.に相当する SdkState列挙型を main.dartファイルに追加した。次の SdkStateenumを追加する。 MainActivity.ktファイルの一番下に

enum SdkState: String {
        case loggedOut = "LOGGED_OUT"
        case loggedIn = "LOGGED_IN"
        case wait = "WAIT"
        case onCall = "ON_CALL"
        case error = "ERROR"
    }

これらの状態を Flutter(上記のデリゲートから)これらの状態を送るには notifyFlutterメソッドを AppDelegateメソッドを追加する必要がある:

func notifyFlutter(state: SdkState) {
        vonageChannel?.invokeMethod("updateState", arguments: state.rawValue)
    }

状態を列挙型に保存しているが、文字列として送信していることに注目してほしい。

FlutterによるSDK状態更新の取得

状態の更新を Flutterの状態更新を取得するには、メソッド・チャネルの更新をリッスンする必要がある。ファイルを開き main.dartファイルを開いて _CallWidgetStateコンストラクタにカスタムハンドラを追加する:

_CallWidgetState() {
    platformMethodChannel.setMethodCallHandler(methodCallHandler);
  }

同じクラス (_CallWidgetState) の中にハンドラー・メソッドを追加する:

Future<dynamic> methodCallHandler(MethodCall methodCall) async {
    switch (methodCall.method) {
      case 'updateState':
        {
          setState(() {
            var arguments = 'SdkState.${methodCall.arguments}';
            _sdkState = SdkState.values.firstWhere((v) {return v.toString() == arguments;}
            );
          });
        }
        break;
      default:
        throw MissingPluginException('notImplemented');
    }
  }

これらのメソッドはAndroidから「シグナル」を受け取り、それをenumに変換する。ここで _updateViewメソッドの内容を更新して SdkState.WAITそして SdkState.LOGGED_INの状態に更新する:

Widget _updateView() {
    if (_sdkState == SdkState.LOGGED_OUT) {
      return ElevatedButton(
          onPressed: () { _loginUser(); },
          child: Text("LOGIN AS ALICE")
      );
    }  else if (_sdkState == SdkState.WAIT) {
      return Center(
        child: CircularProgressIndicator(),
      );
    } else if (_sdkState == SdkState.LOGGED_IN) {
      return ElevatedButton(
          onPressed: () { _makeCall(); },
          child: Text("MAKE PHONE CALL")
      );
    }
  }

期間中 SdkState.WAITプログレスバーが表示されます。ログインに成功すると MAKE PHONE CALLボタンが表示されます。

アプリを起動し LOGIN AS ALICE.をクリックする。 MAKE PHONE CALLボタンが表示されるはずです。 Flutterアプリの別の状態である SdkStateenum`)に基づいたアプリの別の状態です。この例を下の画像に示す:

Make a phone call UI state

電話をかける

次に、電話をかける機能を追加する必要がある。ファイルを開き main.dartファイルを開き _makeCallメソッドのボディを更新します:

Future<void> _makeCall() async {
    try {
      await platformMethodChannel
          .invokeMethod('makeCall');
    } on PlatformException catch (e) {
      print(e);
    }
  }

上記のメソッドは iOSと通信するので AppDelegateクラスのコードも更新しなければならない。追加 makeCall節を switch文の中に addFlutterChannelListenerメソッドに節を追加する:

func addFlutterChannelListener() {
        let controller = window?.rootViewController as! FlutterViewController
        
        vonageChannel = FlutterMethodChannel(name: "com.vonage",
                                             binaryMessenger: controller.binaryMessenger)
        vonageChannel?.setMethodCallHandler({ [weak self]
            (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
            guard let self = self else { return }
            
            switch(call.method) {
            case "loginUser":
                if let arguments = call.arguments as? [String: String],
                   let token = arguments["token"] {
                    self.loginUser(token: token)
                }
                result("")
            case "makeCall":
                self.makeCall()
                result("")
            default:
                result(FlutterMethodNotImplemented)
            }
        })
    }

次に同じファイルに onGoingCallプロパティを追加する:

var onGoingCall: NXMCall?

注:現在 Client SDKは進行中の呼び出し参照を保存しない。 AppDelegateクラスに格納しなければならない。後で通話を終了するときに使用します。

同じクラスに makeCallメソッドを追加します:

func makeCall() {
        client.call("IGNORED_NUMBER", callHandler: .server) { [weak self] (error, call) in
            guard let self = self else { return }
            
            if error != nil {
                self.notifyFlutter(state: .error)
                return
            }
            
            self.onGoingCall = call
            self.notifyFlutter(state: .onCall)
        }
    }

上記のメソッドは Flutterアプリの状態を SdkState.WAITに設定し Client SDKレスポンス(エラーまたは成功)を待つ。ここで、両方の状態 (SdkState.ON_CALLSdkState.ERROR) のサポートを main.dartファイルに追加する必要がある。以下のように _updateViewメソッドのボディを以下のように更新する:

Widget _updateView() {
    if (_sdkState == SdkState.LOGGED_OUT) {
      return ElevatedButton(
          onPressed: () { _loginUser(); },
          child: Text("LOGIN AS ALICE")
      );
    } else if (_sdkState == SdkState.WAIT) {
      return Center(
        child: CircularProgressIndicator(),
      );
    } else if (_sdkState == SdkState.LOGGED_IN) {
      return ElevatedButton(
          onPressed: () { _makeCall(); },
          child: Text("MAKE PHONE CALL")
      );
    } else if (_sdkState == SdkState.ON_CALL) {
      return ElevatedButton(
          onPressed: () { _endCall(); },
          child: Text("END CALL")
      );
    } else {
      return Center(
        child: Text("ERROR")
      );
    }
  }

状態が変わるたびに、UIが変更される。通話を行う前に、アプリケーションはマイクを使用するための特定のパーミッションが必要です。次のステップでは、これらの許可を要求する機能をプロジェクトに追加します。

リクエスト許可

アプリケーションはマイクにアクセスできる必要があるので、マイクへのアクセスをリクエストしなければならない(Permission.microphoneのために Flutter).

ファイルを開く ios/Runner/info.plistファイルを開き Privacy - Microphone Usage Descriptionキーに Make a call値を追加する:

Setting add microphone permission

すでに パッケージパッケージを Flutterプロジェクトに追加しました。次に main.dartファイルの先頭に permission_handlerパッケージをインポートする必要があります:

import 'package:permission_handler/permission_handler.dart';

特定のパーミッションのリクエストをトリガーするには requestPermissions()メソッドを _CallWidgetStateクラス内のメソッドを main.dartファイルに追加する必要がある。そこで、この新しいメソッドをクラス内に追加します:

Future<void> requestPermissions() async {
    await [ Permission.microphone ].request();
  }

上記のメソッドは permission_handler.

同じクラスで、メソッド・チャネル経由でメソッドを呼び出す前に、パーミッションを要求するように _makeCallクラスの本体を修正して、メソッド・チャネル経由でメソッドを呼び出す前にパーミッションを要求するようにします:

Future<void> _makeCall() async {
    try {
      await requestPermissions();
 
      ...
  }

アプリを起動し MAKE PHONE CALLをクリックして通話を開始します。許可ダイアログが表示され、許可を与えると通話が開始されます。

備考:電話番号の定義は、先ほど NCCO

アプリケーションの状態は SdkState.ON_CALLに更新され、UIが更新されます:

On call UI

通話終了

呼び出しを終了するには、ネイティブ・アプリケーションで iOSメソッドをトリガーする必要がある。 platformMethodChannel.インサイド main.dartファイルの内部で _endCallメソッドのボディを更新する:

Future<void> _endCall() async {
    try {
      await platformMethodChannel.invokeMethod('endCall');
    } on PlatformException catch (e) {}
  }

上記のメソッドは iOSと通信するので AppDelegateクラスのコードも更新しなければならない。そのため、クラス内のコードも更新しなければならない。 endCall節を switch文に節を追加する。 addFlutterChannelListenerメソッド内に追加する:

func addFlutterChannelListener() {
        let controller = window?.rootViewController as! FlutterViewController
        
        vonageChannel = FlutterMethodChannel(name: "com.vonage",
                                             binaryMessenger: controller.binaryMessenger)
        vonageChannel?.setMethodCallHandler({ [weak self]
            (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
            guard let self = self else { return }
            
            switch(call.method) {
            case "loginUser":
                if let arguments = call.arguments as? [String: String],
                   let token = arguments["token"] {
                    self.loginUser(token: token)
                }
                result("")
            case "makeCall":
                self.makeCall()
                result("")
            case "endCall":
                self.endCall()
                result("")
            default:
                result(FlutterMethodNotImplemented)
            }
        })
    }

同じクラスに endCallメソッドを追加します:

func endCall() {
        onGoingCall?.hangup()
        onGoingCall = nil
        notifyFlutter(state: .loggedIn)
    }

上記のメソッドは Flutterアプリの状態を SdkState.WAITに設定し Client SDKからのレスポンスを待ちます。どちらのUIステートも Flutterアプリケーション (_updateViewメソッド)。

のボタンを押して通話を終了するようにしました。 END CALLボタンを押すことで FlutterアプリケーションのUIでしかし、通話はアプリの外でも終了できます。 Flutter例えば、通話は拒否されるか、応答され、後で着信側(実際の電話)で終了します。

これらのケースをサポートするには、コールインスタンスに NexmoCallEventListenerリスナーをコールインスタンスに追加し、コール固有のイベントをリッスンする必要がある。

ファイルに AppDelegares.swiftファイルに NXMCallDelegate:

extension AppDelegate: NXMCallDelegate {
    func call(_ call: NXMCall, didUpdate callMember: NXMCallMember, with status: NXMCallMemberStatus) {
        if (status == .completed || status == .cancelled) {
            onGoingCall = nil
            notifyFlutter(state: .loggedIn)
        }
    }
    
    func call(_ call: NXMCall, didUpdate callMember: NXMCallMember, isMuted muted: Bool) {
        
    }
    
    func call(_ call: NXMCall, didReceive error: Error) {
        notifyFlutter(state: .error)
    }
}

上記のリスナーを登録するには onSuccessコールバック makeCallメソッドを修正します:

func makeCall() {
        client.call("IGNORED_NUMBER", callHandler: .server) { [weak self] (error, call) in
            guard let self = self else { return }
            
            if error != nil {
                self.notifyFlutter(state: .error)
                return
            }
            
            self.onGoingCall = call
            self.onGoingCall?.setDelegate(self)
            self.notifyFlutter(state: .onCall)
        }
    }

アプリを起動し、モバイルアプリから物理的な電話番号に電話をかける。

概要

我々はアプリケーションの構築に成功した。そうすることで、モバイル・アプリケーションからVonageを使って電話をかける方法を学びました。 Client SDK.プロジェクト全体については GitHub.このプロジェクトにはさらに、Androidネイティブ・コード (androidフォルダ)が含まれており、Android上でもこのアプリを実行することができます。

その他の機能については、以下を参照してください。 他のチュートリアルおよび Vonage 開発者センター.

参考文献

シェア:

https://a.storyblok.com/f/270183/384x384/8ae5af43bb/igor-wojda.png
Igor Wojdaヴォネージの卒業生