Flutter语音通信插件twilio_voice_mimp的使用

Flutter语音通信插件twilio_voice_mimp的使用

提供了与Twilio的Programmable Voice SDK接口,允许将VoIP(Voice over Internet Protocol)通话集成到您的Flutter应用程序中。

此插件是从原始的flutter_twilio_voice分离出来的,因为它似乎不再被维护。此插件将继续维护。

特性

  • 在iOS设备上接收和拨打电话,使用CallKit接收来电。
  • 在Android设备上接收和拨打电话,使用自定义UI接收来电。

Android限制

由于iOS有CallKit(苹果提供的接听电话的UI),而安卓没有默认的UI来接收来电,因此为安卓制作了默认的UI。为了增加可定制性,UI将使用在res/drawable文件夹注册的splash_icon.png图标。如果找到一种定制颜色的方法,请提交一个Pull Request。

设置

请遵循Twilio的快速设置指南进行每个平台的设置。虽然不需要编写原生代码,但可以帮助您了解如何设置服务器、为iOS应用注册VOIP等基本功能。

iOS设置

要自定义CallKit调用时显示的图标,请打开XCode并添加一个名为callkit_icon的png图标到您的assets.xassets文件夹。

Android设置

AndroidManifest.xml中注册负责显示来电通知的服务:

<Application>
  .....
  <service
      android:name="com.twilio.twilio_voice.fcm.VoiceFirebaseMessagingService"
      android:stopWithTask="false">
      <intent-filter>
          <action android:name="com.google.firebase.MESSAGING_EVENT" />
      </intent-filter>
  </service>
</Application>

使用

该插件分为两个类:TwilioVoice.instanceTwilioVoice.instance.call。前者负责一般配置,后者负责管理通话。

注册iOS能力

  • 添加音频和VoIP背景模式。

TwilioVoice.instance

设置令牌

当应用启动时,调用TwilioVoice.instance.setTokens

  • accessToken:从服务器提供的访问令牌,您可以查看示例云函数这里
  • deviceToken:iOS上自动处理,对于Android,您需要传递FCM令牌。

调用TwilioVoice.instance.unregister以注销Twilio,如果没有访问令牌,则将使用在setTokens中提供的同一会话中的令牌。

呼叫标识符

由于来电UI在后台显示,甚至在接收到呼叫时应用可以关闭,您可以将呼叫标识符(如firebaseAuth用户ID)映射到真实名称。此操作必须在实际接收呼叫之前完成。因此,如果您有一个聊天应用,并且知道成员的名字,可以注册它们,以便当他们呼叫时,呼叫UI可以显示他们的名字而不是用户ID。

注册客户端

TwilioVoice.instance.registerClient(String clientId, String clientName);

取消注册客户端

TwilioVoice.instance.unregisterClient(String clientId);

默认来电者

您还可以设置一个默认来电者,例如“未知号码”或“聊天朋友”,以防来电来自未注册的客户端。

TwilioVoice.instance.setDefaultCallerName(String callerName);

呼叫事件

使用流TwilioVoice.instance.callEventsListener接收来自TwilioSDK的事件,例如呼叫事件和日志。这是一个广播,因此可以在应用的不同部分监听它。当应用未启动时,可能会错过某些事件,请参阅示例项目以查找解决方法。

发送的事件包括:

  • ringing(响铃)
  • connected(已连接)
  • callEnded(呼叫结束)
  • unhold(取消保持)
  • hold(保持)
  • unmute(取消静音)
  • mute(静音)
  • speakerOn(扬声器开启)
  • speakerOff(扬声器关闭)
  • log(日志)
  • answer(接听)

显示未接来电通知

默认情况下,在用户错过呼叫后,会向用户显示本地通知。点击通知将回拨用户。要移除此功能,请将showMissedCallNotifications设置为false

呼叫

拨打呼叫

await TwilioVoice.instance.call.place(from: myId, to: clientId, extraOptions);

静音呼叫

TwilioVoice.instance.call.toggleMute(isMuted: true);

