推送与消息提醒

推送

为了提高消息送达率,云信在 Android 进程保活上做了很多努力,但是在国内 Android 系统的大环境下,厂家的深度定制 ROM 对系统做了越来越严格的限制,想要在所有机型上做到永久保活是不可能实现的,并且保活也会使额外功耗增加。

因此,云信引入手机系统厂商推送,当用户清理掉应用进程、网络不稳定等导致客户端SDK无法与云信服务器保持正常连接时,将使用手机厂商系统级推送来提醒用户有消息需要接收。

手机系统级别的厂商推送(如小米、华为、VIVO、OPPO、魅族等)的优势于其拥有稳定的系统级长连接,可以做到随时接受推送。测试推送时,可以编译apk安装到支持该系统级推送的手机上,登陆成功后杀掉进程,使用其他账号对其发送消息,查看推送接收情况。

推送服务集成

参见SDK集成push的说明。

小米推送

准备工作

接入配置

有两处需要改成开发者自己的 APP 包名,已经配置过的条目则无须添加。

<!--配置权限,已经配置过的条目则无须添加-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.VIBRATE"/>

<!--以下两处 {你的包名} 改开发者App的包名-->
<permission android:name="{你的包名}.permission.MIPUSH_RECEIVE"
            android:protectionLevel="signature" />
<uses-permission android:name="{你的包名}.permission.MIPUSH_RECEIVE" />

下面这些配置直接拷贝到 AndroidManifest.xml ,不需要做任何改动。

<!--配置的service和receiver-->
<service
    android:name="com.xiaomi.push.service.XMPushService"
    android:enabled="true"
    android:process=":mixpush"/>
<service
    android:name="com.xiaomi.push.service.XMJobService"
    android:enabled="true"
    android:exported="false"
    android:permission="android.permission.BIND_JOB_SERVICE"
    android:process=":mixpush" />
    <!--注:此service必须在3.0.1版本以后(包括3.0.1版本)加入-->
<service
    android:enabled="true"
    android:exported="true"
    android:name="com.xiaomi.mipush.sdk.PushMessageHandler" />

<service android:enabled="true"
    android:name="com.xiaomi.mipush.sdk.MessageHandleService" />
<!--注:此service必须在2.2.5版本以后(包括2.2.5版本)加入-->
<receiver
    android:exported="true"
    android:name="com.xiaomi.push.service.receivers.NetworkStatusReceiver" >
    <intent-filter>
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</receiver>
<receiver
    android:exported="false"
    android:process=":mixpush"
    android:name="com.xiaomi.push.service.receivers.PingReceiver" >
    <intent-filter>
        <action android:name="com.xiaomi.push.PING_TIMER" />
    </intent-filter>
</receiver>
<receiver
    android:name="com.netease.nimlib.mixpush.mi.MiPushReceiver"
    android:exported="true">
    <intent-filter android:priority="0x7fffffff">
        <action android:name="com.xiaomi.mipush.RECEIVE_MESSAGE"/>
        <action android:name="com.xiaomi.mipush.MESSAGE_ARRIVED"/>
        <action android:name="com.xiaomi.mipush.ERROR"/>
    </intent-filter>
</receiver>

在SDK初始化时,需要将推送相关证书信息配置到 SDKOptions.mixPushConfig 中。

示例:

MixPushConfig config = new MixPushConfig();
// 传入从小米推送平台获取到的AppId与AppKey
config.xmAppId = "xxxx";
config.xmAppKey = "xxxx";
// 传入云信控制台上小米推送对应的证书名
config.xmCertificateName = "xxxx";
...
options.mixPushConfig = config;

如果构建 APP 时有使用代码混淆,需要在 proguard.cfg 中加入

-dontwarn com.xiaomi.push.**
-keep class com.xiaomi.** {*;}

至此,小米推送接入完成,现在可以在小米设备上进行消息推送的测试。

推送兼容性

若开发者自身业务体系中,也需要接入小米推送,则需要考虑开发者自身业务体系的小米推送与云信消息的小米推送兼容 需要做好以下2点,其余配置、逻辑都不需要修改。

/**
 * 以下这些方法运行在非 UI 线程中, 与小米SDK PushMessageReceiver 方法一一对应。
 * 开发者如果自身也需要接入小米推送,则应将继承 PushMessageReceiver 改为继承 MiPushMessageReceiver
 */

public class MiPushMessageReceiver extends BroadcastReceiver{

    @Override
    public final void onReceive(Context context, Intent intent) {
    }

    public void onReceivePassThroughMessage(Context context, MiPushMessage message) {
    }

    public void onNotificationMessageClicked(Context context, MiPushMessage message) {
    }

    public void onNotificationMessageArrived(Context context, MiPushMessage message) {
    }

    public void onReceiveRegisterResult(Context context, MiPushCommandMessage message) {
    }

    public void onCommandResult(Context context, MiPushCommandMessage message) {
    }
}
<receiver android:name="xxx.MiPushMessageReceiver">
    <intent-filter>
        <action android:name="com.xiaomi.mipush.RECEIVE_MESSAGE"/>
        <action android:name="com.xiaomi.mipush.MESSAGE_ARRIVED"/>
        <action android:name="com.xiaomi.mipush.ERROR"/>
    </intent-filter>
