你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

为呼叫启用推送通知

在这里,我们会了解如何为 Azure 通信服务呼叫启用推送通知。 设置推送通知会使你的用户知道他们何时具有传入呼叫,然后他们可以应答。

推送通知

推送通知使你可以将信息从你的应用程序发送到用户的设备。 可以使用推送通知显示对话、播放声音或将传入呼叫显示进应用 UI 层。 Azure 通信服务提供与 Azure 事件网格Azure 通知中心的集成,使你可以向应用添加推送通知。

TTL 令牌

生存时间 (TTL) 令牌是一种设置,用于确定通知令牌在变得无效之前保持有效的时间长度。 此设置对于用户参与不需要日常交互但长时间仍然重要的应用程序非常有用。

TTL 配置允许管理推送通知的生命周期,从而减少频繁令牌续订的需求,同时确保应用程序与其用户之间的通信通道在长时间内保持开放和可靠。

目前,TTL 的最大值为180 天(15,552,000 秒),最小值为5 分钟(300 秒)。 可以输入此值,并根据需求对其进行相应调整。 如果未提供值,则默认值为24 小时(86,400 秒)

在注册器中保存设备令牌信息时,调用注册推送通知 API 后。 TTL 生命周期结束后,会删除设备终结点信息。 如果这些设备不再调用注册推送通知 API,则这些设备上的任何传入呼叫都不能传递到设备。

如果要撤销标识,则需要遵循此过程,一旦撤销标识,则应删除注册器条目。

注意

对于 CTE(自定义 Teams 终结点),最大 TTL 值为24 小时(86,400 秒),无法增加此值。

先决条件

Azure 通信服务 Web 呼叫 SDK - Web 推送通知快速入门

重要

Azure 通信服务的这一功能目前以预览版提供。

预览版 API 和 SDK 在没有服务级别协议的情况下提供。 建议不要将它们用于生产工作负荷。 某些功能可能不受支持或者已受限。

有关详细信息,请参阅 Microsoft Azure 预览版补充使用条款

Azure 通信服务 Web 呼叫 SDK - Web 推送通知处于公共预览版阶段,并作为 1.12.0-beta.2+ 版本的一部分提供。

请访问我们的 Web 推送通知快速入门教程:https://github.com/Azure-Samples/communication-services-javascript-quickstarts/blob/main/calling-web-push-notifications/README.md

安装 SDK

找到项目级别的 build.gradle 文件,并将 mavenCentral() 添加到 buildscriptallprojects 下的存储库列表中

buildscript {
    repositories {
    ...
        mavenCentral()
    ...
    }
}
allprojects {
    repositories {
    ...
        mavenCentral()
    ...
    }
}

然后,在模块级别的 build.gradle 文件中,将以下行添加到 dependencies 部分

dependencies {
    ...
    implementation 'com.azure.android:azure-communication-calling:1.0.0'
    ...
}

初始化所需的对象

若要创建 CallAgent 实例,必须对 CallClient 实例调用 createCallAgent 方法。 此调用将异步返回 CallAgent 实例对象。

createCallAgent 方法采用 CommunicationUserCredential 作为参数来封装访问令牌

若要访问 DeviceManager,必须先创建 callAgent 实例。 然后,可以使用 CallClient.getDeviceManager 方法获取 DeviceManager

String userToken = '<user token>';
CallClient callClient = new CallClient();
CommunicationTokenCredential tokenCredential = new CommunicationTokenCredential(userToken);
android.content.Context appContext = this.getApplicationContext(); // From within an activity, for instance
CallAgent callAgent = callClient.createCallAgent(appContext, tokenCredential).get();
DeviceManager deviceManager = callClient.getDeviceManager(appContext).get();

若要为主叫方设置显示名称,请使用以下替代方法:

String userToken = '<user token>';
CallClient callClient = new CallClient();
CommunicationTokenCredential tokenCredential = new CommunicationTokenCredential(userToken);
android.content.Context appContext = this.getApplicationContext(); // From within an activity, for instance
CallAgentOptions callAgentOptions = new CallAgentOptions();
callAgentOptions.setDisplayName("Alice Bob");
DeviceManager deviceManager = callClient.getDeviceManager(appContext).get();
CallAgent callAgent = callClient.createCallAgent(appContext, tokenCredential, callAgentOptions).get();

推送通知的其他先决条件

一个 Firebase 帐户,它设置为启用 Cloud Messaging (FCM) 并将 Firebase Cloud Messaging 服务连接到 Azure 通知中心实例。 有关更多详细信息,请参阅通信服务通知。 此外,本教程假定你使用 Android Studio 3.6 或更高版本来构建应用程序。