切换扬声器

TwilioVoice.instance.call.toggleSpeaker(speakerIsOn: true);

挂断

TwilioVoice.instance.call.hangUp();

发送数字

TwilioVoice.instance.call.sendDigits(String digits);

权限

麦克风

接收和拨打呼叫需要麦克风权限,在iOS的info.plist中注册麦克风权限。

您可以使用TwilioVoice.instance.hasMicAccessTwilioVoice.instance.requestMicAccess检查和请求权限。在接收到呼叫时也会自动请求权限。

后台呼叫(仅限Android某些设备)

小米设备等可能需要特殊权限才能接收后台呼叫。使用TwilioVoice.instance.requiresBackgroundPermissions检查您的设备是否需要特殊权限,如果需要,请解释用户为什么需要此权限。最后调用TwilioVoice.instance.requestBackgroundPermissions,这将引导用户到应用设置页面以启用权限。

本地化

由于一些UI是原生代码,因此您需要在项目中本地化这些字符串。您可以在示例项目中找到西班牙语的本地化,欢迎其他语言的PR。


Twilio设置/快速入门帮助

Twilio使用云函数生成访问令牌并将其发送到您的应用。此外,Twilio还使用自己的应用程序TwiML来处理呼叫功能等。

要设置Twilio,有两个主要组件:

  1. 云函数(生成访问令牌和处理呼叫请求的功能)
  2. 移动应用(接收/更新令牌并执行实际呼叫)

1) 云函数

云函数可以分开或组合在一起。主要的两个组件是:

  • 生成访问令牌
  • make-call端点以实际拨打电话

您可以将两者托管在Firebase,TwiML应用程序或混合使用。以下设置假设是混合方式,其中Firebase Functions托管access-token以方便与Flutter集成,TwiML托管make-call函数。

云函数步骤1:创建您的TwiML应用

这将允许您实际拨打电话。

先决条件

应用程序设置

从GitHub获取这个项目,即示例TwiML应用。

cp .env.example .env

编辑.env文件,使用上面收集的三个配置参数。

见配置环境下的详细信息

接下来,我们需要从npm安装依赖项:

npm install

为了简化您的工作,进入src/文件夹,将server.js文件重命名为make-call。这假设每个函数都有自己的文件,这对于新项目来说是个不错的想法。

然后添加以下代码:

const AccessToken = require('twilio').jwt.AccessToken;
const VoiceGrant = AccessToken.VoiceGrant;
const VoiceResponse = require('twilio').twiml.VoiceResponse;

/**
 * 创建一个端点,可以用作TwiML App的语音请求URL。
 * 
 * 为了使用Twilio Voice SDK拨打电话,您需要在访问令牌中提供TwiML App SID。您可以运行您的服务器,使其公开可用,并将`/makeCall`端点作为TwiML App的语音请求URL。
 *
 * @returns {Object} - 用于响应出站呼叫的Response对象
 * @param context
 * @param event
 * @param callback
 */
exports.handler = function(context, event, callback) {
    // 调用的接收者,一个电话号码或客户端

    console.log(event);
    const from = event.From;
    let to = event.to;
    if(isEmptyOrNull(to)) {
        to = event.To;
        if(isEmptyOrNull(to)) {
            console.error("无法找到要呼叫的人");
            to = undefined;
        }
    }

    const voiceResponse = new VoiceResponse();

    if (!to) {
        voiceResponse.say("欢迎,您刚刚打了第一个电话。");
    } else if (isNumber(to)) {
      const dial = voiceResponse.dial({callerId : callerNumber});
      dial.number(to);
  } else {
        console.log(`正在呼叫 [${from}] -> [${to}]`);

        const dial = voiceResponse.dial({callerId: to, timeout: 30, record: "record-from-answer-dual", trim: "trim-silence"});
        dial.client(to);
    }

    callback(null, voiceResponse);
}

const isEmptyOrNull = (s) => {
    return !s || s === '';
}

安装Twilio CLI

