import 'dart:async'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'cloud_push_message.dart'; import 'cloud_push_service_enums.dart'; import 'common_callback_result.dart'; final MethodChannel _channel = const MethodChannel('com.jarvanmo/rammus') ..setMethodCallHandler(_handler); StreamController<CommonCallbackResult> _initCloudChannelResultController = StreamController.broadcast(); ///注意可能被多次调用。 ///Android SDK文档原话如下: ///如果设备成功注册,将回调callback.onSuccess()方法。 ///但如果注册服务器连接失败,则调用callback.onFailed方法,并且自动进行重新注册,直到onSuccess为止。(重试规则会由网络切换等时间自动触发。) ///请在网络通畅的情况下进行相关的初始化调试,如果网络不通,或者App信息配置错误,在onFailed方法中,会有相应的错误码返回,可参考错误处理 Stream<CommonCallbackResult> get initCloudChannelResult => _initCloudChannelResultController.stream; ///用于接收服务端推送的消息。 ///消息不会弹窗,而是回调该方法。 StreamController<CloudPushMessage> _onMessageArrivedController = StreamController.broadcast(); Stream<CloudPushMessage> get onMessageArrived => _onMessageArrivedController.stream; ///客户端接收到通知后,回调该方法。 ///可获取到并处理通知相关的参数。 StreamController<OnNotification> _onNotificationController = StreamController.broadcast(); Stream<OnNotification> get onNotification => _onNotificationController.stream; ///打开通知时会回调该方法,通知打开上报由SDK自动完成。 StreamController<OnNotificationOpened> _onNotificationOpenedController = StreamController.broadcast(); Stream<OnNotificationOpened> get onNotificationOpened => _onNotificationOpenedController.stream; ///删除通知时回调该方法,通知删除上报由SDK自动完成。 StreamController<String> _onNotificationRemovedController = StreamController.broadcast(); Stream<String> get onNotificationRemoved => _onNotificationRemovedController.stream; ///打开无跳转逻辑(open=4)通知时回调该方法(v2.3.2及以上版本支持),通知打开上报由SDK自动完成。 StreamController<OnNotificationClickedWithNoAction> _onNotificationClickedWithNoActionController = StreamController.broadcast(); Stream<OnNotificationClickedWithNoAction> get onNotificationClickedWithNoAction => _onNotificationClickedWithNoActionController.stream; ///当用户创建自定义通知样式,并且设置推送应用内到达不创建通知弹窗时调用该回调,且此时不调用onNotification回调(v2.3.3及以上版本支持) StreamController<OnNotificationReceivedInApp> _onNotificationReceivedInAppController = StreamController.broadcast(); Stream<OnNotificationReceivedInApp> get onNotificationReceivedInApp => _onNotificationReceivedInAppController.stream; ///确保注册成功以后调用获取[deviceId] Future<String?> get deviceId async { return _channel.invokeMethod("deviceId"); } Future<CommonCallbackResult> get pushChannelStatus async { var result = await _channel.invokeMethod("checkPushChannelStatus"); return CommonCallbackResult( isSuccessful: result["isSuccessful"], response: result["response"], errorCode: result["errorCode"], errorMessage: result["errorMessage"], ); } /// 注册设备 /// 仅在 Android 设备生效,且在 Android 端若希望插件正常工作,必须执行一次本方法 /// 分离插件初始化与注册的过程,例如实现在用户同意了隐私政策后再进行远端注册,防止影响应用上架。 void register() { if (Platform.isAndroid) _channel.invokeMethod("register"); } // static Future<String> get platformVersion async { // final String version = await _channel.invokeMethod('getPlatformVersion'); // return version; // } ///这个返回结果永远都是[true],并不是SDK初始化结果 ///初始化结果请监听[initCloudChannelResult] ///只能初始化ios //Future<bool> initCloudChannel({String appKey, String appSecret}) async { // return await _channel.invokeMethod( // "initCloudChannel", {"appKey": appKey, "appSecret": appSecret}); //} Future<CommonCallbackResult> turnOnPushChannel() async { var result = await _channel.invokeMethod("turnOnPushChannel"); return CommonCallbackResult( isSuccessful: result["isSuccessful"], response: result["response"], errorCode: result["errorCode"], errorMessage: result["errorMessage"], ); } Future<CommonCallbackResult> turnOffPushChannel() async { var result = await _channel.invokeMethod("turnOffPushChannel"); return CommonCallbackResult( isSuccessful: result["isSuccessful"], response: result["response"], errorCode: result["errorCode"], errorMessage: result["errorMessage"], ); } /// Android 文档 ///将应用内账号和推送通道相关联,可以实现按账号的定点消息推送; ///设备只能绑定一个账号,同一账号可以绑定到多个设备; ///同一设备更换绑定账号时无需进行解绑,重新调用绑定账号接口即可生效; ///若业务场景需要先解绑后绑定,在解绑账号成功回调中进行绑定绑定操作,以此保证执行的顺序性; ///账户名设置支持64字节。 Future<CommonCallbackResult> bindAccount(String account) async { assert(account != null); var result = await _channel.invokeMethod("bindAccount", account); return CommonCallbackResult( isSuccessful: result["isSuccessful"], response: result["response"], errorCode: result["errorCode"], errorMessage: result["errorMessage"], iosError: result["iosError"]); } Future<CommonCallbackResult> unbindAccount() async { var result = await _channel.invokeMethod("unbindAccount"); return CommonCallbackResult( isSuccessful: result["isSuccessful"], response: result["response"], errorCode: result["errorCode"], errorMessage: result["errorMessage"], iosError: result["iosError"]); } ///Android only Future<CommonCallbackResult> bindPhoneNumber(String phoneNumber) async { var result = await _channel.invokeMethod("bindPhoneNumber", phoneNumber); return CommonCallbackResult( isSuccessful: result["isSuccessful"], response: result["response"], errorCode: result["errorCode"], errorMessage: result["errorMessage"], iosError: result["iosError"]); } ///Android only Future<CommonCallbackResult> unbindPhoneNumber() async { var result = await _channel.invokeMethod("unbindPhoneNumber"); return CommonCallbackResult( isSuccessful: result["isSuccessful"], response: result["response"], errorCode: result["errorCode"], errorMessage: result["errorMessage"], iosError: result["iosError"]); } //void bindTag(int target, String[] tags, String alias, CommonCallback callback); ///Android 文档 ///绑定标签到指定目标; ///支持向设备、账号和别名绑定标签,绑定类型由参数target指定; ///绑定标签在10分钟内生效; ///App最多支持绑定1万个标签,单个标签最大支持128字符。 ///target 目标类型,1:本设备; 2:本设备绑定账号; 3:别名 ///target(V2.3.5及以上版本) 目标类型,CloudPushService.DEVICE_TARGET:本设备; CloudPushService.ACCOUNT_TARGET:本账号; CloudPushService.ALIAS_TARGET:别名 ///tags 标签(数组输入) ///alias 别名(仅当target = 3时生效) ///callback 回调 Future<CommonCallbackResult> bindTag( {@required CloudPushServiceTarget? target, List<String>? tags, String? alias}) async { var result = await _channel.invokeMethod("bindTag", { "target": target!.index + 1, "tags": tags ?? <String>[], "alias": alias }); return CommonCallbackResult( isSuccessful: result["isSuccessful"], response: result["response"], errorCode: result["errorCode"], errorMessage: result["errorMessage"], iosError: result["iosError"]); } ///Android 文档 ///解绑指定目标标签; ///支持解绑设备、账号和别名标签,解绑类型由参数target指定; ///解绑标签在10分钟内生效; ///解绑标签只是解除设备和标签的绑定关系,不等同于删除标签,即该APP下标签仍然存在,系统目前不支持标签的删除。 ///target 目标类型,1:本设备; 2:本设备绑定账号; 3:别名 ///target(V2.3.5及以上版本) 目标类型,CloudPushService.DEVICE_TARGET:本设备; CloudPushService.ACCOUNT_TARGET:本账号; CloudPushService.ALIAS_TARGET:别名 ///tags 标签(数组输入) ///alias 别名(仅当target = 3时生效) ///callback 回调 Future<CommonCallbackResult> unbindTag( {@required CloudPushServiceTarget? target, List<String>? tags, String? alias}) async { var result = await _channel.invokeMethod("unbindTag", { "target": target!.index + 1, "tags": tags ?? <String>[], "alias": alias }); return CommonCallbackResult( isSuccessful: result["isSuccessful"], response: result["response"], errorCode: result["errorCode"], errorMessage: result["errorMessage"], iosError: result["iosError"]); } ///Android 文档 ///查询目标绑定标签,当前仅支持查询设备标签; ///查询结果可从回调onSuccess(response)的response获取; ///标签绑定成功且生效(10分钟内)后即可查询。 Future<CommonCallbackResult> listTags(CloudPushServiceTarget target) async { var result = await _channel.invokeMethod("listTags", target.index + 1); return CommonCallbackResult( isSuccessful: result["isSuccessful"], response: result["response"], errorCode: result["errorCode"], errorMessage: result["errorMessage"], iosError: result["iosError"]); } ///Android 文档 ///添加别名 ///设备添加别名; ///单个设备最多添加128个别名,且同一别名最多添加到128个设备; ///别名支持128字节。 Future<CommonCallbackResult> addAlias(String alias) async { var result = await _channel.invokeMethod("addAlias", alias); return CommonCallbackResult( isSuccessful: result["isSuccessful"], response: result["response"], errorCode: result["errorCode"], errorMessage: result["errorMessage"], iosError: result["iosError"]); } ///Android 文档 ///删除别名 ///删除设备别名; ///支持删除指定别名和删除全部别名(alias = null || alias.length = 0)。 Future<CommonCallbackResult> removeAlias(String alias) async { var result = await _channel.invokeMethod("removeAlias", alias); return CommonCallbackResult( isSuccessful: result["isSuccessful"], response: result["response"], errorCode: result["errorCode"], errorMessage: result["errorMessage"], iosError: result["iosError"]); } ///Android 文档 ///查询设备别名; ///查询结果可从回调onSuccess(response)的response中获取; ///从V3.0.9及以上版本开始,接口内部有5s短缓存,5s内多次调用只会请求服务端一次。 Future<CommonCallbackResult> listAliases() async { var result = await _channel.invokeMethod("listAliases"); return CommonCallbackResult( isSuccessful: result["isSuccessful"], response: result["response"], errorCode: result["errorCode"], errorMessage: result["errorMessage"], iosError: result["iosError"]); } class NotificationChannel { const NotificationChannel(this.id, this.name, this.description, {this.importance = AndroidNotificationImportance.DEFAULT}); final String id; final String name; final String description; final AndroidNotificationImportance importance; Map<String, dynamic> toJson() { return { "id": id, "name": name, "description": description, "importance": importance.index + 1 }; } } ///这个方法只对android有效 ///最好调用这个方法以保证在Android 8以上推送通知好用。 ///如果不调用这个方法,请确认你自己创建了NotificationChannel。 ///为了更好的用户体验,一些参数请不要用传[null]。 ///[id]一定要和后台推送时候设置的通知通道一样,否则Android8.0以上无法完成通知推送。 Future setupNotificationManager(List<NotificationChannel> channels) async { return _channel.invokeMethod( "setupNotificationManager", channels.map((e) => e.toJson()).toList()); } ///这个方法仅针对iOS ///设置推送通知显示方式 /// completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge); Future configureNotificationPresentationOption( {bool none: false, bool sound: true, bool alert: true, bool badge: true}) async { return _channel.invokeMethod("configureNotificationPresentationOption", {"none": none, "sound": sound, "alert": alert, "badge": badge}); } ///这个方法仅针对iOS ///同步远程角标 Future badgeClean({int num: 0}) async { if (Platform.isIOS){ return _channel.invokeMethod("badgeClean", {"num": num}); } } ///清理图标上的角标(包含ios,华为,其他平台需要自行实现) Future applicationBadgeNumberClean({int num: 0}) async { return _channel.invokeMethod("applicationBadgeNumberClean", {"num": num}); } Future<dynamic> _handler(MethodCall methodCall) { if ("initCloudChannelResult" == methodCall.method) { _initCloudChannelResultController.add(CommonCallbackResult( isSuccessful: methodCall.arguments["isSuccessful"], response: methodCall.arguments["response"], errorCode: methodCall.arguments["errorCode"], errorMessage: methodCall.arguments["errorMessage"], )); } else if ("onMessageArrived" == methodCall.method) { _onMessageArrivedController.add(CloudPushMessage( messageId: methodCall.arguments["messageId"], appId: methodCall.arguments["appId"], title: methodCall.arguments["title"], content: methodCall.arguments["content"], traceInfo: methodCall.arguments["traceInfo"], )); } else if ("onNotification" == methodCall.method) { _onNotificationController.add(OnNotification(methodCall.arguments["title"], methodCall.arguments["summary"], methodCall.arguments["extras"])); } else if ("onNotificationOpened" == methodCall.method) { _onNotificationOpenedController.add(OnNotificationOpened( methodCall.arguments["title"], methodCall.arguments["summary"], methodCall.arguments["extras"], methodCall.arguments["subtitle"], methodCall.arguments["badge"])); } else if ("onNotificationRemoved" == methodCall.method) { _onNotificationRemovedController.add(methodCall.arguments); } else if ("onNotificationClickedWithNoAction" == methodCall.method) { _onNotificationClickedWithNoActionController.add( OnNotificationClickedWithNoAction(methodCall.arguments["title"], methodCall.arguments["summary"], methodCall.arguments["extras"])); } else if ("onNotificationReceivedInApp" == methodCall.method) { _onNotificationReceivedInAppController.add(OnNotificationReceivedInApp( methodCall.arguments["title"], methodCall.arguments["summary"], methodCall.arguments["extras"], methodCall.arguments["openType"], methodCall.arguments["openActivity"], methodCall.arguments["openUrl"])); } return Future.value(true); } dispose() { _initCloudChannelResultController.close(); _onMessageArrivedController.close(); _onNotificationController.close(); _onNotificationRemovedController.close(); _onNotificationClickedWithNoActionController.close(); _onNotificationReceivedInAppController.close(); }