Android 应用程序需要一组权限才能接收来自 Firebase Cloud Messaging 的通知消息。 在 AndroidManifest.xml 文件中,在 <manifest ...> 后或在 </application> 标记下添加以下权限集。

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />

概述

移动推送通知是移动设备上显示的弹出通知。 对于呼叫,我们将重点介绍 VoIP(Internet 语音协议)推送通知。 我们将注册推送通知、处理推送通知,然后取消注册推送通知。

注意

要注册推送通知和处理自定义 Teams 终结点(CTE) 的推送通知,API 的推送通知是相同的。 还可以在自定义 Teams 终结点 (CTE) 的CommonCallAgentTeamsCallAgent类上调用以下 API。

注册推送通知

若要注册推送通知,应用程序需要使用设备注册令牌在 CallAgent 实例上调用 registerPushNotification()

若要获取设备注册令牌,请在 dependencies 部分添加以下行(如果尚不存在),将 Firebase SDK 添加到应用程序模块的 build.gradle 文件中:

// Add the SDK for Firebase Cloud Messaging
implementation 'com.google.firebase:firebase-core:16.0.8'
implementation 'com.google.firebase:firebase-messaging:20.2.4'

在项目级别的 build.gradle 文件中,将以下内容添加到 dependencies 部分(如果尚不存在)

classpath 'com.google.gms:google-services:4.3.3'

在文件的开头添加以下插件(如果尚不存在):

apply plugin: 'com.google.gms.google-services'

在工具栏中选择“立即同步”。 添加以下代码片段,获取 Firebase Cloud Messaging SDK 为客户端应用程序实例生成的设备注册令牌。请务必将以下导入内容添加到实例主“活动”的标头中。 代码片段检索令牌时需要这些内容:

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.InstanceIdResult;

添加此代码片段以检索令牌:

FirebaseInstanceId.getInstance().getInstanceId()
    .addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
        @Override
        public void onComplete(@NonNull Task<InstanceIdResult> task) {
            if (!task.isSuccessful()) {
                Log.w("PushNotification", "getInstanceId failed", task.getException());
                return;
            }

            // Get new Instance ID token
            String deviceToken = task.getResult().getToken();
            // Log
            Log.d("PushNotification", "Device Registration token retrieved successfully");
        }
    });

在通话服务 SDK 中注册设备注册令牌,以接收来电推送通知:

String deviceRegistrationToken = "<Device Token from previous section>";
try {
    callAgent.registerPushNotification(deviceRegistrationToken).get();
}
catch(Exception e) {
    System.out.println("Something went wrong while registering for Incoming Calls Push Notifications.")
}

处理推送通知

若要接收来电推送通知,请使用有效负载在 CallAgent 实例上调用 handlePushNotification()

若要从 Firebase Cloud Messaging 获取有效负载,请先创建一个新服务(“文件”>“新建”>“服务”>“服务”),该服务可扩展 FirebaseMessagingService Firebase SDK 类并替代 onMessageReceived 方法。 当 Firebase Cloud Messaging 将推送通知传递到应用程序时,此方法被称为事件处理程序。

public class MyFirebaseMessagingService extends FirebaseMessagingService {
    private java.util.Map<String, String> pushNotificationMessageDataFromFCM;

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // Check if message contains a notification payload.
        if (remoteMessage.getNotification() != null) {
            Log.d("PushNotification", "Message Notification Body: " + remoteMessage.getNotification().getBody());
        }
        else {
            pushNotificationMessageDataFromFCM = remoteMessage.getData();
        }
    }
}

将以下服务定义添加到 AndroidManifest.xml 文件的 <application> 标记内:

<service
    android:name=".MyFirebaseMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>
  • 检索到有效负载后,可将其传递给通信服务 SDK 以解析为内部 IncomingCallInformation 对象,该对象将通过在 CallAgent 实例上调用 handlePushNotification 方法进行处理CallAgent 实例是通过在 CallClient 类上调用 createCallAgent(...) 方法来创建的。
try {
    IncomingCallInformation notification = IncomingCallInformation.fromMap(pushNotificationMessageDataFromFCM);
    Future handlePushNotificationFuture = callAgent.handlePushNotification(notification).get();
}
catch(Exception e) {
    System.out.println("Something went wrong while handling the Incoming Calls Push Notifications.");
}

成功处理推送通知消息,且正确注册所有事件处理程序时,应用程序将响铃。

取消注册推送通知

应用程序可以随时取消注册推送通知。 若要取消注册,请在 callAgent 上调用 unregisterPushNotification() 方法。

