腾讯云即时通信 IM 的终端用户需要随时都能够得知最新的消息,而由于移动端设备的性能与电量有限,当 App 处于后台时,为了避免维持长连接而导致的过多资源消耗,腾讯云即时通信 IM 推荐您使用各厂商提供的系统级推送通道来进行消息通知,系统级的推送通道相比第三方推送拥有更稳定的系统级长连接,可以做到随时接受推送消息,且资源消耗大幅降低。
说明:
- 在没有主动退出登录的情况下,应用退后台、手机锁屏、或者应用进程被用户主动杀掉三种场景下,如果想继续接收到 IM 消息提醒,可以接入即时通信 IM 离线推送。
- 如果应用主动调用 logout 退出登录,或者多端登录被踢下线,即使接入了 IM 离线推送,也收不到离线推送消息。
使用腾讯云 IM 厂商推送 Flutter 集成插件的离线推送能力,可快速接入主流厂商(苹果iOS/Google FCM/OPPO/VIVO/华为/小米/魅族)的离线推送。
本教程含接入腾讯云即时通信 IM 离线推送全流程。插件已封装上述厂商的 SDK,使用时仅需简单改造调用即可。
如果您的应用不需要离线推送,或场景不满足离线推送的需求,请直接看本文最后一节 “在线推送-在本地创建新消息通知” 在线推送部分。
如果您的应用已经自行完成厂商离线推送,仅需查看本教程 第一步 和 第五步,在控制台内录入厂商信息,并在应用登录后,上报证书 ID 即可。
说明:以下 API 若无特殊说明,均可自动兼容 Android/iOS 平台及支持厂商,插件内部进行平台及厂商判断,您直接调用即可。
API | 说明 |
---|---|
构造函数(TimUiKitPushPlugin) | 实例化一个 Push 插件对象,并确定是否使用 Google Service FCM |
init | 初始化插件,绑定点击通知回调事件及传入厂商渠道信息 |
uploadToken | 自动获取设备 Token 及证书 ID,自动上传至腾讯云 IM 服务端 |
requireNotificationPermission | 申请推送权限 |
setBadgeNum | 设置未读数角标 (仅支持部分 Android 设备,可参见 API 代码参数说明) |
clearAllNotification | 清除通知栏内,当前应用,所有的通知 |
getDevicePushConfig | 获取当前厂商的推送相关信息,含机型/证书 ID/Token |
getDevicePushToken | 获取当前厂商的推送 Token |
getOtherPushType | 获取厂商信息 |
getBuzId | 获取当前厂商对应的腾讯云控制台上注册的证书 ID |
createNotificationChannel | 为Android机型创建通知Channel渠道,详见Google官方文档 |
clearAllNotification | 清除通知栏内,当前应用,所有的通知 |
displayNotification | 在客户端本地,手动创建一条消息通知 |
displayDefaultNotificationForMessage | 在客户端本地,按照默认的规则,自动为一个 V2TimMessage 创建一个消息通知 |
需要完成厂商开发者账号申请(一般需要企业认证),创建应用,申请 PUSH 权限,拿到 key 信息。
前往 Google Firebase控制台 创建一个项目,无需启用 Google Analysis。
单击您的应用卡片,进入应用配置页面。
单击 Project Overview 右侧的 ,选择项目设置>服务帐号,单击生成新的私钥下载私钥文件。
将该私钥文件托管至即时通信 IM 控制台。在 IM 控制台-基础配置 右侧,添加 Android 证书。选择 Google 后,请选择上传证书。
请参见 OPPO PUSH 服务开启指南 注册开发者账号,创建应用,并开通 PUSH 服务。
在 OPPO 推送平台 >配置管理>应用配置页面,您可以查看详细的应用信息。记录 AppId、AppKey、AppSecret 和 MasterSecret 信息。
按照 OPPO 官网要求,在 OPPO Android 8.0 及以上系统版本必须配置 ChannelID,否则推送消息无法展示。您需要先在 App 中创建对应的 ChannelID(例如 tuikit
)。
请在配置管理-新建通道内,创建一个新通道。通道ID即为Channel ID。
说明:OPPO 对于公信通道有每日上限,对于通讯类型消息,建议参见 OPPO 官方文档 申请私信通道。
com.tencent.flutter.tim_ui_kit_push_plugin.pushActivity.OPPOMessageActivity
。打开 小米开放平台官网 进行注册并通过开发者认证。
说明:认证过程大约需要2天左右,请务必提前阅读 小米推送服务启用指南,以免影响您的接入进度。
在小米开放平台创建应用,并选择应用服务>PUSH服务,创建推送服务应用。
小米推送服务应用创建完成后,在应用详情中,您可以查看详细的应用信息。
记录主包名、AppID、AppSecret 信息。
在 IM 控制台-基础配置 右侧,添加 Android 证书。选择小米后,请填写相关信息,行为请选择打开应用。
打开 vivo 开放平台官网 进行注册并通过开发者认证。
说明:认证过程大约需要3天左右,请务必提前阅读 vivo 推送服务说明,以免影响您的接入进度。
登录 vivo 开放平台的管理中心,选择消息推送>创建>测试推送,创建 vivo 推送服务应用。
vivo 推送服务应用创建完成后,在应用详情中,您可以查看详细的应用信息。记录 APP ID、APP key 和 App secret信息。
说明:vivo 要求应用在上架后,才能使用正式推送服务。如果您需要在开发中调试 vivo 机器,请参见本文最后一节 vivo 调试 内容,开启测试模式。
在 IM 控制台-基础配置 右侧,添加 Android 证书。选择 vivo 后,请填写相关信息。
tencent_im_push://${替换成您的包名}/message?#Intent;scheme=tencent_im_push;launchFlags=0x4000000;end
说明:若在应用信息>我的应用中无法找到 SecretKey,可前往项目设置>常规中查看 Client Secret。
获取 SHA256 证书指纹,并在华为推送平台中配置证书指纹,单击 保存。证书指纹获取可参见 生成签名证书指纹。
说明:如果您的应用需要经过流水线编译发布,每次编译在不同的构建机上进行,可在本地创建
keystore.jks
密钥文件,得到该 keystore 的 SHA256 值,填入华为推送平台中。在流水线的构建脚本中,对完成构建后的产物进行归档对齐,及使用刚才的 keystore 签名。此时该最终产物签名 SHA256 值即可保持一致。代码如下:
> zipalign -v -p 4 构建生成的apk.apk 打包生成的apk_aligned.apk
> apksigner sign --ks keystore.jks --ks-pass pass:您创建的keystore密码 --out 最终签名 完成的apk.apk 打包生成的apk_aligned.apk
>
登录华为开放平台,进入我的项目> 选择项目 > 项目设置,下载华为应用最新配置文件 agconnect-services.json。放置于android/app
目录下。
在华为推送平台,单击全部服务>推送服务,进入推送服务页面。
在推送服务页面,单击立即开通,详情请参见 打开推送服务开关。
角标参数
请填写 Android 应用入口 Activity 类,如我们DEMO的 com.tencent.flutter.tuikit
,否则华为通道下发通知的角标设置将不生效。
点击后续动作
请选择打开应用。
打开 魅族开放平台官网 进行注册并通过开发者认证。
说明:认证过程大约需要3天左右,请务必提前阅读 魅族 Flyme 推送接入文档,以免影响您的接入进度。
登录魅族开放平台的管理控制台,选择服务>集成推送服务>推送后台,创建魅族推送服务应用。
魅族推送服务应用创建完成后,在应用详情中,您可以查看详细的应用信息。记录应用包名、App ID、App Secret信息。
在您的项目中安装 IM Flutter 离线推送插件:
flutter pub add tim_ui_kit_push_plugin
在插件市场,启用推送插件。
完成 接入准备(注册厂商)的配置后,可在即时通信 IM 的控制台首页右侧,查看我们后台为您的厂商渠道 App 信息分配的证书 ID。
请将这些信息,配上厂商渠道的账号信息,实例化一个静态的PushAppInfo
类,汇总起来。后续步骤需要传入此对象。
该类支持配置所有您需要接入厂商推送机型的信息。无需完整填写构造函数字段。若需要使用某个厂商平台,请完整填写该平台相关字段。
import 'package:tim_ui_kit_push_plugin/model/appInfo.dart';
static final PushAppInfo appInfo = PushAppInfo(
hw_buz_id: , // 华为证书ID
mi_app_id: , // 小米APPID
mi_app_key: , // 小米APPKey
mi_buz_id: , // 小米证书ID
mz_app_id: , // 魅族APPID
mz_app_key: , // 魅族APPKey
mz_buz_id: , // 魅族证书ID
vivo_buz_id: , // vivo证书ID
oppo_app_key: , // OPPO APPKey
oppo_app_secret: , // OPPO APP Secret
oppo_buz_id: , // OPPO证书ID
oppo_app_id: , // OPPO APPID
google_buz_id: , // Google FCM证书ID
apple_buz_id: , // Apple证书ID
);
说明:可参见我们DEMO lib/utils/push/push_constant.dart文件 中的做法。
如果需要使用 Firebase Emulator Suite,请打开 android/app/src/main/AndroidManifest.xml
文件,在 application
中新增usesCleartextTraffic
字段。
<application
android:usesCleartextTraffic="true" // 增加本行
>
<!-- possibly other elements -->
</application>
firebase_core
的依赖,使用1.12.0版本。说明:由于最新版 Google Firebase Flutter 插件最低支持的Dart版本为2.16.0,此处限制为2022年3月发布的1.12.0版本。
dependencies:
firebase_core: 1.12.0
执行flutter pub get
完成安装。
在控制台内,执行以下命令,结合操作提示,完成配置 Google Firebase Flutter 项目。
详见 Google FlutterFire 官方文档。
// 安装Firebase CLI
npm install -g firebase-tools
curl -sL https://firebase.tools | bash
dart pub global activate flutterfire_cli
// 生成配置文件
flutterfire configure
执行该步骤后,会将此项目与您在 Google Firebase 创建的项目关联起来。main()
方法中初始化 FirebaseAPP。
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
isUseGoogleFCM
字段设为 false 即可。打开文件 android/build.gradle
。
buildscript>repositories & dependencies下分别添加华为仓库地址和 HMS gradle 插件依赖:
buildscript {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'} // 添加华为 maven 仓库地址
}
dependencies {
// 其他classpath配置
classpath 'com.huawei.agconnect:agcp:1.3.1.300' // 添加华为推送 gradle 插件依赖
}
// Set release signing and passwords in the same build configuration file
signingConfigs {
release {
storeFile file('<keystore_file>')
storePassword '<keystore_password>'
keyAlias '<key_alias>'
keyPassword '<key_password>'
}
}
buildTypes {
// debug模式也要使用证书编译,否则华为指纹验证不通过
debug {
signingConfig signingConfigs.release
}
release {
signingConfig signingConfigs.release
}
}
}
打开 android/build.gradle
文件,在allprojects>repositories下添加华为依赖仓库地址:
allprojects {
repositories {
google()
jcenter()
maven {url 'https://developer.huawei.com/repo/'} // 添加华为 maven 仓库地址
}
}
android/app
目录下。打开 android/app/build.gradle
文件,添加以下配置:
// app 其他 gradle 插件
apply plugin: 'com.huawei.agconnect' // HMS SDK gradle 插件
android {
// app 配置内容
}
打开 android/app/src/main/AndroidManifest.xml
文件,如下添加 uses-permission 。
<uses-permission android:name = "com.huawei.android.launcher.permission.CHANGE_BADGE "/>
<uses-permission android:name = "com.hihonor.android.launcher.permission.CHANGE_BADGE" />
打开 android/app/build.gradle
文件,如下配置 vivo 的 APPID 和 App_Key。
android: {
defaultConfig {
manifestPlaceholders = [
....
vivo_APPID: "vivo的APPID"
vivo_APPKEY:"vivo的APP_Key",
.....
]
}
}
打开 android/app/src/main/AndroidManifest.xml
文件,在 <application>
中,如下添加meta-data。
<meta-data
android:name="com.vivo.push.api_key"
android:value="填入您申请的vivo API_KEY" />
<meta-data
android:name="com.vivo.push.app_id"
android:value="填入您申请的vivo API_ID" />
</application>
打开 android/app/src/main/AndroidManifest.xml
文件,如下添加 uses-permission 。
<uses-permission android:name="com.vivo.notification.permission.BADGE_ICON" />
打开 android/app/build.gradle
文件,在 defaultConfig
中加入包名。
defaultConfig {
applicationId "${替换成您的包名}"
...
}
打开 android/app/src/main/AndroidManifest.xml
文件,配置各厂商权限列表。
<!--小米 开始-->
<permission
android:name="${替换成您的包名}.permission.MIPUSH_RECEIVE"
android:protectionLevel="signature" />
<uses-permission android:name="${替换成您的包名}.permission.MIPUSH_RECEIVE" />
<!--小米 结束-->
<!--OPPO 开始-->
<uses-permission android:name="com.coloros.mcs.permission.RECIEVE_MCS_MESSAGE" />
<uses-permission android:name="com.heytap.mcs.permission.RECIEVE_MCS_MESSAGE" />
<!--OPPO 结束-->
<!--魅族 开始-->
<!-- 可选,用于兼容 Flyme5 且推送服务是旧版本的情况-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 兼容 Flyme5 的权限配置-->
<uses-permission android:name="com.meizu.flyme.push.permission.RECEIVE" />
<permission android:name="${替换成您的包名}.push.permission.MESSAGE"
android:protectionLevel="signature"/>
<uses-permission android:name="${替换成您的包名}.push.permission.MESSAGE" />
<!-- 兼容 Flyme3 的权限配置-->
<uses-permission android:name="com.meizu.c2dm.permission.RECEIVE" />
<permission android:name="${替换成您的包名}.permission.C2D_MESSAGE" android:protectionLevel="signature"
/>
<uses-permission android:name="${替换成您的包名}.permission.C2D_MESSAGE"/>
<!--魅族 结束-->
init
方法。该步骤会完成初始化各厂商通道。说明:由于国内大部分 Android 设备不支持 Google Service, 因此提供一个开关
isUseGoogleFCM
供开发者根据主要用户群体判断,是否启用 Google Firebase Cloud Messaging 推送服务。
import 'package:tim_ui_kit_push_plugin/tim_ui_kit_push_plugin.dart';
final TimUiKitPushPlugin cPush = TimUiKitPushPlugin(
isUseGoogleFCM: bool, // 是否启用Google Firebase Cloud Messaging,默认true启用
);
cPush.init(
pushClickAction: pushClickAction, // 单击通知后的事件回调,会在STEP6讲解
appInfo: PushConfig.appInfo, // 传入STEP1做的appInfo
);
初始化结束后,需要为部分厂商创建消息通道,如OPPO和小米均需此配置。调用createNotificationChannel
方法即可。
说明:如果向厂商申请的 channel ID 一致,同一个 channel ID 调用一次即可。
cPush.createNotificationChannel(
channelId: "new_message",
channelName: "消息推送",
channelDescription: "推送新聊天消息");
部分厂商(如 OPPO)默认不提供推送权限,需要开发者手动申请。调用requireNotificationPermission
方法即可。
说明:申请权限的时机可由您自行决定,您可以在用户登录成功后再调用。
cPush.requireNotificationPermission();
需要将当前设备对应厂商的证书 ID 及 Device Token 上报至腾讯云即时通信后台,服务端才可正常使用厂商通道下行通知。
插件支持自动在appInfo内找到当前厂商的证书ID,并自动完成Token上报。
说明:
- 根据个保法内隐私相关规定,请在用户Login后再调用该方法上报。
- Device Token 在同一设备保持一致,仅需在登录时上报一次即可,无需每次启动都上报。
import 'package:tim_ui_kit_push_plugin/tim_ui_kit_push_plugin.dart';
final TimUiKitPushPlugin cPush = TimUiKitPushPlugin(
isUseGoogleFCM: false,
);
final bool isUploadSuccess = await cPush.uploadToken(PushConfig.appInfo);
建议:在应用切换到 inactive/paused 状态前,使用插件中setBadgeNum( int badgeNum )
方法,将最新未读数同步至桌面角标。iOS角标由IM SDK自动管理,此处本插件支持配置 XIAOMI(MIUI6 - MIUI 11机型), HUAWEI, HONOR, vivo 及 OPPO 设备角标。
说明:OPPO角标属于OPPO侧高级权益,不默认开放。如需使用,请自行联系OPPO应用推送权益对接人。
/// coreInstance
@override
Future<V2TimCallback> setOfflinePushStatus({required AppStatus status, int? totalCount}) {
if(Platfrom.isIOS){
return;
}
if(status == AppStatus.foreground){
// 当应用status为前台时,上报doForeground()
return TencentImSDKPlugin.v2TIMManager
.getOfflinePushManager()
.doForeground();
}else{
// 当应用status为后台时,上报doBackground(),并带上未读数
return TencentImSDKPlugin.v2TIMManager
.getOfflinePushManager()
.doBackground(unreadCount: totalCount ?? 0);
}
}
/// App
final TimUiKitPushPlugin cPush = TimUiKitPushPlugin(
isUseGoogleFCM: false,
);
@override
void didChangeAppLifecycleState(AppLifecycleState state) async {
print("--" + state.toString());
int? unreadCount = await _getTotalUnreadCount();
switch (state) {
case AppLifecycleState.inactive:
_coreInstance.setOfflinePushStatus(status: AppStatus.background, totalCount: unreadCount);
if(unreadCount != null){
cPush.setBadgeNum(unreadCount);
}
break;
case AppLifecycleState.resumed:
_coreInstance.setOfflinePushStatus(status: AppStatus.foreground);
break;
case AppLifecycleState.paused:
_coreInstance.setOfflinePushStatus(status: AppStatus.background, totalCount: unreadCount);
if(unreadCount != null){
cPush.setBadgeNum(unreadCount);
}
break;
}
}
如您自行接入腾讯云 IM SDK,请在发消息时配置OfflinePushInfo offlinePushInfo
字段。
OfflinePushInfo({
this.title = '', // 推送通知标题。留空字符串时,按照优先级,IM后台自动替换成 sender的昵称 => sender ID。因此,如无特殊需求,该字段建议留空
this.desc = '', // 推送第二行小字部分
this.disablePush = false,
this.ext = '', // 推送内额外信息,对方可于单击通知跳转时拿到。建议传含Conversation信息的JSON,用于收件方跳转至对应Chat。可参见下方TUIKit的实例代码。
this.androidOPPOChannelID = '', // OPPO的channel ID
});
如果您使用我们的 Flutter TUIKit 组件库,可直接在TIMUIKitChat
组件TIMUIKitChatConfig
中,使用notificationTitle
/notificationOPPOChannelID
/notificationBody
/notificationExt
/notificationIOSSound
定义自定义推送。详情如下:
TIMUIKitChat(
config: TIMUIKitChatConfig(
notificationTitle: "",// 推送通知标题。留空字符串时,按照优先级,IM后台自动替换成sender的昵称 => sender ID。因此,如无特殊需求,该字段建议留空,可达到和微信一致的效果
notificationOPPOChannelID: "", // 用于推送消息的OPPO配置Channel ID
notificationBody: (V2TimMessage message, String convID, ConvType convType) {
return "您根据给出的参数自定义的第二行通知";
},
notificationExt: (V2TimMessage message, String convID, ConvType convType) {
// 您根据给出的参数自定义的EXT字段:此处建议传conversation id,JSON格式,即如下所示
String createJSON(String convID){
return "{\"conversationID\": \"$convID\"}";
}
String ext = (convType == ConvType.c2c
? createJSON("c2c_${message.sender}")
: createJSON("group_$convID"));
return ext;
}
)
)
说明:在后台跳转情况下,此时 Flutter 首页可能已经 unmounted,无法为跳转提供 context,因此建议启动时缓存一个 context,保证跳转成功。
建议跳转成功后,清除通知栏中其他通知消息,避免太多IM消息堆积在通知栏中。调用插件中
clearAllNotification()
方法即可。
BuildContext? _cachedContext;
final TimUiKitPushPlugin cPush = TimUiKitPushPlugin(
isUseGoogleFCM: false,
);
// 仅限TUIKit
final TIMUIKitChatController _timuiKitChatController =
TIMUIKitChatController();
@override
void initState() {
super.initState();
_cachedContext = context;
}
void handleClickNotification(Map<String, dynamic> msg) async {
String ext = msg['ext'] ?? "";
Map<String, dynamic> extMsp = jsonDecode(ext);
String convId = extMsp["conversationID"] ?? "";
// 【TUIKit】若当前的会话与要跳转至的会话一致,则不跳转。
final currentConvID = _timuiKitChatController.getCurrentConversation();
if(currentConvID == convId.split("_")[1]){
return;
}
final targetConversationRes = await TencentImSDKPlugin.v2TIMManager
.getConversationManager()
.getConversation(conversationID: convId);
V2TimConversation? targetConversation = targetConversationRes.data;
if(targetConversation != null){
cPush.clearAllNotification();
Navigator.push(
_cachedContext ?? context,
MaterialPageRoute(
builder: (context) => Chat(
selectedConversation: targetConversation,
),
));
}
}
一般情况下,发起 TRTC 通话使用信令消息通知对方。您可在信令消息中,按照 步骤6,加入offlinePushInfo
字段。
call
方法第三个参数中,传入offlinePush
对象即可。final user = await sdkInstance.getLoginUser();
final myId = user.data;
OfflinePushInfo offlinePush = OfflinePushInfo(
title: "",
desc: "邀请您语音通话",
ext: "{\"conversationID\": \"c2c_$myId\"}",
disablePush: false,
ignoreIOSBadge: false,
androidOPPOChannelID: PushConfig.OPPOChannelID
);
_calling?.call(widget.selectedConversation.userID!, CallingScenes.Audio, offlinePush);
说明:通话群邀请暂不支持离线推送。
本部分在使用插件跑通离线推送(Android)完成的基础上,补充对应步骤 iOS 端需要做的事情。
该页面没有提到过的步骤,和 Android 端一致。
使用 Xcode 打开您的项目,在 Runner>Target 中,配置支持 Push 的 Signing Profile。
并在左上角新增Push Notification
的 Capability。
执行flutter pub get
安装好插件后进入 iOS 目录,执行:pod install
安装依赖库。
将以下代码添加到 iOS 工程下ios/Runner/AppDelegate.swift
文件didFinishLaunchingWithOptions
方法中。
Objective-C:
if (@available(iOS 10.0, *)) {
[UNUserNotificationCenter currentNotificationCenter].delegate = (id<UNUserNotificationCenterDelegate>) self;
}
Swift:
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
info.plist
加入如下字段。<key>flutter_apns.disable_firebase_core</key>
<false/>
调用插件init
方法。该步骤会完成初始化各厂商通道,并申请厂商通知权限。该步骤建议在应用启动后就执行调用。
import 'package:tim_ui_kit_push_plugin/tim_ui_kit_push_plugin.dart';
final TimUiKitPushPlugin cPush = TimUiKitPushPlugin();
cPush.init(
pushClickAction: pushClickAction, // 单击通知后的事件回调,会在STEP6讲解
appInfo: PushConfig.appInfo, // 传入STEP1做的appInfo
);
如您自行接入腾讯云 IM SDK,请在发消息时配置OfflinePushInfo offlinePushInfo
字段。
OfflinePushInfo({
// ..其他配置
this.iOSSound = "", // iOS离线推送声音设置, 当 iOSSound = kIOSOfflinePushNoSound,表示接收时不会播放声音。 当 iOSSound = kIOSOfflinePushDefaultSound,表示接收时播放系统声音。 如果要自定义 iOSSound,需要先把语音文件链接进 Xcode 工程,然后把语音文件名(带后缀)设置给 iOSSound。
this.ignoreIOSBadge = false,
});
如果您使用我们的 Flutter TUIKit 组件库,可直接在TIMUIKitChat
组件TIMUIKitChatConfig
中,使用notificationTitle
/notificationOPPOChannelID
/notificationBody
/notificationExt
/notificationIOSSound
定义自定义推送。详情如下:
TIMUIKitChat(
config: TIMUIKitChatConfig(
// ..其他配置
notificationIOSSound: "", // iOS离线推送声音设置, 当 iOSSound = kIOSOfflinePushNoSound,表示接收时不会播放声音。 当 iOSSound = kIOSOfflinePushDefaultSound,表示接收时播放系统声音。 如果要自定义 iOSSound,需要先把语音文件链接进 Xcode 工程,然后把语音文件名(带后缀)设置给 iOSSound。
)
)
您可使用 离线推送自查 工具,检测终端状态/证书上报及发送测试消息。
由于 vivo 官方限制,应用在 vivo 应用市场上架前,不允许使用正式 PUSH 能力,详见此文档。
开发过程中,需要调试,请参见本步骤:
获取测试设备(vivo 真机)的 regId(我们称做 Device Token)。
在 vivo 控制台内,添加该设备为测试设备。
此时可推送测试消息至测试设备。可参见 vivo 单播推送文档。
由于腾讯云 IM 控制台的测试推送,和直接使用 IM SDK 发送聊天消息的推送,均不能修改推送模式为测试。因此请使用我们提供的,可触发测试消息的JS脚本,单击此处下载
下载后,请根据顶部五行注释,填入vivo相关参数。默认ext为conversationID
,如果在处理单击回调跳转(可参见 步骤6)时需要其他字段,请自行修改JS代码。
执行脚本。npm install axios
npm install js-md5
后node testvivo
。推送结果会显示在 log 最后一行。
此时测试终端可收到测试消息推送,单击消息后,可触发 Dart 层回调。
1、国内厂商都有消息分类机制,不同类型也会有不同的推送策略。如果想要推送及时可靠,需要按照厂商规则设置自己应用的推送类型为高优先级的系统消息类型或者重要消息类型。反之离线推送消息会受厂商推送消息分类影响,与预期会有差异。
2、另外,一些厂商对于应用每天的推送数量也是有限制的,可以在厂商控制台查看应用每日限制的推送数量。
如果离线推送消息出现推送不及时或者偶尔收不到情况,需要考虑下这里:
华为:将推送消息分为服务与通讯类和资讯营销类,推送效果和策略不同。另外,消息分类还和自分类权益有关:
vivo:将推送消息分为系统消息类和运营消息类,推送效果和策略不同。系统消息类型还会进行厂商的智能分类二次修正,若智能分类识别出不是系统消息,会自动修正为运营消息,如果误判可邮件申请反馈。另外,消息推送也受日推总数量限制,日推送量由应用在厂商订阅数统计决定。
具体请参见 厂商描述1 或 厂商描述2。
OPPO:将推送消息分为私信消息类和公信消息类,推送效果和策略不同。其中私信消息是针对用户有一定关注度,且希望能及时接收的信息,私信通道权益需要邮件申请。公信通道推送数量有限制。
具体请参见 厂商描述1 或 厂商描述2。
小米:将推送消息分为重要消息类和普通消息类,推送效果和策略不同。其中重要消息类型仅允许即时通讯消息、个人关注动态提醒、个人事项提醒、个人订单状态变化、个人财务提醒、个人状态变化、个人资源变化、个人设备提醒这8类消息推送,可以在厂商控制台申请开通。普通消息类型推送数量有限制。
具体请参见 厂商描述1 或 厂商描述2。
魅族:推送消息数量有限制,具体可参见 魅族平台合约。
FCM:推送上行消息频率有限制。
具体请参见 厂商描述。
OPPO 手机收不到推送一般有以下几种情况:
自定义消息的离线推送和普通消息不太一样,自定义消息的内容我们无法解析,不能确定推送的内容,所以默认不推送,如果您有推送需求,需要您在sendMessage
的时候设置offlinePushInfo
的desc
字段,推送的时候会默认展示 desc 信息。
离线推送的直观表现就是通知栏提示,所以同其他通知一样受设备通知相关设置的影响,以华为为例:
本文以上部分介绍了,如何使用本插件,结合腾讯云 IM 后端的推送服务,实现通过厂商通道的离线推送。
但是,在某些情况下,厂商离线推送并不适用。如,您的目标客户端机型非我们兼容的厂商,使用华强北定制的 Android 设备等。
此时,您只得通过在线监听收到新消息回调,在客户端上,手动触发创建通知。这仅适用于,应用未被kill掉,还处于前后台状态,能正常与 IM 服务端通信。
为此种情况,本插件在0.3版本中,新增两个本地创建消息的方法,displayNotification
自定义通知,及 displayDefaultNotificationForMessage
根据消息生成默认通知,您可按需使用。
在您的项目中安装 IM Flutter 推送插件:
flutter pub add tim_ui_kit_push_plugin
@mipmap/ic_launcher
存在且为您的应用 iCon。完整路径:android/app/src/main/res/mipmap/ic_launcher.png
如果不存在,可手动将您的应用 iCon 复制进去,或通过 Android Studio 自动创建不同分辨率版本(mipmap
目录右键,New
=> Image Asset
)。
android/app/src/main/AndroidManifest.xml
文件,在您应用的主 activity 中,添加如下代码。<activity
android:showWhenLocked="true"
android:turnScreenOn="true">
如果您已经配置 iOS 端离线推送,可忽略本部分。若无,请在 ios/Runner/AppDelegate.swift
或 ios/Runner/AppDelegate.m
文件中, didFinishLaunchingWithOptions
函数内,添加如下代码。可参考我们的DEMO。
Objective-C:
if (@available(iOS 10.0, *)) {
[UNUserNotificationCenter currentNotificationCenter].delegate = (id<UNUserNotificationCenterDelegate>) self;
}
Swift:
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
请在 IM SDK 初始化完成后,初始化本 Push 插件。实例化一个 cPush
插件类,供后续调用。
final TimUiKitPushPlugin cPush = TimUiKitPushPlugin();
cPush.init(
// 此处绑定点击通知的跳转函数,下文会介绍
pushClickAction: onClickNotification,
);
V2TimAdvancedMsgListener
如果您已经挂载监听 V2TimAdvancedMsgListener
,可忽略本部分;若无,请在 IM login 后,挂载监听。
代码如下:
final advancedMsgListener = V2TimAdvancedMsgListener(
onRecvNewMessage: (V2TimMessage newMsg) {
// 这里完成监听回调触发事件
// 下一步创建的方法,请在这里调用
},
});
TencentImSDKPlugin.v2TIMManager
.getMessageManager()
.addAdvancedMsgListener(listener: advancedMsgListener);
请从我们提供的两个 API 中,displayNotification
自定义通知,及 displayDefaultNotificationForMessage
根据消息生成默认通知,选一个合适的 API。
对于Android端,这两个 API 均需传入 channelID
及 channelName
。若还未创建 Android Push Channel ,请使用插件 createNotificationChannel
API 创建。
cPush.createNotificationChannel(
channelId: "new_message",
channelName: "消息推送",
channelDescription: "推送新聊天消息");
displayNotification
本 API 需要您提供 title
, body
, 及 ext
用于点击跳转信息,三个参数。您可以根据需要自行解析收到的 V2TimMessage
,生成这三个字段。
为便于跳转,此处 ext 的生成规则可查看 displayDefaultNotificationForMessage
的代码。
cPush.displayNotification(
channelID: "new_message",
channelName: "消息推送",
title: "",
body: "",
ext: ""
);
displayDefaultNotificationForMessage
为了方便,推荐您使用此 API,自动根据 V2TimMessage
,生成通知。
您只需传入一个 V2TimMessage
即可。
cPush.displayDefaultNotificationForMessage(
message: message, channelID: "new_message", channelName: "消息推送");
本步骤与 上文离线推送的步骤6 单击回调一致,均为在 ext 中,读取需要跳转的 conversation,并导航过去。
如果您在上一步使用 displayDefaultNotificationForMessage
,或在 displayNotification
中使用与default相同的 ext 生成函数,此时的 ext 结构为: "conversationID": "对应的conversation"
。
此时,填上初始化时,为 pushClickAction 埋的坑。
初始化时,注册该回调方法,可拿到含推送本体及 ext 信息在内的 Map。
说明:在后台跳转情况下,此时 Flutter 首页可能已经 unmounted,无法为跳转提供 context,因此建议启动时缓存一个 context,保证跳转成功。
建议跳转成功后,清除通知栏中其他通知消息,避免太多 IM 消息堆积在通知栏中。调用插件中
clearAllNotification()
方法即可。
BuildContext? _cachedContext;
final TimUiKitPushPlugin cPush = TimUiKitPushPlugin(
isUseGoogleFCM: false,
);
// 仅限TUIKit
final TIMUIKitChatController _timuiKitChatController =
TIMUIKitChatController();
@override
void initState() {
super.initState();
_cachedContext = context;
}
void onClickNotification(Map<String, dynamic> msg) async {
String ext = msg['ext'] ?? "";
Map<String, dynamic> extMsp = jsonDecode(ext);
String convId = extMsp["conversationID"] ?? "";
// 【TUIKit】若当前的会话与要跳转至的会话一致,则不跳转
final currentConvID = _timuiKitChatController.getCurrentConversation();
if(currentConvID == convId.split("_")[1]){
return;
}
final targetConversationRes = await TencentImSDKPlugin.v2TIMManager
.getConversationManager()
.getConversation(conversationID: convId);
V2TimConversation? targetConversation = targetConversationRes.data;
if(targetConversation != null){
cPush.clearAllNotification();
Navigator.push(
_cachedContext ?? context,
MaterialPageRoute(
builder: (context) => Chat(
selectedConversation: targetConversation,
),
));
}
}
如果您自定义了 ext
结构,则需自实现点击跳转函数。
此时,您已完成在线推送的接入。测试通过后,你可以在 onRecvNewMessage
内定义,触发推送通知的时机及场景。
本页内容是否解决了您的问题?