Flutter VoIP通信插件voip24h_sdk_mobile的使用

Flutter VoIP通信插件voip24h_sdk_mobile的使用


Flutter Voip24h-SDK Mobile #

pub package

目录 #

功能 #

功能 描述
CallKit • 登录/登出/刷新SIP账户连接
• 拨打电话/接听来电
• 接受/拒绝/挂断来电
• 暂停/恢复通话
• 保持/取消保持通话
• 开启/关闭麦克风
• 获取麦克风状态
• 开启/关闭扬声器
• 获取扬声器状态
• 转接通话
• 发送DTMF音
Graph • 获取访问令牌
• 请求API(参考https://docs-sdk.voip24h.vn/

要求 #

  • 操作系统平台:
    • Android -> minSdkVersion: 23
    • IOS -> iOS Deployment Target: 9.0
  • 权限:在运行时声明和授权
    • Android: 在文件 AndroidManifest.xml

      <uses-permission android:name="android.permission.INTERNET" />
      <uses-permission android:name="android.permission.RECORD_AUDIO"/>
      
    • IOS: 在文件 Info.plist

      <key>NSAppTransportSecurity</key>
      <dict>
          <key>NSAllowsArbitraryLoads</key><true/>
      </dict>
      <key>NSMicrophoneUsageDescription</key>
      <string>{Your permission microphone description}</string>
      

安装 #

使用终端:

flutter pub add voip24h_sdk_mobile

关联模块:

  • IOS:
    • ios/Podfile 文件中:
      ...
      # 声明库
      platform :ios, '9.0'
      source "https://gitlab.linphone.org/BC/public/podspec.git"
      

      target ‘Your Project’ do … use_frameworks! use_modular_headers!

      flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
      
      # 声明库 
      pod 'linphone-sdk-novideo' , '5.1.36'
      

      end

    • ios 文件夹打开终端,输入以下命令:
      rm -rf Pods/
      pod install
      

模块声明 #

import 'package:voip24h_sdk_mobile/voip24h_sdk_mobile.dart';
import 'package:voip24h_sdk_mobile/callkit/utils/sip_event.dart';
import 'package:voip24h_sdk_mobile/callkit/utils/transport_type.dart';
import 'package:voip24h_sdk_mobile/graph/extensions/extensions.dart';
import 'package:voip24h_sdk_mobile/callkit/model/sip_configuration.dart';

// TODO: 使用模块

CallKit #

  • 声明 sipConfiguration: #

    var sipConfiguration = SipConfigurationBuilder(extension: "extension", domain: "domain", password: "password")
                            .setKeepAlive(true/false) // 可选参数(布尔值)
                            .setPort(port) // 可选参数(整数)
                            .setTransport(TransportType.Udp/TransportType.Tcp/TransportType.Tls) // 可选参数(枚举类型)
                            .build(); 
    
功能
方法和参数
(使用异步/等待或.then来获取返回数据)
返回结果及属性
初始化 Voip24hSdkMobile.callModule.initSipModule(sipConfiguration)
获取SIP账户注册状态 Voip24hSdkMobile.callModule.getSipRegistrationState() value: String
error: String
注销SIP账户 Voip24hSdkMobile.callModule.unregisterSipAccount() value: bool
error: String
刷新SIP账户 Voip24hSdkMobile.callModule.refreshSipAccount() value: bool
error: String
拨打电话 Voip24hSdkMobile.callModule.call(phoneNumber) value: bool
error: String
挂断电话 Voip24hSdkMobile.callModule.hangup() value: bool
error: String
接听来电 Voip24hSdkMobile.callModule.answer() value: bool
error: String
拒绝来电 Voip24hSdkMobile.callModule.reject() value: bool
error: String
转接通话 Voip24hSdkMobile.callModule.transfer("extension") value: bool
error: String
获取通话ID Voip24hSdkMobile.callModule.getCallId() value: String
error: String
获取未接来电数量 Voip24hSdkMobile.callModule.getMissedCalls() value: int
error: String
暂停通话 Voip24hSdkMobile.callModule.pause() value: bool
error: String
恢复通话 Voip24hSdkMobile.callModule.resume() value: bool
error: String
开启/关闭麦克风 Voip24hSdkMobile.callModule.toggleMic() value: bool
error: String
获取麦克风状态 Voip24hSdkMobile.callModule.isMicEnabled() value: bool
error: String
开启/关闭扬声器 Voip24hSdkMobile.callModule.toggleSpeaker() value: bool
error: String
获取扬声器状态 Voip24hSdkMobile.callModule.isSpeakerEnabled() value: bool
error: String
发送DTMF音 Voip24hSdkMobile.callModule.sendDTMF("number#") value: bool
error: String
  • SIP事件监听器: #

    Voip24hSdkMobile.callModule.eventStreamController.stream.listen((event) {
        switch (event['event']) {
            case SipEvent.AccountRegistrationStateChanged: {
                var body = event['body'];
                // TODO
            } break;
            case SipEvent.Ring: {
                // TODO
            } break;
            case ...
              break;
        }
    });
    

    @override void dispose() { Voip24hSdkMobile.callModule.eventStreamController.close(); super.dispose(); }

事件名称
返回结果及属性
属性特性
SipEvent.AccountRegistrationStateChanged body = {
  registrationState: String,
  message: String
}
registrationState: SIP连接状态 (None/Progress/Ok/Cleared/Failed)
message: 描述状态的字符串
SipEvent.Ring body = {
  extension: String,
  phoneNumber: String
  callType: String
}
extension: 分机号
phoneNumber: 来电号码
callType: 通话类型(inbound/outbound)
SipEvent.Up body = {
  callId: String
}
callId: 通话ID
SipEvent.Hangup body = {
  duration: int
}
duration: 通话时长(毫秒)
SipEvent.Paused
SipEvent.Resuming
SipEvent.Missed body = {
  phoneNumber: String,
  totalMissed: int
}
phoneNumber: 来电号码
totalMissed: 总未接来电数
SipEvent.Error body = {
  message: String
}
message: 错误信息

推送通知 #

  • IOS: 我们使用Apple Push Notification service (APNs) 进行后台状态下的来电推送通知
    • 步骤1: 创建APNs Auth Key
      • 访问Apple Developer创建证书
        9
      • 选择VoIP Services Certificate 7
      • 选择你的应用ID。每个想使用VoIP服务的应用都需要单独的VoIP服务证书。VoIP服务证书绑定到应用ID上,允许服务器通知(Voip24h)连接到VoIP服务以向你的应用发送推送通知。
        8
      • 下载证书并用Keychain Access打开
        11
      • 将证书导出为.p12格式
        12
      • 将.p12格式的证书转换为.pem格式并提交给Voip24h配置
        openssl pkcs12 -in path_your_certificate.p12 -out path_your_certificate.pem -nodes
        
  • 步骤2: 配置你的项目以接收来电推送通知 -> 从iOS 10开始,使用CallKit + PushKit

    • Callkit 允许你在你的应用中显示系统级别的通话界面,并协调你的呼叫服务与其它应用和系统。
    • PushKit 支持专门的通知类型以接收VoIP来电。
    • 为了使用CallKit框架+PushKit框架,我们推荐使用库callkeep,在pubspec.yaml中添加:
      dependencies:
          ....
          callkeep:
          git:
            url: https://github.com/Voip24h-Corp/callkeep
            ref: master
      

      然后运行命令:

      flutter pub get
      cd ios
      pod install
      
      • 在你的项目中添加Push Notifications,并选择Voice over IP,Background fetch,Remote notifications,Background processing(Background Modes)。 5 6
      • 当启动应用时,callkeep会为应用客户生成注册令牌。使用该令牌注册到服务器Voip24h
      import 'package:callkeep/callkeep.dart';
      ...
      callKeep.on<CallKeepPushKitToken>((value) => {
        tokenPushIOS = value.token ?? ""
      });
      callKeep.setup(context, <String, dynamic>{
        'ios': {
          'appName': 'Example',
        }
      });
      

      // tokenGraph: 通过API Graph生成的访问令牌 // token: 通过pushkit生成的设备令牌 // sipConfiguration: SIP注册时的参数 // isIOS: 默认为false // appId: iOS应用的Bundle ID // isProduction: true(生产环境) / false(开发环境) // deviceMac: 设备MAC地址

      Voip24hSdkMobile.pushNotificationModule.registerPushNotification( tokenGraph: tokenGraph, token: tokenPushIOS, sipConfiguration: sipConfiguration, isIOS: true, appId: packageInfo.packageName, isProduction: false, deviceMac: iosDeviceInfo.identifierForVendor ).then((value) => { print(value) }, onError: (error) => { print(error) });

      必须在使用推送通知功能前在iOS上授予通知权限。

      • 注册接收来自Voip24h服务器的推送通知

      • 重要提示: 接收到来自Voip24h服务器的推送通知后,根据上述的Callkit和PushKit机制,你必须首先显示系统的通话界面(假的通话),然后立即重新登录分机以接收来自Voip24h的真实通话信号,此时所有如接听/拒绝等通话操作才能正常工作。

      callKeep.on<CallKeepReceivedPushNotification>((value) => {
        callId = value.callId ?? "",
        testCallKit()
      });
      callKeep.on<CallKeepPerformAnswerCallAction>((value) => {
        answer()
      });
      callKeep.on<CallKeepPerformEndCallAction>((value) => {
        reject()
      });
      
      • 取消注册接收推送通知
      Voip24hSdkMobile.pushNotificationModule.unregisterPushNotification(
          sipConfiguration: sipConfiguration,
          isIOS: true,
          appId: packageInfo.packageName
      ).then((value) => {
        print(value)
      }, onError: (error) => {
        print(error)
      });
      
    • Android: 我们使用Firebase Cloud Messaging (FCM) 进行后台状态下的来电推送通知
      • 步骤1: 创建API Token
        • Firebase控制台创建一个项目
          1
        • 注册Android应用
          2
          • 下载google-services.json文件并将其添加到你的应用项目中
            3
        • 在Firebase项目设置中创建Cloud Messaging API (Legacy) Token,并将此Token提交给Voip24h进行配置
          4
      • 步骤2: 配置你的项目以接收来电推送通知 -> 我们建议你使用库Firebase Messaging
        • Flutter包:
        flutter pub add firebase_core
        flutter pub add firebase_messaging
        

        根据Firebase Messaging文档配置你的项目

        • 当启动应用时,Firebase Messaging会为应用客户生成注册令牌。使用该令牌注册到服务器Voip24h
          String? token = await messaging.getToken();
            ....
          if(token != null) {
              // tokenGraph: 通过API Graph生成的访问令牌
          // token: 通过Firebase生成的设备令牌
          // sipConfiguration: SIP注册时的参数
          // isAndroid: 默认为false
          // appId: Android应用的包名
          // isProduction: true(生产环境) / false(开发环境)
          // deviceMac: 设备MAC地址
          

          Voip24hSdkMobile.pushNotificationModule.registerPushNotification( tokenGraph: tokenGraph, token: token, sipConfiguration: sipConfiguration, isAndroid: true, appId: packageInfo.packageName, isProduction: false, deviceMac: androidDeviceInfo.androidId ).then((value) => { print(value) }, onError: (error) => { print(error) }); }

          • 从Android 13 (SDK 32) 开始,接收推送通知需要请求通知权限 https://developer.android.com/develop/ui/views/notifications/notification-permission。请确保在使用前请求POST_NOTIFICATIONS权限。
            • 配置接收推送通知。当收到推送通知时,请重新注册分机以接收来电信号
              [@pragma](/user/pragma)('vm:entry-point')
              Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
              if(Platform.isAndroid) {
              print("Handling a background message: ${message.data}");
              await Firebase.initializeApp().whenComplete(() => {
                localNotificationService.initialNotification().then((value) => {
              // register sip account here
                })
              });
              }
              }
              
            • 取消注册接收推送通知
            Voip24hSdkMobile.pushNotificationModule.unregisterPushNotification(
                sipConfiguration: sipConfiguration,
                isAndroid: true,
                appId: packageInfo.packageName
            ).then((value) => {
              print(value)
            }, onError: (error) => {
              print(error)
            });
            

      Graph #

      • key和security certificate由Voip24h提供
      • 请求API: 方法,端点。数据主体可参考https://docs-sdk.voip24h.vn/文档

      功能
      方法
      参数说明
      返回结果
      返回结果属性
      获取访问令牌 Voip24hSdkMobile.graphModule.getAccessToken(apiKey: API_KEY, apiSecert: API_SECERT) • apiKey: String,
      • secert: String
      value: Oauth
      error: String
      • Oauth: 包含的属性 (token, createAt, expired, isLongAlive)
      • error: 错误信息
      请求API Voip24hSdkMobile.graphModule.sendRequest(token: token, endpoint: endpoint, body: body) • method: MethodRequest(MethodRequest.POST, MethodRequest.GET,...)
      • endpoint: 请求URL的末尾部分:"call/find", "call/findone",...
      • token: 访问令牌
      • params: 数据主体对象如 { "offset": "0", "limit": "25" }
      value: Map<String, dynamic>
      error: String
      • value: 返回结果的形式为键值对
      • error: 错误码
      获取数据对象 value.getData()
      (扩展函数形式)
      object: Object object包含的数据属性可参考https://docs-sdk.voip24h.vn/文档中的返回结果描述
      获取数据对象列表 value.getDataList()
      (扩展函数形式)
      List<Object> 每个object包含的数据属性可参考https://docs-sdk.voip24h.vn/文档中的返回结果描述
      获取状态码 value.statusCode()
      (扩展函数形式)
      int 状态码
      获取消息 value.message()
      (扩展函数形式)
      String 描述状态的字符串
      获取限制 value.limit()
      (扩展函数形式)
      int 找到数据的数量限制
      获取偏移量 value.offset()
      (扩展函数形式)
      int 找到数据的起始位置
      获取总数 value.total()
      (扩展函数形式)
      int 数据的总数量
      获取排序方式 value.isSort()
      (扩展函数形式)
      String 数据的排序方式


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

