Flutter 120: Flutter & 腾讯移动通讯 TPNS~

    小菜前两天刚学习了原生 Android 腾讯移动通讯 TPNS,发现同时提供了 Flutter_Plugin,今天尝试一下对 Flutter 的支持;

Flutter TPNS

1. 基本接入

1.1 环境配置

    小菜在接入 Flutter TPNS 时,需要在 FlutterAndroid 两端进行插件的安装配置;

  • Flutter

    在工程 pubspec.yamldependencies 下引入 tpns_flutter_plugin 插件;

dependencies:
  flutter:
    sdk: flutter
  tpns_flutter_plugin:
    git:
      url: https://github.com/TencentCloud/TPNS-Flutter-Plugin
      ref: V1.0.7
  • Android

    在 app build.gradle 文件下配置 IDKEY 以及支持的 .so 库

defaultConfig {
    applicationId "com.ace.plugin.flutter_app07"
    minSdkVersion 16
    targetSdkVersion 28
    versionCode flutterVersionCode.toInteger()
    versionName flutterVersionName
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    ndk {
        abiFilters 'armeabi', 'armeabi-v7a', 'x86', 'x86_64', 'mips', 'mips64', 'arm64-v8a', 'arm6'
    }
    manifestPlaceholders = [
        XG_ACCESS_ID : "1500018481",
        XG_ACCESS_KEY : "AW8Y2K3KXZ38",
    ]
}

1.2 方法使用

    小菜按照官网的介绍尝试了一些常用的 API 方式,主要分为应用类,账号类和标签类三种 API,小菜业务中没有应用账号和标签模块,暂未深入研究;

  • 应用接口 API
a. 注册推送服务

    对于服务的注册初始化,可以在首次进入应用 initState() 中直接初始化,也可以根据业务逻辑在固定的位置进行初始化,需要传递申请的账号 IDKEY;注册成功之后会在 onRegisteredDone() 中进行回调,并获取对应设备的唯一 Token

XgFlutterPlugin().startXg("1500018481", "AW8Y2K3KXZ38");

// 注册回调
XgFlutterPlugin().addEventHandler(
  onRegisteredDone: (String msg) async {
    print("HomePage -> onRegisteredDone -> $msg");
    _showDialog('注册成功', msg);
  },
);
b. 注销推送服务

    服务的注销方法可以通过 stopXg() 进行处理,并在 unRegistered 进行回调监听;

XgFlutterPlugin().stopXg();

// 注销回调
XgFlutterPlugin().addEventHandler(
  unRegistered: (String msg) async {
    print("HomePage -> unRegistered -> $msg");
  },
);
c. 设备推送标识

    对于设备唯一标识的获取,可以通过注册初始化成功之后获取,也可以通过 XgFlutterPlugin.xgToken 获取唯一 Token

Future<void> getTPNSToken(title) async {
  try {
    String xgToken = await XgFlutterPlugin.xgToken;
    print('HomePage -> getTPNSToken -> $xgToken');
    _showDialog(title, xgToken);
  } catch (e) {
    print(e.toString());
  }
}
d. 上报角标数

    对于桌面角标,在通知类消息中 华为小米 设备在开启权限之后,接收通知会由桌面角标的更新;而 TPNS 提供的 setBadge() 只有在 iOS 环境下支持,对于 Android 环境下的透传类型或其他厂商设备的支持,可以通过 FlutterNative 通信来由原生实现;

e. SDK 版本

    TPNS SDK 版本可以通过 XgFlutterPlugin.xgSdkVersion 获取;

Future<void> getTPNSSDKVersion(title) async {
  try {
    String sdkVersion = await XgFlutterPlugin.xgSdkVersion;
    print('HomePage -> getTPNSSDKVersion -> $sdkVersion');
    _showDialog(title, sdkVersion);
  } catch (e) {
    print(e.toString());
  }
}
  • 账号接口 API
        TPNS 提供了个性化服务,关于账号的绑定和解绑等功能,可以根据具体的业务逻辑进行处理;
String inputStr = "ACE_Flutter";
// 设置账号
XgFlutterPlugin().setAccount(inputStr, AccountType.UNKNOWN);
// 解绑账号
XgFlutterPlugin().deleteAccount(inputStr, AccountType.UNKNOWN);
// 清空账号
XgFlutterPlugin().cleanAccounts();

XgFlutterPlugin().addEventHandler(
  xgPushDidBindWithIdentifier: (String msg) async {
    print("HomePage -> xgPushDidBindWithIdentifier -> $msg");
    _showDialog('绑定标签 $inputStr', msg);
  },
  xgPushDidUnbindWithIdentifier: (String msg) async {
    print("HomePage -> xgPushDidUnbindWithIdentifier -> $msg");
    _showDialog('解绑账号', msg);
  },
  xgPushDidClearAllIdentifiers: (String msg) async {
    print("HomePage -> xgPushDidClearAllIdentifiers -> $msg");
    _showDialog('清除全部账号', msg);
  }
)
  • 标签接口 API
        TPNS 的用户标签功能比较强大,可以针对性的进行地理围栏或标签分布的推送;TPNS 提供了绑定和解绑标签,更新和清理标签等功能,方便针对性的进行数据推送;
String inputStr = "ACE_Flutter";
// 绑定标签
XgFlutterPlugin().addTags([inputStr]);
// 解绑标签
XgFlutterPlugin().deleteTags([inputStr]);
// 更新标签
XgFlutterPlugin().setTags([inputStr]);
// 清除标签
XgFlutterPlugin().cleanTags();

2. 通知类消息

    小菜在上一篇文章中介绍了 TPNS 消息发布后台,不管是哪种方式集成,发布后台是一致的;