确保您已登录到twilio-cli。首先,使用以下命令安装twilio-cli

npm i twilio-cli -g

之后,使用以下命令登录到Twilio(请提供Twilio账户SID和AuthToken):

twilio login

我们需要生成一个应用,这将给我们一个App SID,稍后在Firebase函数中使用(见此处了解更多详情)。

创建TwiML应用

我们需要创建一个TwiML应用,这将允许我们托管make-call函数:

twilio api:core:applications:create \
--friendly-name=my-twiml-app \
--voice-method=POST \
--voice-url="https://my-quickstart-dev.twil.io/make-call"

这将为您提供一个格式为APxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx的应用程序SID,我们将稍后在Firebase配置和生成推送凭证密钥中使用它。

非常重要! 这里提供的URL https://my-quickstart-dev.twil.io/make-call 对您无效。一旦部署了您的TwiML应用(稍后),您将获得一个URL(首次部署时),您需要复制并粘贴为您的请求URL。如果不这样做,呼叫将无法正常工作!

配置环境

确保您在项目的根目录下有一个.env文件,与package.json在同一目录下。

接下来,编辑.env文件,格式如下:

ACCOUNT_SID=(插入您的账户SID)
APP_SID=(插入TwiML应用中的App SID,或上述APxxxxx密钥)

API_KEYAPI_KEY_SECRET在这里不是必需的,因为我们不会使用它们。

获取推送凭证

我们将在稍后生成它们

您将获得一个格式为CRxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx的推送凭证SID,将其用于PUSH_CREDENTIAL_SID

部署

现在让我们部署。

请注意: 确保您已经配置好环境

导航到根目录,使用以下命令部署:

twilio serverless:deploy

非常重要! 一旦完成(如果尚未完成),请确保将make-call端点添加到您的Twilio应用的请求URL中。此URL将在部署文本中显示。如果不这样做,呼叫将无法正常工作!

云函数步骤2:设置Firebase和配置

Twilio的配置存储在.runtimeconfig.json中,包含:

"auth_token": "",
"account_sid": "",
"app_sid": "",
"phone": "",
"api_key": "",
"api_key_secret": "",
"android_push_credential": "",
"apple_push_credential_debug": "",
"apple_push_credential_release": ""

注意: 这用于本地模拟器测试,但在您准备上线时,您需要将这些部署到您的Firebase函数应用中。如果不这样做,这将不起作用!

推送凭证是一次性创建的(针对iOS和Android),用于生成access-token,这是所有Twilio应用用于其通信的回调函数。


以下是生成推送凭证所需的三个操作,这些推送凭证应添加到上述.runtimeconfig.json

Android

要生成Android推送凭证,请从Firebase FCM获取Cloud Messaging服务器密钥,并将其添加到以下内容:

twilio api:chat:v2:credentials:create \
--type=fcm \
--friendly-name="voice-push-credential-fcm" \
--secret=SERVER_KEY_VALUE

然后将其放入字段:android_push_credential

这将生成一个格式为CRxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx的推送凭证SID,必须用于生成Android设备的访问令牌。

有关更多信息,请参阅:https://github.com/twilio/voice-quickstart-android#7-create-a-push-credential-using-your-fcm-server-key

iOS

类似于Android,但步骤更多,包括使用.p12证书。要获取这些证书,请登录到Apple开发者网站并转到证书页面。您需要生成一个VoIP服务证书,如下所示。

请注意: 有两种不同的模式:沙盒和生产。

- 沙盒模式

使用沙盒VoIP证书:

$ openssl pkcs12 -in PATH_TO_YOUR_SANDBOX_P12 -nokeys -out sandbox_cert.pem -nodes
$ openssl pkcs12 -in PATH_TO_YOUR_SANDBOX_P12 -nocerts -out sandbox_key.pem -nodes
$ openssl rsa -in sandbox_key.pem -out sandbox_key.pem

使用沙盒证书生成凭证:

twilio api:chat:v2:credentials:create \
--type=apn \
--sandbox \
--friendly-name="voice-push-credential (sandbox)" \
--certificate="$(cat PATH_TO_SANDBOX_CERT_PEM)" \
--private-key="$(cat PATH_TO_SANDBOX_KEY_PEM)"

然后将其放入字段apple_push_credential_debug

- 生产模式

使用生产VoIP证书:

$ openssl pkcs12 -in PATH_TO_YOUR_P12 -nokeys -out prod_cert.pem -nodes
$ openssl pkcs12 -in PATH_TO_YOUR_P12 -nocerts -out prod_key.pem -nodes
$ openssl rsa -in prod_key.pem -out prod_key.pem

使用生产证书生成凭证:

twilio api:chat:v2:credentials:create \
--type=apn \
--friendly-name="voice-push-credential (production)" \
--certificate="$(cat PATH_TO_PROD_CERT_PEM)" \
--private-key="$(cat PATH_TO_PROD_KEY_PEM)"

然后将其放入字段apple_push_credential_release

有关更多信息,请参阅:https://github.com/twilio/voice-quickstart-ios#6-create-a-push-credential-with-your-voip-service-certificate


云函数步骤3:通过云函数生成访问令牌

GET api-voice-accessToken

要生成access-tokens,将使用以下Firebase函数:

请注意,默认的有效期为1小时。

有关更多信息,请参阅:https://github.com/twilio/voice-quickstart-android/blob/master/Docs/access-token.md

Firebase Cloud Function: access-token

const { AccessToken } = require('twilio').jwt;
const functions = require('firebase-functions');

const { VoiceGrant } = AccessToken;

/**
 * 使用您的Twilio凭据创建带有VoiceGrant的访问令牌。
 *
 * @param {Object} request - 提供呼叫接收者的POST或GET请求,一个电话号码或客户端
 * @param {Object} response - HTTP请求的响应对象
 * @returns {string} - 访问令牌字符串及其过期日期(毫秒)
 */
exports.accessToken = functions.https.onCall((payload, context) => {
    // 检查用户是否已认证
    if (typeof (context.auth) === 'undefined') {
        throw new functions.https.HttpsError('unauthenticated', '该函数必须在认证后调用');
    }
    let userId = context.auth.uid;

    console.log('为', userId, '创建访问令牌');

    // 使用Firebase环境变量进行配置
    const twilioConfig = functions.config().twilio;
    const accountSid = twilioConfig.account_sid;
    const apiKey = twilioConfig.api_key;
    const apiSecret = twilioConfig.api_key_secret;
    const outgoingApplicationSid = twilioConfig.app_sid;

    // 专门用于创建语音令牌,我们需要为每个平台使用单独的推送凭证。
    // iOS有不同的APNs环境,所以我们需要区分沙盒和生产,因为一个不能在另一个环境中工作。
    let pushCredSid;
    if (payload.isIOS === true) {
        console.log('为iOS创建访问令牌');
        pushCredSid = payload.production ? twilioConfig.apple_push_credential_release
            : (twilioConfig.apple_push_credential_debug || twilioConfig.apple_push_credential_release);
    } else if (payload.isAndroid === true) {
        console.log('为Android创建访问令牌');
        pushCredSid = twilioConfig.android_push_credential;
    } else {
        throw new functions.https.HttpsError('unknown_platform', '未指定平台');
    }

    // 生成有效期为24小时的令牌 - 最小3分钟,最大24小时,默认1小时
    const dateTime = new Date();
    dateTime.setDate(dateTime.getDate() + 1);
    // 创建一个访问令牌,我们将对其进行签名并返回给客户端,
    // 包含我们刚创建的授予
    const voiceGrant = new VoiceGrant({
        outgoingApplicationSid,
        pushCredentialSid: pushCredSid,
    });

    // 创建一个访问令牌,我们将对其进行签名并返回给客户端,
    // 包含我们刚创建的授予
    const token = new AccessToken(accountSid, apiKey, apiSecret);
    token.addGrant(voiceGrant);

    // 使用Firebase ID作为身份
    token.identity = userId;
    console.log(`Token:${token.toJwt()}`);

    // 返回JSON对象
    return {
        "jwt_token": token.toJwt(),
        "expiry_date": dateTime.getTime()
    };
});

