【玩转腾讯云】初识腾讯移动通讯 TPNS~

2021-04-08 09:45:20 浏览数 (2)

    和尚之前因业务需求,配合过推送平台的相关搭建,其中涉及过 友盟 UmengPush极光 JPush个推公司自建 UPDPush华为 HMS小米 MiPushOPPO PushVIVO Push 等;今天借 腾讯云 活动,简单了解一下 腾讯移动通讯 TPNS

    和尚了解 腾讯移动通讯 TPNS 前身是腾讯信鸽,前期经过长期等技术沉淀积累了良好的口碑;现在由免费转为付费,相信会提供更优质的服务;而精准用户标签是 TPNS 的一个巨大优势;

1. TPNS 基本介绍

    TPNS 为移动推送 Tencent Push Notification Service 首字母缩写,为 app 提供稳定、快速、高抵达的推送服务;具备多种推送形式和方式,支持小米、华为、魅族、vivoOPPO 等国内主流厂商通道集成,Google 境外支持 FCM 通道,可以做到单推毫秒级抵达;其具备精准用户标签能力,有效助力 app 的精细化运营;

2. TPNS 集成

    接下来和尚简单介绍一下 TPNS 的集成,据和尚了解,一般的 Push 接入方式主要是 Gradle 自动集成jar 手动集成 两种;特殊的还有华为 Push 通过 config 方式导入配置方式等;而令和尚意外的是 TPNS 支持三种方式的接入;

    和尚主要介绍 configGradle 自动集成两种方式;两种集成方式都非常简单,同时和尚不得不夸赞一下官网的接入文档,真的非常人性化;

2.1 config 导入配置项
  • a. 在 TPNS【基本配置】中下载对应 app 的配置文件,并添加在 app 根目录下
  • b. 在项目级 build.gradle 中添加配置信息
代码语言:txt复制
buildscript {
    ......
    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'
        classpath "com.tencent.android.tpns:tpnsplugin:1.7.0"
    }
}

allprojects {
    repositories {
        ......
        maven { url 'https://dl.bintray.com/umsdk/release' }
        maven {url 'http://developer.huawei.com/repo/'}
    }
}
  • c. 在应用级 app build.gradle 中添加依赖
  • d. 配置混淆文件
代码语言:txt复制
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep class com.tencent.android.tpush.** {*;}
-keep class com.tencent.tpns.baseapi.** {*;}
-keep class com.tencent.tpns.mqttchannel.** {*;}
-keep class com.tencent.tpns.dataacquisition.** {*;}
2.2 Gradle 自动集成
  • a. 在 TPNS【基本配置】中获取对应 app 的 ID 和 KEY
  • b. 在 app build.gradle 文件下配置 ID 和 KEY 以及 SDK 版本
代码语言:txt复制
android {
  ......
  defaultConfig {
      applicationId "com.ace.demo01"
      ......
       ndk {
          abiFilters "armeabi", "armeabi-v7a"
      }
      manifestPlaceholders = 
          XG_ACCESS_ID : "1500018288",
          XG_ACCESS_KEY : "AYFMNKBGT92Z",
      
      multiDexEnabled true
  }
  ......
}
dependencies {
  ......
  //添加以下依赖
  implementation 'com.tencent.jg:jg:1.1'
  implementation 'com.tencent.tpns:tpns:1.2.3.1-release'
}
  • c. 配置混淆文件

3. TPNS 应用

    上述只是对 TPNS 的简单集成,对于应用还需要初始化以及接收推送等一系列业务操作;还可以进行一系列复杂操作,比如根据标签自定义定量定向发送 Push 等;和尚仅根据最基础需求进行学习测试;

3.1 初始化获取 Token

    集成 TPNS 之后都需要初始化,其中 Token 作为唯一标识可以通过 registerPush 初始化获取,也可以通过继承 XGPushBaseReceiver 广播并在 onRegisterResult 回调中进行监听;

代码语言:txt复制
XGPushManager.registerPush(this, new XGIOperateCallback() {
    @Override
    public void onSuccess(Object data, int flag) {
        //token在设备卸载重装的时候有可能会变
        Log.d("TPush:", "注册成功,设备token为:"   data);
    }

    @Override
    public void onFail(Object data, int errCode, String msg) {
        Log.d("TPush:", "注册失败,错误码:"   errCode   ",错误信息:"   msg);
    }
});