2.1 接收 & 展示

    通知类 Push 在设备开启权限时,接收消息后会自动展示通知,这是由 TPNS SDK 实现好的,与原生一致,通知类 Push 标题和内容也只能以通过消息后台发布为准,不能自由更改;其中 通知类 Push 接收通过 onReceiveNotificationResponse() 方法回调监听;

XgFlutterPlugin().addEventHandler(
  onReceiveNotificationResponse: (Map<String, dynamic> msg) async {
    print("HomePage -> onReceiveNotificationResponse -> $msg");
    _showDialog('通知类消息接收', msg.toString());
  },
);
TPNS_通知类_接收.jpg

TPNS_通知类_展示.jpg

2.2 点击

    通知类 Push 消息点击是通过 xgPushClickAction() 方法进行回调,之后的业务逻辑可以根据消息返回的信息进行处理;小菜为了适配其他的 Push 类型,调整了点击后的操作,默认为启动 app,小菜通常在【附加参数】中添加 Json 进行数据解析,在进行之后的业务处理;

XgFlutterPlugin().addEventHandler(
  xgPushClickAction: (Map<String, dynamic> msg) async {
    print("HomePage -> xgPushClickAction -> $msg");
    _showDialog('通知类消息点击', msg.toString());
  },
);
TPNS_通知类_点击.jpg

3. 透传类消息

    透传类 Push 相比 通知类 Push 要复杂一些,TPNS 只提供了 透传类 Push 接收,不会进行 Notification 通知展示;因此小菜通过 Flutter-Native 消息通信进行处理;其中 Notification 的展示点击需要 Native 方面进行配合处理;

3.1 接收

    透传类 Push 通过 onReceiveMessage() 进行消息接收的回调监听;之后,小菜建立一个 MethodChannel 将消息传递给 Android Native

XgFlutterPlugin().addEventHandler(
    onReceiveMessage: (Map<String, dynamic> msg) async {
      print("HomePage -> onReceiveMessage -> $msg");
      _showDialog('透传类消息接收', msg.toString());
      await methodChannel
          .invokeMethod('tpns_extras', msg['customMessage'])
          .then((val) {
        print("HomePage -> 透传类消息接收 -> $val");
        if (val != null) {
          _showDialog('透传类消息点击', val);
        }
      });
    },
);
TPNS_透传类_接收.jpg

3.2 展示

    Flutter 端在接收到 透传类 Push 消息时,发送 MethodChannelAndroid NativeNative 端在解析对应参数进行 Notification 展示;

@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
    GeneratedPluginRegistrant.registerWith(flutterEngine);
    new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(),
        "com.ace.plugin.flutter_app/tpns_notification").setMethodCallHandler(new MethodChannel.MethodCallHandler() {
        @Override
        public void onMethodCall(MethodCall call, MethodChannel.Result result) {
            if (call != null && call.method.equals("tpns_extras")) {
                setNotification(MainActivity.this, call.arguments.toString());
                mResult = result;
            } else {
                result.notImplemented();
            }
        }
    });
}
TPNS_透传类_展示.jpg

3.3 点击

    Native 端展示 Notification 后,小菜尝试两种方式,第一种是通过一个新的 BasicMessageChannel 来进行消息通信到 Flutter 端,第二种是通过之前 Flutter 发送的 MethodChannel 进行 result 回调;小菜虽然应用了第二种方式,但更倾向于第一种,每个事件更加专一;

    Flutter 端接收到 Native 发送或返回的消息后便可自由进行业务逻辑处理了;

private void setNotification(Context context, String extras) {
    NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel channel =
            new NotificationChannel("ace_push", "ace_push_name", NotificationManager.IMPORTANCE_HIGH);
        if (notificationManager != null) {
            notificationManager.createNotificationChannel(channel);
        }
    }
    int notificationId = new java.util.Random().nextInt(1000);

    //Intent intent = new Intent(MainActivity.this, TPNSNotificationReceiver.class);
    //PendingIntent pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 101, intent, 102);
    Intent intent = new Intent(context, MainActivity.class);
    intent.putExtra("push_extras", extras);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    PendingIntent pendingIntent =
        PendingIntent.getActivity(context, notificationId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
    JSONObject json = JSONObject.parseObject(extras);
    String extrasStr = json.getString("extras");
    json = JSONObject.parseObject(extrasStr);
    String title = json.getString("title");
    String desc = json.getString("desc");
    Notification notification = new NotificationCompat.Builder(context, "ace_push").setContentTitle(title)
        .setContentText(desc)
        .setContentIntent(pendingIntent)
        .setWhen(System.currentTimeMillis())
        .setSmallIcon(R.mipmap.ic_launcher)
        .setAutoCancel(true)
        .build();
    notificationManager.notify(notificationId, notification);
}
TPNS_透传类_点击.jpg

3.4 注意事项

    小菜在 PendingIntent 中传递的页面依旧是 MainActivity,可以根据具体的业务逻辑启动专门的中转页面;其中使用 MainActivity 时需要,因为设置了 FlagIntent.FLAG_ACTIVITY_NEW_TASK 因此注意数据的接收通过 onNewIntent 进行接收;

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    if (intent != null && intent.getExtras() != null && intent.getExtras().containsKey("push_extras")) {
        String extras = intent.getStringExtra("push_extras");
        if (mResult != null) {
            mResult.success(extras);
        }
    }
}

    Flutter TPNS 案例源码


    小菜对于 Flutter TPNS 中很多高级方法还未做尝试,仅实现最基本的通知类和透传类 Push 的接收展示点击等;如有错误请多多指导!

来源: 阿策小和尚

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,273评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,349评论 3 398
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,709评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,520评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,515评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,158评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,755评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,660评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,203评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,287评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,427评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,122评论 5 349
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,801评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,272评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,393评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,808评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,440评论 2 359

推荐阅读更多精彩内容