小菜前两天刚学习了原生 Android 腾讯移动通讯 TPNS,发现同时提供了 Flutter_Plugin,今天尝试一下对 Flutter 的支持;
Flutter TPNS
1. 基本接入
1.1 环境配置
小菜在接入 Flutter TPNS 时,需要在 Flutter 和 Android 两端进行插件的安装配置;
在工程 pubspec.yaml 中 dependencies 下引入 tpns_flutter_plugin 插件;
dependencies: flutter: sdk: flutter tpns_flutter_plugin: git: url: https://github.com/TencentCloud/TPNS-Flutter-Plugin ref: V1.0.7
复制代码
在 app build.gradle 文件下配置 ID 和 KEY 以及支持的 .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,小菜业务中没有应用账号和标签模块,暂未深入研究;
a. 注册推送服务
对于服务的注册初始化,可以在首次进入应用 initState() 中直接初始化,也可以根据业务逻辑在固定的位置进行初始化,需要传递申请的账号 ID 和 KEY;注册成功之后会在 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 环境下的透传类型或其他厂商设备的支持,可以通过 Flutter 与 Native 通信来由原生实现;
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()); }}
复制代码
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); })
复制代码
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()); },);
复制代码
2.2 点击
通知类 Push 消息点击是通过 xgPushClickAction() 方法进行回调,之后的业务逻辑可以根据消息返回的信息进行处理;小菜为了适配其他的 Push 类型,调整了点击后的操作,默认为启动 app,小菜通常在【附加参数】中添加 Json 进行数据解析,在进行之后的业务处理;
XgFlutterPlugin().addEventHandler( xgPushClickAction: (Map<String, dynamic> msg) async { print("HomePage -> xgPushClickAction -> $msg"); _showDialog('通知类消息点击', msg.toString()); },);
复制代码
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); } }); },);
复制代码
3.2 展示
Flutter 端在接收到 透传类 Push 消息时,发送 MethodChannel 到 Android Native,Native 端在解析对应参数进行 Notification 展示;
@Overridepublic 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(); } } });}
复制代码
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);}
复制代码
3.4 注意事项
小菜在 PendingIntent 中传递的页面依旧是 MainActivity,可以根据具体的业务逻辑启动专门的中转页面;其中使用 MainActivity 时需要,因为设置了 Flag 为 Intent.FLAG_ACTIVITY_NEW_TASK 因此注意数据的接收通过 onNewIntent 进行接收;
@Overrideprotected 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 的接收展示点击等;如有错误请多多指导!
来源: 阿策小和尚
评论