将上述函数添加到您的Firebase Functions应用中,详见创建Firebase Functions项目的帮助文档。

完成后,部署您的.runtimeconfig.json,详见环境配置的帮助文档。

完成以上所有操作后,使用以下命令部署您的Firebase函数:

firebase deploy --only functions

更多关于Flutter语音通信插件twilio_voice_mimp的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter语音通信插件twilio_voice_mimp的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用 twilio_voice_mimp 插件进行 Flutter 语音通信的基本代码示例。这个插件允许你在 Flutter 应用中实现 Twilio 的语音通信功能。请注意,这只是一个基本的实现示例,你可能需要根据实际需求进行进一步的配置和优化。

首先,你需要在你的 Flutter 项目中添加 twilio_voice_mimp 插件。你可以通过在你的 pubspec.yaml 文件中添加以下依赖项来完成这一步:

dependencies:
  flutter:
    sdk: flutter
  twilio_voice_mimp: ^最新版本号  # 请替换为实际的最新版本号

然后,运行 flutter pub get 来获取依赖项。

接下来,在你的 Flutter 应用中实现 Twilio 语音通信。以下是一个基本的实现示例:

  1. 配置 Twilio 凭证

    你需要在你的 Flutter 应用中配置 Twilio 的 Account SID 和 Auth Token。这些信息通常是从你的 Twilio 控制台获取的。

    import 'package:twilio_voice_mimp/twilio_voice_mimp.dart';
    
    void configureTwilio() {
      TwilioVoiceMimp.configure(
        accountSid: '你的Account SID',  // 替换为你的Twilio Account SID
        authToken: '你的Auth Token',    // 替换为你的Twilio Auth Token
      );
    }
    
  2. 初始化 Twilio 语音通信

    在你的应用启动时,调用 configureTwilio 方法来初始化 Twilio 语音通信。

    void main() {
      WidgetsFlutterBinding.ensureInitialized();
      configureTwilio();
      runApp(MyApp());
    }
    
  3. 拨打电话

    你可以使用 TwilioVoiceMimp.call 方法来拨打电话。

    import 'package:flutter/material.dart';
    
    void makeCall(String toPhoneNumber) {
      TwilioVoiceMimp.call(
        to: toPhoneNumber,  // 替换为你要拨打的电话号码
        from: '你的Twilio Phone Number',  // 替换为你的Twilio 电话号码
      ).then((callSid) {
        print('Call SID: $callSid');
      }).catchError((error) {
        print('Error making call: $error');
      });
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: Text('Twilio Voice Example'),
            ),
            body: Center(
              child: ElevatedButton(
                onPressed: () {
                  makeCall('+1234567890');  // 替换为实际的电话号码
                },
                child: Text('Make Call'),
              ),
            ),
          ),
        );
      }
    }
    
  4. 接听电话(可选):

    如果你想处理来电,你需要监听 Twilio 的来电事件。这通常涉及到在后台运行一个服务来监听 Twilio 的 Webhook 请求,并在收到来电时通知你的 Flutter 应用。这超出了这个基本示例的范围,但你可以参考 Twilio 的文档来实现这一功能。

  5. 处理通话状态(可选):

    你还可以监听通话状态的变化,例如通话开始、通话结束等。这可以通过监听 TwilioVoiceMimp 提供的回调来完成。

    TwilioVoiceMimp.onCallStarted.listen((call) {
      print('Call started: ${call.callSid}');
    });
    
    TwilioVoiceMimp.onCallEnded.listen((call) {
      print('Call ended: ${call.callSid}');
    });
    

请注意,这只是一个基本的实现示例,你可能需要根据你的具体需求进行进一步的配置和优化。此外,由于 Twilio 的 API 和插件可能会随时间更新,因此请确保你查阅最新的文档和插件版本。

回到顶部