1 回复

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


当然,以下是一个关于如何在Flutter项目中使用voip24h_sdk_mobile插件进行VoIP通信的示例代码。请注意,这只是一个基本的示例,具体实现可能需要根据您的实际需求进行调整。同时,确保您已经按照插件的官方文档完成了必要的配置和权限申请。

首先,您需要在pubspec.yaml文件中添加voip24h_sdk_mobile插件的依赖:

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

然后,运行flutter pub get来安装依赖。

接下来,我们需要在Flutter项目中初始化VoIP SDK,并进行基本的通话操作。以下是一个示例代码:

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: VoIPPage(),
    );
  }
}

class VoIPPage extends StatefulWidget {
  @override
  _VoIPPageState createState() => _VoIPPageState();
}

class _VoIPPageState extends State<VoIPPage> {
  VoIP24hSdk? voipSdk;

  @override
  void initState() {
    super.initState();
    // 初始化VoIP SDK
    initVoIPSdk();
  }

  void initVoIPSdk() async {
    // 替换为您的API Key和Secret
    String apiKey = "YOUR_API_KEY";
    String apiSecret = "YOUR_API_SECRET";

    voipSdk = VoIP24hSdk(apiKey: apiKey, apiSecret: apiSecret);

    // 注册VoIP回调(例如来电、挂断等)
    voipSdk?.setCallEventListener((callEvent) {
      if (callEvent.type == CallEventType.Incoming) {
        // 处理来电
        showDialog(
          context: context,
          builder: (context) => AlertDialog(
            title: Text("来电"),
            content: Text("来自: ${callEvent.callerId}"),
            actions: [
              TextButton(
                onPressed: () {
                  // 拒绝来电
                  voipSdk?.rejectCall(callEvent.callId);
                  Navigator.of(context).pop();
                },
                child: Text("拒绝"),
              ),
              TextButton(
                onPressed: () {
                  // 接听来电
                  voipSdk?.acceptCall(callEvent.callId);
                  Navigator.of(context).pop();
                },
                child: Text("接听"),
              ),
            ],
          ),
        );
      } else if (callEvent.type == CallEventType.Ended) {
        // 处理通话结束
        print("通话结束: ${callEvent.callId}");
      }
    });

    // 注册VoIP服务(确保在后台运行时也能接收来电)
    await voipSdk?.registerVoIPService();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("VoIP通信示例"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TextButton(
              onPressed: () async {
                // 发起通话(替换为实际的被叫号码)
                String calleeId = "callee_id";
                await voipSdk?.makeCall(calleeId);
              },
              child: Text("发起通话"),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    // 注销VoIP服务并释放资源
    voipSdk?.unregisterVoIPService();
    voipSdk = null;
    super.dispose();
  }
}

在这个示例中,我们完成了以下操作:

  1. pubspec.yaml中添加了voip24h_sdk_mobile插件的依赖。
  2. VoIPPage中初始化了VoIP SDK,并设置了来电回调。
  3. 提供了发起通话和接听/拒绝来电的基本功能。
  4. dispose方法中注销了VoIP服务并释放了资源。

请注意,这只是一个基本的示例。在实际应用中,您可能还需要处理更多的细节,如音频管理、UI优化、错误处理等。同时,确保您已经阅读并理解了voip24h_sdk_mobile插件的官方文档,以便更好地集成和使用该插件。

回到顶部