@Override
public void onRegisterResult(Context context, int errorCode, XGPushRegisterResult message) {
    if (context == null || message == null) {
        return;
    }
    String text = "";
    if (errorCode == XGPushBaseReceiver.SUCCESS) {
        // 在这里拿token
        String token = message.getToken();
        text = "注册成功1. token:"   token;
    } else {
        text = message   "注册失败,错误码:"   errorCode;
    }
    Log.d(LogTag, text);
}

    XGPushBaseReceiver 用于接收消息和结果反馈的 Receiver,需要开发者在 AndroidManifest.xml 自主完成静态注册;不管是通知类 Push 还是透传类 Push 均需通过 XGPushBaseReceiver 中的回调来处理;

3.2 通知类 Push

    首先我们需要了解 通知类 Push 发布平台,里面涉及很多内容,其中有几点需要注意:

  • 【通知标题】和【通知内容】对应推送消息中展示内容;
  • 【高级设置】里面可以通过【附加参数】传递标题和内容之外的其他消息内容,供用户自定义;
  • 【推送时间】可以设置立即或延迟推送;
  • 【推送目标】可以发布全量 Push 或根据地理围栏定向推送以及根据 Token 固定设备推送;
  • 【角标数字】在华为和小米手机开启角标通知权限之后,会自动增加一,而无需用户自己适配,减轻了开发者工作量;
  • 【点击打开】TPNS 提供了四种点击 Push 后续操作方式,分别是仅打开应用 app;客户端自定义,此时需要在清单文件中设置 Intent 配置信息;URL 网络路径;应用内 Activity,但官方并不推荐使用,需要设置 Activity 的完整路径;

    通知类 Push 收到和点击事件通过 XGPushBaseReceiver 回调进行监听;onNotificationShowedResult 为通知类 Push 展示回调,但和尚反复测试,通知类 Push 中标题和内容只能是 XGPushShowedResult.getTitle()XGPushShowedResult.getContent() 对应内容,无法更改;onNotificationClickedResult 为通知类 Push 点击时回调,业务处理主要是在该回调方法中完成;

代码语言:txt复制
/**
 * 通知展示
 * @param notifiShowedRlt 包含通知的内容
 */
@Override
public void onNotificationShowedResult(Context context, XGPushShowedResult notifiShowedRlt) {
    if (context == null || notifiShowedRlt == null) {
        return;
    }
    Log.e("通知类 Push", "onNotificationShowedResultn"
          notifiShowedRlt.getCustomContent()
          "n"
          notifiShowedRlt.getPushChannel()
          "n"
          notifiShowedRlt.getNotifactionId()
          "n"
          notifiShowedRlt.toString());
    Log.d(LogTag, "您有1条新消息, 通知被展示;"   notifiShowedRlt.toString()   ", PushChannel:"   notifiShowedRlt.getPushChannel());
}

/**
 * 通知点击回调 
 * actionType=1为该消息被清除,actionType=0为该消息被点击
 * @param message 包含被点击通知的内容
 */