</receiver>

华为推送

华为推送从新版 HMS 包开始采用了和小米推送相似的系统级连接方案,但是依赖于 EMUI 版本和 华为移动服务 版本,经过大量测试表明,EMUI4.1及以上并同时满足华为移动服务版本4.0.4.301`以上时比较稳定能收到推送。

准备工作

参考华为开发准备文档进行如下工作:

接入配置

首先,Application#onCreate中,主进程下进行如下操作:

public class NimApplication extends Application {
    ...
    @Override
    public void onCreate() {
        ...
        if (NIMUtil.isMainProcess(this)) {
            ...
            // 在此处添加以下代码
            com.huawei.hms.support.common.ActivityMgr.INST.init(this);
            ...
        }
    }
}
<service
      android:name="com.netease.nimlib.mixpush.hw.HWPushService"
      android:exported="false">
      <intent-filter>
            <action android:name="com.huawei.push.action.MESSAGING_EVENT" />
      </intent-filter>
</service>

在SDK初始化时,需要将推送相关证书信息配置到 SDKOptions.mixPushConfig 中。

MixPushConfig config = new MixPushConfig();
// 传入华为推送的APP ID
config.hwAppId = "xxxx";
// 传入云信控制台上华为推送证书名
config.hwCertificateName = "xxxx";
...
options.mixPushConfig = config;

如果构建 APP 时有使用代码混淆,需要在 proguard.cfg 中加入排除 HMS SDK 的混淆配置:

-ignorewarning 
-keepattributes *Annotation* 
-keepattributes Exceptions 
-keepattributes InnerClasses 
-keepattributes Signature 
-keepattributes SourceFile,LineNumberTable 
-keep class com.hianalytics.android.**{*;} 
-keep class com.huawei.updatesdk.**{*;} 
-keep class com.huawei.hms.**{*;}

如果开发者使用了AndResGuard,需要在混淆配置文件中加入AndResGuard白名单:

"R.string.hms*",
"R.string.connect_server_fail_prompt_toast",
"R.string.getting_message_fail_prompt_toast",
"R.string.no_available_network_prompt_toast",
"R.string.third_app_*",
"R.string.upsdk_*",
"R.layout.hms*",
"R.layout.upsdk_*",
"R.drawable.upsdk*",
"R.color.upsdk*",
"R.dimen.upsdk*",
"R.style.upsdk*",
"R.string.agc*"

至此,华为推送接入完成,现在可以在满足条件的华为设备上进行消息推送测试。

推送兼容性

若开发者自身业务体系中,也需要接入华为推送,则需要考虑开发者自身业务体系的华为推送与云信消息的华为推送兼容需要做好以下2点,其余配置、逻辑都不需要修改。

/**
 * 以下这些方法运行在非 UI 线程中, 与HuaWei的PHmsMessageService 方法一一对应。
 * 当开发者自身也接入HuaWei推送,则应将继承 HmsMessageService 改为继承 HWPushMessageService,其他不变
 */
public class HWPushMessageService extends Service {

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    public void onNewToken(String token) {
        MixPushPlatforms.getPushPlatform(PushType.HUA_WEI).onToken(token);
    }

    /**
     * 透传消息, 需要用户自己弹出通知
     *
     * @param remoteMessage
     */
    public void onMessageReceived(RemoteMessage remoteMessage) {
    }

    public void onMessageSent(String s) {
    }

    public void onDeletedMessages() {
    }

    public void onSendError(String var1, Exception var2) {
    }
}
<service 
    android:name="xxx.HWPushMessageService"
    android:exported="false">
    <intent-filter>
          <action android:name="com.netease.nimlib.mixpush.hw.action.MESSAGING_EVENT" />
    </intent-filter>
</service>

VIVO推送

准备工作

接入配置

下面这些配置直接拷贝到AndroidManifest.xml。

<!--配置的service, activity, receiver-->
 <service
        android:name="com.vivo.push.sdk.service.CommandClientService"
        android:exported="true"/>
    <activity
        android:name="com.vivo.push.sdk.LinkProxyClientActivity"
        android:exported="false"
        android:screenOrientation="portrait"
        android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
    <receiver android:name="com.netease.nimlib.mixpush.vivo.VivoPushReceiver">
        <intent-filter>
            <!-- 接收 push 消息 -->
            <action android:name="com.vivo.pushclient.action.RECEIVE"/>
        </intent-filter>
</receiver>

同样在AndroidManifest.xml中,添加配置app_id与api_key:

<meta-data
    android:name="com.vivo.push.api_key"
    android:value="{你的vivo推送app key}"/>
<meta-data
    android:name="com.vivo.push.app_id"
    android:value="{你的vivo推送的app id}"/>

在SDK初始化时,需要将推送相关证书信息配置到 SDKOptions.mixPushConfig 中。

// 传入云信控制台上配置的vivo推送证书名
config.vivoCertificateName = "DEMO_VIVO_PUSH"; 
...
options.mixPushConfig = config;

如果构建 APP 时有使用代码混淆,需要在proguard.cfg中加入:

-dontwarn com.vivo.push.**
-keep class com.vivo.push.**{*; } 
-keep class com.vivo.vms.**{*; }
-keep class com.netease.nimlib.mixpush.vivo.VivoPush* {*;}
-keep class com.netease.nimlib.mixpush.vivo.VivoPushReceiver{*;}

至此,VIVO推送接入完成,现在可以在VIVO设备上进行消息推送的测试。

推送兼容性


/**
 * 以下这些方法运行在非 UI 线程中, 与VIVO SDK 的 OpenClientPushMessageReceiver 方法一一对应。
 * 当开发者自身也接入VIVO推送,则应将继承 OpenClientPushMessageReceiver 改为继承 VivoPushMessageReceiver,其他不变
 */

public class VivoPushMessageReceiver extends BroadcastReceiver {

    @Override
    public final void onReceive(Context context, Intent intent) {
    }

    public void onNotificationMessageClicked(Context context, UPSNotificationMessage upsNotificationMessage) {
    }

    public void onReceiveRegId(Context context, String s) {
    }
}
<receiver android:name="xxx.VivoPushMessageReceiver">
    <intent-filter>
        <action android:name="com.vivo.pushclient.action.RECEIVE" />
    </intent-filter>
</receiver>

消息类型配置

VIVO的推送消息分为运营消息和系统消息,需要在推送时进行指定,否则按照运营消息处理。

该字段的配置点为消息体的pushPayload,在其中添加以vivoField为key的Map或者JsonObject数据即可,数据格式参照VIVO文档

int classification = vivoClassificationCheckBox.isChecked() ? 1 : 0;
Map<String, Object> pushPayload = msg.getPushPayload();
pushPayload = pushPayload == null ? new HashMap<>() : pushPayload;

//vivoField
Map<String, Object> vivoField = new HashMap<>();
vivoField.put("classification", classification);
pushPayload.put("vivoField", vivoField);

OPPO推送

准备工作

接入配置

首先,Application#onCreate中,主进程下进行如下操作:

public class NimApplication extends Application {
    ...
    @Override
    public void onCreate() {
        ...
        if (NIMUtil.isMainProcess(this)) {
            ...
            // 在此处添加以下代码
            com.heytap.msp.push.HeytapPushManager.init(this, true);
            ...
        }
    }
}

先声明推送权限:

<!--  oppo推送配置权限-->
<uses-permission android:name="com.coloros.mcs.permission.RECIEVE_MCS_MESSAGE"/>
<uses-permission android:name="com.heytap.mcs.permission.RECIEVE_MCS_MESSAGE"/>


<!--Oppo推送配置项 需要配置以下两项-->
<service
    android:name="com.netease.nimlib.mixpush.oppo.OppoPushService"

    android:permission="com.coloros.mcs.permission.SEND_MCS_MESSAGE">
    <intent-filter>
        <action android:name="com.coloros.mcs.action.RECEIVE_MCS_MESSAGE"/>
    </intent-filter>
</service> <!--兼容Q以下版本-->

<service
    android:name="com.netease.nimlib.mixpush.oppo.OppoAppPushService"

    android:permission="com.heytap.mcs.permission.SEND_PUSH_MESSAGE">

    <intent-filter>
        <action android:name="com.heytap.mcs.action.RECEIVE_MCS_MESSAGE"/>

        <action android:name="com.heytap.msp.push.RECEIVE_MCS_MESSAGE"/>
    </intent-filter>
</service> <!--兼容Q版本-->

在SDK初始化时,需要将推送相关证书信息配置到 SDKOptions.mixPushConfig 中。

config.oppoAppId = "xxxx";
config.oppoAppKey = "xxxxxx";
// 注意区分AppSercet与MasterSecret
config.oppoAppSercet = "xxxxxxx";
// 传入云信控制台上配置的oppo推送证书名
config.oppoCertificateName = "xxxx";
...
options.mixPushConfig = config;

如果构建 APP 时有使用代码混淆,需要在 proguard.cfg 中加入:

-keep public class * extends android.app.Service

目前OPPO推送不支持透传消息。

至此,OPPO推送接入完成,现在可以在OPPO设备上进行消息推送的测试。

推送兼容性

与小米推送兼容性类似

/**
 *  以下这些方法运行在非 UI 线程中, 与Oppo的PushService 方法一一对应。
 *  当开发者自身也接入Oppo推送,则应将继承 PushService 改为继承 OppoPushMessageService,其他不变
 */
public class OppoPushMessageService extends Service {

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * 普通消息
     * @param context
     * @param appMessage
     */
    public void processMessage(Context context, AppMessage appMessage) {
    }

    /**
     * oppo 官方目前还不支持透传消息
     *
     * @param context
     * @param sptDataMessage
     */
    public void processMessage(Context context, SptDataMessage sptDataMessage) {
    }
}
/**
 *  以下这些方法运行在非 UI 线程中, 与Oppo的PushService 方法一一对应。
 *  当开发者自身也接入Oppo推送,则应将继承 AppPushService 改为继承 OppoAppPushMessageService,其他不变
 */
public class OppoAppPushMessageService extends Service {

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * 普通消息
     * @param context
     * @param appMessage
     */
    public void processMessage(Context context, AppMessage appMessage) {
    }

    /**
     * oppo 官方目前还不支持透传消息
     *
     * @param context
     * @param sptDataMessage
     */
    public void processMessage(Context context, SptDataMessage sptDataMessage) {
    }
}
<service android:name="xxx.OppoService"
         android:permission="com.coloros.mcs.permission.SEND_MCS_MESSAGE">
    <intent-filter>
            <action android:name="com.coloros.mcs.action.RECEIVE_MCS_MESSAGE"/>
    </intent-filter>
</service>

魅族推送

准备工作

接入配置

有2处需要改成开发者自己的 APP 包名。

<!-- 兼容 Flyme5 以下版本,魅族内部接入 PushSDK 必填,不然无法收到消息-->
<uses-permission android:name="com.meizu.flyme.push.permission.RECEIVE"/>
<permission
    android:name="{你的包名}.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"/>

下面这些配置直接拷贝到AndroidManifest.xml,并替换你自己的包名。

<!--魅族推送配置项-->
<receiver android:name="com.netease.nimlib.mixpush.mz.MZPushReceiver">
    <intent-filter android:priority="0x7fffffff">
        <!-- 接收 push 消息 -->
        <action android:name="com.meizu.flyme.push.intent.MESSAGE" />
        <!-- 接收 register 消息 -->
        <action android:name="com.meizu.flyme.push.intent.REGISTER.FEEDBACK" />
        <!-- 接收 unregister 消息-->
        <action android:name="com.meizu.flyme.push.intent.UNREGISTER.FEEDBACK"/>
        <!-- 兼容低版本 Flyme3 推送服务配置 -->
        <action android:name="com.meizu.c2dm.intent.REGISTRATION" />
        <action android:name="com.meizu.c2dm.intent.RECEIVE" />

        <category android:name="com.netease.nim.demo"/>
    </intent-filter>
</receiver>

在SDK初始化时,需要将推送相关证书信息配置到 SDKOptions.mixPushConfig 中。

config.mzAppId = "xxx";
config.mzAppKey = "xxxx";
config.mzCertificateName = "xxxx";

如果构建 APP 时有使用代码混淆,需要在 proguard.cfg 中加入:

-dontwarn com.meizu.cloud.**
-keep class com.meizu.cloud.** {*;}

至此,魅族推送接入完成,现在可以在魅族设备上进行消息推送的测试。

推送兼容性


/**
 * 以下这些方法运行在非 UI 线程中, 与魅族 SDK 的 MzPushMessageReceiver 方法一一对应。
 * 当开发者自身也接入魅族推送,则应将继承 MzPushMessageReceiver 改为继承 MeiZuPushReceiver,其他不变
 */

public class MeiZuPushReceiver extends BroadcastReceiver {

    @Override
    public final void onReceive(Context context, Intent intent) {
    }

    public void onRegister(Context context, String pushId) {
    }

    public void onUnRegister(Context context, boolean success) {
    }

    public void onPushStatus(Context context, PushSwitchStatus pushSwitchStatus) {
    }

    public void onRegisterStatus(Context context, RegisterStatus registerStatus) {
    }

    public void onUnRegisterStatus(Context context, UnRegisterStatus unRegisterStatus) {
    }

    public void onSubTagsStatus(Context context, SubTagsStatus subTagsStatus) {
    }

    public void onSubAliasStatus(Context context, SubAliasStatus subAliasStatus) {
    }

    public void onNotificationClicked(Context context, String title, String content, String selfDefineContentString) {
    }

    public void onNotificationArrived(Context context, String title, String content, String selfDefineContentString) {
    }

    public void onNotifyMessageArrived(Context context, String message) {
    }

    public void onNotificationDeleted(Context context, String title, String content, String selfDefineContentString) {
    }

    public void onUpdateNotificationBuilder(PushNotificationBuilder pushNotificationBuilder) {
    }
}
<receiver android:name="xxx.MeiZuPushReceiver">
    <intent-filter>
        <action android:name="com.meizu.flyme.push.intent.MESSAGE" />
        <action android:name="com.meizu.flyme.push.intent.REGISTER.FEEDBACK" />
        <action android:name="com.meizu.flyme.push.intent.UNREGISTER.FEEDBACK" />
    </intent-filter>
</receiver>

谷歌推送

谷歌推送FCM 是 GCM 的升级版,适用于海外用户,FCM 成功推送需要两个条件:

需要说明的是,在某些国产手机上,虽然满足以上两个条件,FCM 推送成功了,但是仍然是没能看到推送通知栏的。如果应用面向国内用户,则不需要集成FCM。

准备工作

implementation 'com.google.firebase:firebase-messaging:20.1.0'
implementation 'com.google.android.gms:play-services-base:17.1.0'
implementation 'com.google.firebase:firebase-core:17.2.3'

接入配置

下面这些配置直接拷贝到AndroidManifest.xml。

<!-- fcm -->
<service android:name="com.netease.nimlib.mixpush.fcm.FCMTokenService">
    <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
    </intent-filter>
</service>

设置收到 FCM 通知展示的图标和颜色

<!--设置收到 fcm 通知展示的图标和颜色-->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_icon"
    android:resource="@drawable/改成你的通知图标" />
<meta-data
    android:name="com.google.firebase.messaging.default_notification_color"
    android:resource="@color/改成你的通知字体颜色" />

在SDK初始化时,需要将推送相关证书信息配置到 SDKOptions.mixPushConfig 中。

config.fcmCertificateName = "xxxx";
...
options.mixPushConfig = config;

如果构建 APP 时有使用代码混淆,需要在 proguard.cfg 中加入:

-dontwarn com.google.**
-keep class com.google.** {*;}

至此,FCM 推送接入完成,现在可以进行消息推送的测试。

消息提醒

云信 SDK 提供内置的消息提醒功能,其作用的场景与推送不同,一般对即时通讯的场景来说,主要作用在:

以下场景一般不需要消息提醒:

启用消息提醒

/**
 * 通知栏消息提醒开关控制。只有StatusBarNotificationConfig配置不为空时才有效
 *
 * @param on 开关
 */
public static void toggleNotification(boolean on);
// 开启通知栏消息提醒
NIMClient.toggleNotification(true);

启用后,需要依据当前页面环境动态调整是否需要消息提醒。此处,需要结合未读数相关接口进行处理:

// 进入聊天界面,建议放在onResume中。表示来自account的消息无需进行消息提醒。
NIMClient.getService(MsgService.class).setChattingAccount(accountsessionType);

// 进入最近联系人列表界面,建议放在onResume中。表示所有消息无需进行消息提醒。
NIMClient.getService(MsgService.class).setChattingAccount(MsgService.MSG_CHATTING_ACCOUNT_ALL, SessionTypeEnum.None);

// 退出聊天界面或离开最近联系人列表界面,建议放在onPause中。表示所有消息都可以进行消息提醒。
NIMClient.getService(MsgService.class).setChattingAccount(MsgService.MSG_CHATTING_ACCOUNT_NONE, SessionTypeEnum.None);

撤回通知消息提醒

/**
 * 设置收到撤回通知时,是否需要产生消息提醒。只有StatusBarNotificationConfig配置不为空并且通知栏提醒开关是打开的才有效。默认打开。
 *
 * @param on 开关
 */
public static void toggleNotification(boolean on);

消息提醒配置

/**
 * 更新状态栏通知提醒设置
 *
 * @param config 设置
 */
public static void updateStatusBarNotificationConfig(StatusBarNotificationConfig config);
StatusBarNotificationConfig 参数 说明
notificationSmallIconId 状态栏提醒的小图标的资源ID。
如果不提供,使用 app 的 icon
ring 是否需要响铃提醒。
默认为 true
notificationSound 响铃提醒的声音资源,如果不提供,使用系统默认提示音
vibrate 是否需要振动提醒。
默认为 true
ledARGB 呼吸灯的颜色。
建议尽量使用绿色、蓝色、红色等基本颜色,不要去用混合色
ledOnMs 呼吸灯亮时的持续时间(毫秒)
ledOffMs 呼吸灯熄灭时的持续时间(毫秒)
hideContent 不显示消息详情开关。
默认为 false
downTimeToggle 免打扰设置开关。默认为关闭
downTimeBegin 免打扰的开始时间, 格式为HH:mm(24小时制)。
downTimeEnd 免打扰的结束时间, 格式为HH:mm(24小时制)。
如果结束时间小于开始时间,免打扰时间为开始时间-24:00-结束时间。
notificationEntrance 通知栏提醒的响应intent的activity类型。
可以为null。如果未提供,将使用包的launcher的入口intent的activity。
titleOnlyShowAppName 通知栏提醒的标题是否只显示应用名。
默认是 false,当有一个会话发来消息时,显示会话名;
当有多个会话发来时,显示应用名。
修改为true,那么无论一个还是多个会话发来消息,标题均显示应用名。
应用名称请在 AndroidManifest 的 application 节点下设置 android:label
notificationColor 消息通知栏颜色,将应用到 NotificationCompat.Builder 的 setColor 方法。
对Android 5.0 以后机型会影响到smallIcon
downTimeEnableNotification 免打扰期间,是否显示通知,默认为显示
notificationFoldStyle 通知栏合并方式:
全部折叠:NotificationFoldStyle.ALL
全部不折叠:NotificationFoldStyle.EXPAND
按会话折叠:NotificationFoldStyle.CONTACT
// 更新消息提醒配置 StatusBarNotificationConfig,以设置不响铃为例。
StatusBarNotificationConfig config = UserPreferences.getStatusConfig();
config.ring = false;
NIMClient.updateStatusBarNotificationConfig(config);

定制头像与名称

开发者可以实现UserInfoProvider接口来处理通知栏显示的头像和名称。该接口具有以下方法:

具体的接口说明请查看API文档,示例代码请下载即时通讯Demo源码,查看 NimUserInfoProvider.java文件。

云信支持定制通知栏显示的头像(用户头像、群头像),在 UserInfoProvider 接口下提供方法:

/**
 * 为云信端内通知栏提供消息发送者显示名称(例如:如果是P2P聊天,可以显示备注名、昵称、帐号等;如果是群聊天,可以显示群昵称,备注名,昵称、帐号等)
 *
 * @param account     消息发送者账号
 * @param sessionId   会话ID(如果是P2P聊天,那么会话ID即为发送者账号,如果是群聊天,那么会话ID就是群号)
 * @param sessionType 会话类型
 * @return 消息发送者对应的显示名称
 */
String getDisplayNameForMessageNotifier(String account, String sessionId, SessionTypeEnum sessionType);

/**
 * 为云信端内推送通知栏提醒提供头像(个人、群组)
 * 一般从本地图片缓存中获取,若未下载或本地不存在,请返回默认本地头像(可以返回默认头像资源ID对应的Bitmap)
 *
 * @param sessionType 会话类型(个人、群组)
 * @param sessionId   用户账号或者群ID
 * @return 头像位图
 */
Bitmap getAvatarForMessageNotifier(SessionTypeEnum sessionType, String sessionId);

实现上述需要的方法,在 SDKOptions 中配置 UserInfoProvider 实例,在 SDK 初始化时传入 SDKOptions 方可生效。

需要注意的是,上述返回头像 Bitmap 的函数,请尽可能从内存缓存里拿头像,如果读取本地头像可能导致 UI 进程阻塞,从而导致通知栏提醒延时弹出。

多端提醒策略配置

当桌面端在线时,SDK 支持设置同账号所在的手机端是否需要产生推送与消息提醒。

该功能由 SettingsService 提供:

/**
 * 设置桌面端(PC/WEB)在线时,移动端是否需要推送
 * @param isOpen  开关
 * @return NoDisturbConfig
 */
InvocationFuture<java.lang.Void> updateMultiportPushConfig(boolean isOpen);

/**
 * 获取桌面端(PC/WEB)在线时,移动端是否需要推送
 */
boolean isMultiportPushOpen();

示例:

NIMClient.getService(SettingsService.class).updateMultiportPushConfig(checkState)
                 .setCallback(new RequestCallback<Void>() {
                     @Override
                     public void onSuccess(Void param) {
                         ToastHelper.showToast(SettingsActivity.this, "设置成功");
                     }

                     @Override
                     public void onFailed(int code) {
                         ToastHelper.showToast(SettingsActivity.this, "设置失败,code:" + code);
                         adapter.notifyDataSetChanged();
                     }

                     @Override
                     public void onException(Throwable exception) {
                     }
});

此外,可以通过 SettingsServiceObserver提供的回调来监听该项的变更:

/**
 * 注册/注销桌面端(PC/WEB)在现时,移动端是否需要推送事件观察者
 */
void observeMultiportPushConfigNotify(Observer<java.lang.Boolean> observer,boolean register);

全局免打扰

关闭推送服务

当要直接关闭推送与消息提醒时,需要同时关闭推送服务与消息提醒。

关闭推送服务

使用 MixPushService 提供的 enable 方法可以实现。当设置为 false 时,该客户端将接收不到来自云信体系内的推送。

/**
 * 开启/关闭推送服务
 *
 * @param enable true 开启,SDK 需要与云信服务器做确认;false 关闭,SDK 也需要通知云信服务器。
 * @return InvocationFuture 可以设置回调函数。只有与服务器交互完成后才算成功,如果出错,会有具体的错误代码。
 */
public InvocationFuture<Void> enable(boolean enable);

/**
 *  是否开启了第三方推送服务
 */ 
boolean isEnable();

调用示例:

NIMClient.getService(MixPushService.class).enable(enable).setCallback(new RequestCallback<Void>(){ ... });

关闭消息提醒

/**
 * 通知栏消息提醒开关控制。只有StatusBarNotificationConfig配置不为空时才有效
 *
 * @param on 开关
 */
public static void toggleNotification(boolean on);

设置免打扰时段

推送免打扰时段

使用 MixPushService 提供的 setPushNoDisturbConfig 方法设置推送免打扰时间。

/**
 * 设置推送免打扰时间,时间参数为北京时间的24小时计数 HH:mm,该时间段将不再向用户推送消息
 * SDK 3.2.0 版本以前的用户,为了将用户设置的免打扰配置与push免打扰同步,应该在监听到登陆同步完成后,
 * 调用 setPushNoDisturbConfig 方法。如果开发者不使用新版第三方推送功能,只要不调用该方法,则旧的功能不受影响。
 * 此外,在免打扰设置界面也应该做到同时设置push免打扰
 * @param isOpen 是否开启
 * @param startTime 开始时间 格式 HH:mm
 * @param stopTime 结束时间 格式 HH:mm
 * @return InvocationFuture 可以设置回调函数。成功会返回成功信息,错误会返回相应的错误码。
 */
InvocationFuture<Void> setPushNoDisturbConfig(boolean isOpen, String startTime, String stopTime);

使用 MixPushService 提供的 getPushNoDisturbConfig() 方法获取推送免打扰时间。

/**
 * 获取推送免打扰设置
 * @return NoDisturbConfig
 */
NoDisturbConfig getPushNoDisturbConfig();

消息提醒免打扰时段

通过设置 StatusBarNotificationConfig 的免打扰属性来设置:

StatusBarNotificationConfig 参数 说明
downTimeToggle 免打扰设置开关。默认为关闭
downTimeBegin 免打扰的开始时间, 格式为HH:mm(24小时制)。
downTimeEnd 免打扰的结束时间, 格式为HH:mm(24小时制)。
如果结束时间小于开始时间,免打扰时间为开始时间-24:00-结束时间。

示例:

config.downTimeToggle = true;
config.downTimeBegin = startTime;
config.downTimeEnd = endTime;
config.downTimeEnableNotification = enableNotification;
NIMClient.updateStatusBarNotificationConfig(config);

消息配置

是否推送与消息提醒

当需要指定某条消息无需推送和消息提醒时,可以通过设置CustomMessageConfig.enablePush来设置,设置为false,则该条消息不会触发推送。具体参见消息属性设置

设置推送文案前缀

当需要指定某条消息推送时是否带有前缀,当前默认为消息发送者的昵称。可以通过设置CustomMessageConfig.enablePushNick来设置。具体参见消息属性设置

推送标题设置

通知栏文案

推送文案

可以通过IMMessage.setPushContent(String pushContent)方法来设置推送文案。如果不设置推送文案,将使用云信内置文案。

如果开发者配置了「不显示推送详情」(配置方法见下),默认的推送文案是:“你收到一条新消息”。此时,开发者可以自定义推送文案(例如基于系统语言等场景)。注意:需要联系商务顾问申请开通才能使用。

登录云信控制台 - 选择应用 - 证书管理 - 自定义推送文案。可以配置最多 100 种自定义文案,每种自定义文案用一个自定义类型来标识。

当客户端配置为「不显示推送详情」时,自定义推送文案才会生效。

/**
 * 设置推送是否不展示详情
 *
 * @param showNoDetail 是否不展示详情,true为不展示详情
 * @return InvocationFuture 可以设置回调函数。成功会返回成功信息,错误会返回相应的错误码。
 */
InvocationFuture<Void> setPushShowNoDetail(boolean showNoDetail);

不显示推送详情情况下,根据配置的推送文案下发。对应的设置参数为SDKOptions.customPushContentType

消息提醒文案

Android SDK通知栏提醒文案显示的优先级如下:

群消息强制推送

用户在发消息的时候,可以通过配置 IMMessage.setMemberPushOption(MemberPushOption pushOption) 字段实现群消息强制推送。即接收者屏蔽了当前会话(如免打扰),仍能够推送当前这条推送。

MemberPushOption 接口说明

返回值 MemberPushOption接口 说明
List getForcePushList() 返回强制推送的账号列表
String getForcePushContent() 返回强制推送的文案
boolean isForcePush() 返回是否强制推送
void setForcePush(boolean forcePush) 设置是否强推。
针对 forcePushList 里的帐号,
false 为不强推,true 为强推,默认为 true。
对于 forcePushList 中的用户,推送文案为 forcePushContent;
对于不在 forcePushList 中的用户,推送文案为 pushContent;
针对在 forcePushList 中的账号:
isForcePush 为true 时,推送文案中不会包含发送者 nick,直接为 forcePushContent;
isForcePush 为 false 时,推送文案中目前包含了发送者 nick(暂定),即为 fromNick:forcePushContent
void setForcePushList(List forcePushList) 设置强推列表,
填 null 表示强推给该会话所有成员,
不为 null 时最大上限账号为100个
void setForcePushContent(String forcePushContent) 强推文案(可扩展为区别与普通推送的推送文案),长度目前限制为500
// 该帐号为示例,请先注册
String account = "testAccount";
// 群聊才有强推消息
SessionTypeEnum sessionType = SessionTypeEnum.Team;
String text = "指定推送消息";
// 创建一个文本消息
IMMessage textMessage = MessageBuilder.createTextMessage(account, sessionType, text);

// 配置指定成员推送
MemberPushOption memberPushOption = new MemberPushOption();
// 开启强制推送
memberPushOption.setForcePush(true);
// 设置强推文案
memberPushOption.setForcePushContent(textMessage.getContent());
List<String> pushList = new ArrayList<>();
pushList.add("account1");
pushList.add("account2");
// 设置指定推送列表
memberPushOption.setForcePushList(pushList);
textMessage.setMemberPushOption(memberPushOption);

// 发送给对方
NIMClient.getService(MsgService.class).sendMessage(textMessage, false);

点击通知栏跳转

当收到推送与通知栏提醒后,用户点击通知栏,希望进入指定的聊天界面时,需要跳转到对应的聊天界面。

推送通知栏跳转

华为推送

发送消息前,在云信消息体的 pushPayload 中传入 key 为 hwField 的Map或者JsonObject类型的数据,通常为 发送者的account/ 群聊id 与类型(单聊或群聊)等信息,这些信息将被透传到推送的接收方。数据的参数填写方法请参考华为开放平台:HTTPS下行消息

Intent hwIntent = new Intent(Intent.ACTION_VIEW);
String intentStr = String.format(
        "pushscheme://com.huawei.codelabpush/deeplink?sessionID=%s&sessionType=%s",
        sessionId,  // 发送者的account 或  群聊id
        sessionType // 类型(单聊或群聊)
);
hwIntent.setData(Uri.parse(intentStr));
hwIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
String intentUri = hwIntent.toUri(Intent.URI_INTENT_SCHEME);
//点击事件的内容
JSONObject clickAction = new JSONObject();
//通知的内容
JSONObject notification = new JSONObject();

try {
    clickAction.putOpt("type", 1)
            .putOpt("intent", intentUri);
    notification.putOpt("click_action", clickAction);
    pushPayload.put("hwField", notification);
} catch (JSONException e) {
    e.printStackTrace();
}

当接收方收到华为推送时,处理方式请参考华为开放平台:点击通知消息

OPPO推送

发送消息前,在云信消息体的 pushPayload 中传入 key 为 oppoField 的Map或者JsonObject类型的数据,通常为 发送者的account/ 群聊id 与类型(单聊或群聊)等信息,这些信息将被透传到推送的接收方。数据的参数请参考OPPO开放平台:通知栏消息

// oppoField
Map<String, Object> oppoField = new HashMap<>();
Editable oppoChannelId = oppoChannelIdET.getText();
oppoField.put("click_action_type", 1);
oppoField.put("click_action_activity", "com.oppo.codelabpush.intent.action.test");
// oppoField.put("click_action_type", 4);
// oppoField.put("click_action_activity", "com.netease.nim.demo.main.activity.MixPushActivity");
JSONObject obj = new JSONObject();
try {
    obj.putOpt("sessionID", sessionType == SessionTypeEnum.P2P ? TestCache.getAccount() : msg.getSessionId());
    obj.putOpt("sessionType", sessionType.getValue());
} catch (JSONException e) {
    e.printStackTrace();
}
oppoField.put("action_parameters", obj.toString());
pushPayload.put("oppoField", oppoField);

当接收方收到OPPO推送时,处理方式请参考OPPO开放平台:通知栏消息

谷歌推送

点击谷歌推送通知栏之后,直接启动应用入口Activity,通过Intent 携带数据,SDK 提供接口判断是否是云信侧集成的 FCM Intent。

MixPushService提供两个接口处理 FCM payload:

/**
 * Activity是否是由点击 fcm 通知启动
 *
 * @param intent activity intent
 * @return 判断结果
 */
boolean isFCMIntent(Intent intent);

/**
 * 从 FCM 中解出 payload 字符串
 *
 * @param intent activity intent
 * @return
 */
String parseFCMPayload(Intent intent);

即时通讯Demo中,在 WelcomeActivity.java 的 onIntent 中判断:if (NIMClient.getService(MixPushService.class).isFCMIntent(intent)),具体代码请参考Demo。

其他推送

对于推送,发送方在构造消息对象时,需要通过IMMessage.setPushPayload(Map pushPayload)插入表示会话标识的信息(如自身的账号、群id、会话类型等),便于接收端获取到 payload 时解析出来。

推送通知栏点击事件的回调由 MixPushMessageHandler 提供:

public interface MixPushMessageHandler {

    /**
     * 推送通知栏点击之后的回调方法
     *
     * @param context
     * @param payload IMessage 中的用户设置的自定义pushPayload {@link com.netease.nimlib.sdk.msg.model.IMMessage}
     * @return true 表示开发者自行处理第三方推送通知栏点击事件,SDK将不再处理; false 表示仍然使用SDK提供默认的点击后的跳转
     */
    boolean onNotificationClicked(Context context, Map<String, String> payload);
}

开发者需要在Application#oncreate中,主进程中进行MixPushMessageHandler的注册,如Demo示例:

if (NIMUtil.isMainProcess(this)) {
    // 注册自定义推送消息处理,这个是可选项
    NIMPushClient.registerMixPushMessageHandler(new DemoMixPushMessageHandler());
}

消息提醒通知栏跳转

可以通过StatusBarNotificationConfig.notificationEntrance参数来设置通知栏提醒的响应Intent的Activity,通过NIMClient.updateStatusBarNotificationConfig(StatusBarNotificationConfig config)来更新通知栏消息提醒设置。

对于即时通讯Demo来说,存在以下逻辑:

[注意] 关于EXTRA_NOTIFY_CONTENT的含义请参考EXTRA_NOTIFY_CONTENT