try {
    callAgent.unregisterPushNotification().get();
}
catch(Exception e) {
    System.out.println("Something went wrong while un-registering for all Incoming Calls Push Notifications.")
}

设置系统

创建 Xcode 项目

在 Xcode 中,创建新的 iOS 项目,并选择“单视图应用”模板。 本快速入门使用 SwiftUI 框架,因此应将“语言”设置为“Swift”,并将“接口”设置为“SwiftUI”

在此快速入门过程中,无需创建测试。 请随意清除“包括测试”复选框

显示用于在 Xcode 中创建项目的窗口的屏幕截图。

使用 CocoaPods 安装包和依赖项

  1. 为应用程序创建 Podfile,如此示例所示:

    platform :ios, '13.0'
    use_frameworks!
    target 'AzureCommunicationCallingSample' do
        pod 'AzureCommunicationCalling', '~> 1.0.0'
    end
    
  2. 运行 pod install

  3. 使用 Xcode 打开 .xcworkspace

请求访问麦克风

若要访问设备的麦克风,需要使用 NSMicrophoneUsageDescription 更新应用的信息属性列表。 将关联的值设置为将要包含在系统用于向用户请求访问权限的对话框中的字符串。

右键单击项目树的 Info.plist 条目,然后选择“打开为...”>“源代码”。 将以下代码行添加到顶层 <dict> 节,然后保存文件。

<key>NSMicrophoneUsageDescription</key>
<string>Need microphone access for VOIP calling.</string>

设置应用框架

打开项目的 ContentView.swift 文件。 将 import 声明添加到文件顶部以导入 AzureCommunicationCalling 库。 此外,导入 AVFoundation。 你将需要用它来处理代码中的音频权限请求。

import AzureCommunicationCalling
import AVFoundation

初始化 CallAgent

若要从 CallClient 创建 CallAgent 实例,必须使用 callClient.createCallAgent 方法,该方法在初始化后异步返回 CallAgent 对象。

若要创建通话客户端,请传递 CommunicationTokenCredential 对象:

import AzureCommunication

let tokenString = "token_string"
var userCredential: CommunicationTokenCredential?
do {
    let options = CommunicationTokenRefreshOptions(initialToken: token, refreshProactively: true, tokenRefresher: self.fetchTokenSync)
    userCredential = try CommunicationTokenCredential(withOptions: options)
} catch {
    updates("Couldn't created Credential object", false)
    initializationDispatchGroup!.leave()
    return
}

// tokenProvider needs to be implemented by Contoso, which fetches a new token
public func fetchTokenSync(then onCompletion: TokenRefreshOnCompletion) {
    let newToken = self.tokenProvider!.fetchNewToken()
    onCompletion(newToken, nil)
}

将创建的 CommunicationTokenCredential 对象传递给 CallClient 并设置显示名称:

self.callClient = CallClient()
let callAgentOptions = CallAgentOptions()
options.displayName = " iOS Azure Communication Services User"

self.callClient!.createCallAgent(userCredential: userCredential!,
    options: callAgentOptions) { (callAgent, error) in
        if error == nil {
            print("Create agent succeeded")
            self.callAgent = callAgent
        } else {
            print("Create agent failed")
        }
})

概述

移动推送通知是移动设备上显示的弹出通知。 对于呼叫,我们将重点介绍 VoIP(Internet 语音协议)推送通知。 我们将注册推送通知、处理推送通知,然后取消注册推送通知。 有关 iOS 应用程序中 CallKit 集成的指南,请参阅此处,CallKit 与 iOS ACS SDK 集成

注意

要注册推送通知和处理自定义 Teams 终结点(CTE) 的推送通知,API 的推送通知是相同的。 还可以在自定义 Teams 终结点 (CTE) 的CommonCallAgentTeamsCallAgent类上调用 API。

设置推送通知

移动推送通知是在移动设备中收到的弹出通知。 对于呼叫,我们将重点介绍 VoIP(Internet 语音协议)推送通知。

以下部分介绍如何注册、处理和取消注册推送通知。 在开始这些任务之前,请先满足以下先决条件:

  1. 在 Xcode 中,转到“签名和功能”。 选择“+功能”来添加一项功能,然后选择“推送通知”
  2. 选择“+功能”来再添加一项功能,然后选择“背景模式”
  3. 在“背景模式”下,选中“IP 语音”和“远程通知”复选框

显示如何在 Xcode 中添加功能的屏幕截图。

注册推送通知

若要注册推送通知,请使用设备注册令牌在 CallAgent 实例上调用 registerPushNotification()