@Override
public void onNotificationClickedResult(Context context, XGPushClickedResult message) {
    if (context == null || message == null) {
        return;
    }
    String text = "";
    if (message.getActionType() == NotificationAction.clicked.getType()) {
        // 通知在通知栏被点击
        // APP自己处理点击的相关动作
        text = "通知被打开 :"   message;
    } else if (message.getActionType() == NotificationAction.delete.getType()) {
        // 通知被清除
        // APP自己处理通知被清除后的相关动作
        text = "通知被清除 :"   message;
    }
    Toast.makeText(context, "广播接收到通知被点击:"   message.toString(), Toast.LENGTH_SHORT).show();
    // 获取自定义key-value
    String customContent = message.getCustomContent();
    if (customContent != null && customContent.length() != 0) {
        try {
            JSONObject obj = new JSONObject(customContent);
            if (!obj.isNull("extras")) {
                PushInfo pushInfo = new Gson().fromJson(obj.getString("extras"), PushInfo.class);
                if (pushInfo != null) {
                    Log.e("PushInfo: ", pushInfo.title   pushInfo.desc);
                }
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
    
    Intent intent = new Intent(context, PageActivity.class);
    intent.putExtra("pushInfo", customContent);
    intent.putExtra("from", "通知类消息");
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.getApplicationContext().startActivity(intent);
}

    对于通知类 Push 点击的操作,TPNS 提供了四种默认的方式,但和尚为了适配其他的 Push 类型,调整了点击后的操作,默认为启动 app,之后的业务逻辑通过解析【附加参数】来进行不同的业务处理;例如根据某一个字段不同进行不同页面的跳转等;

3.3 透传类 Push

    透传类消息后台相对于通知类型要简单,主要区分在【高级设置】中,透传类因厂商限制,不能通过厂商通道下发,仅通过 TPNS 通道下发;且透传类消息下发之后不会出现 Notification,需要自己根据业务来处理;

代码语言:txt复制
/**
 * 消息透传处理
 * @param message 解析自定义的 JSON
 */
@Override
public void onTextMessage(Context context, XGPushTextMessage message) {
    String text = "收到消息:"   message.toString();
    // 获取自定义key-value
    String customContent = message.getCustomContent();
    PushInfo pushInfo = Utils.getPushInfo(customContent);
    showNotification(context, getNotification(context, pushInfo, customContent));
}

public static Notification getNotification(Context context, PushInfo pushInfo, String msg) {
    Notification notification = null;
    try {
        Intent intent = new Intent(context, PageActivity.class);
        intent.putExtra("pushInfo", msg);
        intent.putExtra("from", "透传类消息");
        PendingIntent pendingIntent =
            PendingIntent.getActivity(context, new java.util.Random().nextInt(1000), intent,
                PendingIntent.FLAG_CANCEL_CURRENT);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, "ace_push");
        notificationBuilder.setContentIntent(pendingIntent);
        notificationBuilder.setContentText(pushInfo.desc);
        notificationBuilder.setContentTitle(pushInfo.title);
        notificationBuilder.setSmallIcon(R.mipmap.icon_logo);
        notificationBuilder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.icon_logo));
        notificationBuilder.setAutoCancel(true);
        notificationBuilder.setOngoing(false);
        notificationBuilder.setWhen(System.currentTimeMillis());
        notificationBuilder.setDefaults(Notification.DEFAULT_ALL);
        notification = notificationBuilder.build();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return notification;
}

public void showNotification(Context context, Notification notification) {
    NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    if (manager != null) {
        manager.notify(new java.util.Random().nextInt(1000), notification);
    }
}

    和尚为了适配多种类型推送消息,通过解析【高级设置】中的【附加参数】中的 Json 来展示通知栏消息;

  • Notification 展示在 Android8.0 之后需要设置 NotificationChannel 通道
  • app kill 状态下不会收到透传类消息,需要启动应用之后才会收到消息,包括历史消息

4. TPNS 小对比

    和尚尝试了多家推送模块,简单分析如下:

优势:
  1. TPNS 集成方式最为丰富和简单;
  2. TPNS 中的定向标签丰富,推送精准,方便进行更精细化的运营;
  3. TPNS 统计后台做的最为丰富全面;可以实时统计推送的抵达、展示、点击效果等数据口径,并将以上数据在管理台可视化地展现出来;
不足:
  1. TPNS 付费模式可能会损失一些中小型 app 用户;
  2. TPNS 通知类消息未提供消息送达的回调方法,对于 app 自身维度的统计略有不便;
  3. TPNS 未提及类似【极光轻推送】之类的辅助激活唤醒老用户的功能;

5. TPNS 小建议

    TPNS 已经积累了足够的技术沉淀,使用也非常简单,官方文档介绍的非常详细;和尚作为最底层的码农,仅就集成使用过程中提出一点点小小的个人见解,如有错误,请多多指导!

1.XGPushBaseReceiver 中是否可以减少抽象方法,对于用户不需要的业务模块,每次实现所有的抽象方法是否略微有些冗余;

代码语言:txt复制
public abstract void onRegisterResult(Context var1, int var2, XGPushRegisterResult var3);

public abstract void onUnregisterResult(Context var1, int var2);

public abstract void onSetTagResult(Context var1, int var2, String var3);

public abstract void onDeleteTagResult(Context var1, int var2, String var3);

public abstract void onSetAccountResult(Context var1, int var2, String var3);

public abstract void onDeleteAccountResult(Context var1, int var2, String var3);

public abstract void onSetAttributeResult(Context var1, int var2, String var3);

public abstract void onDeleteAttributeResult(Context var1, int var2, String var3);

public abstract void onTextMessage(Context var1, XGPushTextMessage var2);

public abstract void onNotificationClickedResult(Context var1, XGPushClickedResult var2);

public abstract void onNotificationShowedResult(Context var1, XGPushShowedResult var2);

2.通知类消息在通知栏中的标题和内容无法通过【高级设置】中的【附加参数】来更改;如果用户可以自由的定义设置就更方便了;

3.服务后台中的【推送任务】在历史任务列表中,如果有【复用】的功能的话,会大大减轻开发测试和运营同学的工作量;这个功能在友盟和极光等推送平台都有,真的很方便;

UmengUmeng
JPushJPush
TPNSTPNS

4.希望 TPNS 可以提供类似【极光轻推送】辅助激活唤醒老用户的功能;


    和尚仅尝试了 TPNS 最基础的推送功能,对于高级的用户标签暂未涉及,同时对【实时推送效果分析】后台观察不足;同时涉及到其他厂商的推送模块,和尚仅以基础程序员角度学习和了解,并未涉及任何商业优劣区分;如有错误,请多多指导!

来源: 阿策小和尚

0 人点赞