成功初始化后需要注册推送通知。 销毁 callAgent 对象时,将调用 logout,这会自动取消注册推送通知。

let deviceToken: Data = pushRegistry?.pushToken(for: PKPushType.voIP)
callAgent.registerPushNotifications(deviceToken: deviceToken!) { (error) in
    if(error == nil) {
        print("Successfully registered to push notification.")
    } else {
        print("Failed to register push notification.")
    }
}

处理推送通知

若要接收来电推送通知,请使用字典有效负载在 CallAgent 实例上调用 handlePushNotification()

let callNotification = PushNotificationInfo.fromDictionary(pushPayload.dictionaryPayload)

callAgent.handlePush(notification: callNotification) { (error) in
    if (error == nil) {
        print("Handling of push notification was successful")
    } else {
        print("Handling of push notification failed")
    }
}

取消注册推送通知

应用程序可以随时取消注册推送通知。 在 CallAgent 上调用 unregisterPushNotification 方法即可。

注意

注销时,应用程序不会自动取消注册推送通知。

callAgent.unregisterPushNotification { (error) in
    if (error == nil) {
        print("Unregister of push notification was successful")
    } else {
       print("Unregister of push notification failed, please try again")
    }
}

设置系统

创建 Visual Studio 项目

对于 UWP 应用,请在 Visual Studio 2022 中创建新的“空白应用(通用 Windows)”项目。 输入项目名称后,可随意选择任何版本高于 10.0.17763.0 的 Windows SDK。

对于 WinUI 3 应用,请使用“已打包空白应用(桌面中的 WinUI 3)”模板创建新项目,以设置单页 WinUI 3 应用。 需要 Windows App SDK 版本 1.3 或更高版本。

使用 NuGet 包管理器安装包和依赖项

可通过 NuGet 包公开提供通话 SDK API 和库。

以下步骤举例说明了如何查找、下载和安装通话 SDK NuGet 包:

  1. 选择“工具”>“NuGet 包管理器”>“管理解决方案的 NuGet 包”,以打开 NuGet 包管理器
  2. 选择“浏览”,然后在搜索框中输入 Azure.Communication.Calling.WindowsClient
  3. 确保已选中“包括预发行版”复选框
  4. 选择 Azure.Communication.Calling.WindowsClient 包,然后选择 Azure.Communication.Calling.WindowsClient1.4.0-beta.1 或更高版本。
  5. 在右侧选项卡上选中与 Azure 通信服务项目对应的复选框。
  6. 选择“安装”按钮。

概述

Windows 平台上的推送通知使用Windows Push Notification Service (WNS),传递。

注意

要注册推送通知和处理自定义 Teams 终结点(CTE) 的推送通知,API 的推送通知是相同的。 还可以在自定义 Teams 终结点 (CTE) 的CommonCallAgentTeamsCallAgent类上调用以下 API。

设置推送通知

推送通知是在设备中收到的弹出通知。 对于呼叫,我们将重点介绍 VoIP(Internet 语音协议)推送通知。

以下部分介绍如何注册、处理和显示 Windows 通知以接听/拒接传入呼叫。 在开始这些任务之前,请先满足以下先决条件:

  1. 按照教程:使用 Azure 通知中心向通用 Windows 平台应用发送通知中所述进行操作。 按照本教程进行操作后,你已具备:

    • 包含 WindowsAzure.Messaging.ManagedMicrosoft.Toolkit.Uwp.Notifications 包的应用程序。
    • 本快速入门中被称为 <AZURE_PNH_HUB_NAME> 的 Azure PNH(推送通知中心)中心名称以及被称为 <AZURE_PNH_HUB_CONNECTION_STRING> 的 Azure PNH 连接字符串。
  2. 若要在每次应用程序初始化时都注册 WNS(Windows 通知服务)通道,请确保在 App.xaml.cs 文件中添加初始化代码:

// App.xaml.cs

protected override async void OnLaunched(LaunchActivatedEventArgs e)
{
    await InitNotificationsAsync();
    
    ...
}

private async Task InitNotificationsAsync()
{
    if (AZURE_PNH_HUB_NAME != "<AZURE_PNH_HUB_NAME>" && AZURE_PNH_HUB_CONNECTION_STRING != "<AZURE_PNH_HUB_CONNECTION_STRING>")
    {
        var channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();
        channel.PushNotificationReceived += Channel_PushNotificationReceived;
    
        var hub = new NotificationHub(AZURE_PNH_HUB_NAME, AZURE_PNH_HUB_CONNECTION_STRING);
        var result = await hub.RegisterNativeAsync(channel.Uri);
    
        if (result.ChannelUri != null)
        {
            PNHChannelUri = new Uri(result.ChannelUri);
        }
        else
        {
            Debug.WriteLine("Cannot register WNS channel");
        }
    }
}
  1. 在 App.xaml.cs 中注册新的推送通知消息到达时激活的事件处理程序:
// App.xaml.cs

private void Channel_PushNotificationReceived(PushNotificationChannel sender, PushNotificationReceivedEventArgs args)
{
    switch (args.NotificationType)
    {
      case PushNotificationType.Toast:
      case PushNotificationType.Tile:
      case PushNotificationType.TileFlyout:
      case PushNotificationType.Badge:
          break;
      case PushNotificationType.Raw:
          var frame = (Frame)Window.Current.Content;
          if (frame.Content is MainPage)
          {
              var mainPage = frame.Content as MainPage;
              await mainPage.HandlePushNotificationIncomingCallAsync(args.RawNotification.Content);
          }
          break;
    }
}

注册推送通知

若要注册推送通知,请使用在应用程序初始化时获取的 WNS 注册通道对 CallAgent 实例调用 RegisterForPushNotificationAsync()

成功初始化后需要注册推送通知。

// MainPage.xaml.cs

this.callAgent = await this.callClient.CreateCallAgentAsync(tokenCredential, callAgentOptions);
                
if ((Application.Current as App).PNHChannelUri != null)
{
    await this.callAgent.RegisterForPushNotificationAsync((Application.Current as App).PNHChannelUri.ToString());
}

this.callAgent.CallsUpdated += OnCallsUpdatedAsync;
this.callAgent.IncomingCallReceived += OnIncomingCallAsync;

处理推送通知

若要接收来电推送通知,请使用字典有效负载在 CallAgent 实例上调用 handlePushNotification()

// MainPage.xaml.cs

public async Task HandlePushNotificationIncomingCallAsync(string notificationContent)
{
    if (this.callAgent != null)
    {
        PushNotificationDetails pnDetails = PushNotificationDetails.Parse(notificationContent);
        await callAgent.HandlePushNotificationAsync(pnDetails);
    }
}

这会触发 CallAgent 上的一个传入呼叫事件,该事件会显示传入呼叫通知。

// MainPage.xaml.cs

private async void OnIncomingCallAsync(object sender, IncomingCallReceivedEventArgs args)
{
    incomingCall = args.IncomingCall;
    (Application.Current as App).ShowIncomingCallNotification(incomingCall);
}
// App.xaml.cs

public void ShowIncomingCallNotification(IncomingCall incomingCall)
{
    string incomingCallType = incomingCall.IsVideoEnabled ? "Video" : "Audio";
    string caller = incomingCall.CallerDetails.DisplayName != "" ? incomingCall.CallerDetails.DisplayName : incomingCall.CallerDetails.Identifier.RawId;
    new ToastContentBuilder()
    .SetToastScenario(ToastScenario.IncomingCall)
    .AddText(caller + " is calling you.")
    .AddText("New Incoming " + incomingCallType + " Call")
      .AddButton(new ToastButton()
          .SetContent("Decline")
          .AddArgument("action", "decline"))
      .AddButton(new ToastButton()
          .SetContent("Accept")
          .AddArgument("action", "accept"))
      .Show();
}

在 OnActivated 方法中添加用于处理通知的按钮按下事件的代码:

// App.xaml.cs

protected override async void OnActivated(IActivatedEventArgs e)
{   
    // Handle notification activation
    if (e is ToastNotificationActivatedEventArgs toastActivationArgs)
    {
      ToastArguments args = ToastArguments.Parse(toastActivationArgs.Argument);
      string action = args?.Get("action");
    
      if (!string.IsNullOrEmpty(action))
      {
          var frame = Window.Current.Content as Frame;
          if (frame.Content is MainPage)
          {
              var mainPage = frame.Content as MainPage;
              await mainPage.AnswerIncomingCall(action);
          }
      }
    }
}
// MainPage.xaml.cs

public async Task AnswerIncomingCall(string action)
{
    if (action == "accept")
    {
      var acceptCallOptions = new AcceptCallOptions()
      {
          IncomingVideoOptions = new IncomingVideoOptions()
          {
              StreamKind = VideoStreamKind.RemoteIncoming
          }
      };
    
      call = await incomingCall?.AcceptAsync(acceptCallOptions);
      call.StateChanged += OnStateChangedAsync;
      call.RemoteParticipantsUpdated += OnRemoteParticipantsUpdatedAsync;
    }
    else if (action == "decline")
    {
      await incomingCall?.RejectAsync();
    }
}

后续步骤