From 6d2bd260bb59771d1ef199c2bfe354555c295192 Mon Sep 17 00:00:00 2001 From: raoxudong Date: Tue, 19 Nov 2019 15:02:42 +0800 Subject: [PATCH] v0.3.0 --- .packages | 4 +- CHANGELOG.md | 4 + README.md | 2 +- android/build.gradle | 4 +- .../java/com/jiguang/jpush/JPushPlugin.java | 24 +- .../ios/Flutter/flutter_export_environment.sh | 10 + example/lib/main.dart | 455 +++++------ example/pubspec.lock | 16 +- ios/Classes/JPushPlugin.m | 715 +++++++++--------- ios/jpush_flutter.podspec | 5 +- lib/jpush_flutter.dart | 564 +++++++------- pubspec.lock | 2 +- pubspec.yaml | 4 +- 13 files changed, 949 insertions(+), 860 deletions(-) create mode 100755 example/ios/Flutter/flutter_export_environment.sh diff --git a/.packages b/.packages index 6368a38b..496e7efb 100644 --- a/.packages +++ b/.packages @@ -1,4 +1,4 @@ -# Generated by pub on 2019-09-25 15:21:45.301321. +# Generated by pub on 2019-11-19 13:53:32.095797. analyzer:file:///Applications/flutter/.pub-cache/hosted/pub.flutter-io.cn/analyzer-0.37.0/lib/ args:file:///Applications/flutter/.pub-cache/hosted/pub.flutter-io.cn/args-1.5.2/lib/ async:file:///Applications/flutter/.pub-cache/hosted/pub.flutter-io.cn/async-2.3.0/lib/ @@ -19,7 +19,7 @@ io:file:///Applications/flutter/.pub-cache/hosted/pub.flutter-io.cn/io-0.3.3/lib js:file:///Applications/flutter/.pub-cache/hosted/pub.flutter-io.cn/js-0.6.1+1/lib/ kernel:file:///Applications/flutter/.pub-cache/hosted/pub.flutter-io.cn/kernel-0.3.20/lib/ matcher:file:///Applications/flutter/.pub-cache/hosted/pub.flutter-io.cn/matcher-0.12.5/lib/ -meta:file:///Applications/flutter/.pub-cache/hosted/pub.flutter-io.cn/meta-1.1.6/lib/ +meta:file:///Applications/flutter/.pub-cache/hosted/pub.flutter-io.cn/meta-1.1.7/lib/ mime:file:///Applications/flutter/.pub-cache/hosted/pub.flutter-io.cn/mime-0.9.6+3/lib/ mockito:file:///Applications/flutter/.pub-cache/hosted/pub.flutter-io.cn/mockito-3.0.2/lib/ multi_server_socket:file:///Applications/flutter/.pub-cache/hosted/pub.flutter-io.cn/multi_server_socket-1.0.2/lib/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 2771b1c1..bf98e526 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.3.0 ++ 新增:清除通知栏单条通知方法 ++ 修复:点击通知栏无法获取消息问题 ++ 同步最新版 SDK ## 0.2.0 + 适配最新版本 JPush SDK + Android 支持设置角标 badge diff --git a/README.md b/README.md index b83dd6d8..5a2c5361 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ ```yaml dependencies: - jpush_flutter: 0.2.0 + jpush_flutter: 0.3.0 //github dependencies: diff --git a/android/build.gradle b/android/build.gradle index 801e2462..4edd23e1 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -34,8 +34,8 @@ android { } dependencies { - implementation 'cn.jiguang.sdk:jpush:3.3.4' - implementation 'cn.jiguang.sdk:jcore:2.1.2' + implementation 'cn.jiguang.sdk:jpush:3.4.0' + implementation 'cn.jiguang.sdk:jcore:2.1.6' // implementation 'com.android.support:appcompat-v7:28.+' compileOnly files('libs/flutter.jar') diff --git a/android/src/main/java/com/jiguang/jpush/JPushPlugin.java b/android/src/main/java/com/jiguang/jpush/JPushPlugin.java index aff313c4..d4643d23 100644 --- a/android/src/main/java/com/jiguang/jpush/JPushPlugin.java +++ b/android/src/main/java/com/jiguang/jpush/JPushPlugin.java @@ -12,6 +12,7 @@ import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.Result; +import io.flutter.plugin.common.PluginRegistry; import io.flutter.plugin.common.PluginRegistry.Registrar; import java.util.ArrayList; @@ -23,17 +24,26 @@ import java.util.Set; import cn.jpush.android.api.JPushInterface; +import io.flutter.view.FlutterNativeView; /** JPushPlugin */ public class JPushPlugin implements MethodCallHandler { + /** Plugin registration. */ public static void registerWith(Registrar registrar) { final MethodChannel channel = new MethodChannel(registrar.messenger(), "jpush"); channel.setMethodCallHandler(new JPushPlugin(registrar, channel)); - + + registrar.addViewDestroyListener(new PluginRegistry.ViewDestroyListener() { + @Override + public boolean onViewDestroy(FlutterNativeView flutterNativeView) { + instance.dartIsReady = false; + return false; + } + }); } - private static String TAG = "| JPUSH | Android | "; + private static String TAG = "| JPUSH | Flutter | Android | "; public static JPushPlugin instance; static List> openNotificationCache = new ArrayList<>(); @@ -86,6 +96,8 @@ public void onMethodCall(MethodCall call, Result result) { resumePush(call, result); } else if (call.method.equals("clearAllNotifications")) { clearAllNotifications(call, result); + } else if (call.method.equals("clearNotification")) { + clearNotification(call,result); } else if (call.method.equals("getLaunchAppNotification")) { getLaunchAppNotification(call, result); } else if (call.method.equals("getRegistrationID")) { @@ -133,6 +145,7 @@ public void scheduleCache() { if (ridAvailable && dartIsReady) { // try to schedule get rid cache for (Result res: JPushPlugin.instance.getRidCache) { + Log.d(TAG,"scheduleCache rid = " + rid); res.success(rid); JPushPlugin.instance.getRidCache.remove(res); } @@ -220,6 +233,13 @@ public void clearAllNotifications(MethodCall call, Result result) { JPushInterface.clearAllNotifications(registrar.context()); } + public void clearNotification(MethodCall call, Result result) { + Log.d(TAG,"clearNotification: "); + Object id = call.arguments; + if (id != null) { + JPushInterface.clearNotificationById(registrar.context(),(int)id); + } + } public void getLaunchAppNotification(MethodCall call, Result result) { Log.d(TAG,""); diff --git a/example/ios/Flutter/flutter_export_environment.sh b/example/ios/Flutter/flutter_export_environment.sh new file mode 100755 index 00000000..91af1a2e --- /dev/null +++ b/example/ios/Flutter/flutter_export_environment.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=/Applications/flutter" +export "FLUTTER_APPLICATION_PATH=/Users/raoxudong/JPush/jpush-github/jpush-flutter-plugin/example" +export "FLUTTER_TARGET=lib/main.dart" +export "FLUTTER_BUILD_DIR=build" +export "SYMROOT=${SOURCE_ROOT}/../build/ios" +export "FLUTTER_FRAMEWORK_DIR=/Applications/flutter/bin/cache/artifacts/engine/ios" +export "FLUTTER_BUILD_NAME=1.0.0" +export "FLUTTER_BUILD_NUMBER=1" diff --git a/example/lib/main.dart b/example/lib/main.dart index d24001a1..515b41f3 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -13,7 +13,7 @@ class MyApp extends StatefulWidget { class _MyAppState extends State { String debugLable = 'Unknown'; -final JPush jpush = new JPush(); + final JPush jpush = new JPush(); @override void initState() { super.initState(); @@ -23,53 +23,56 @@ final JPush jpush = new JPush(); // Platform messages are asynchronous, so we initialize in an async method. Future initPlatformState() async { String platformVersion; - - // Platform messages may fail, so we use a try/catch PlatformException. - jpush.getRegistrationID().then((rid) { - setState(() { - debugLable = "flutter getRegistrationID: $rid"; - }); - }); - - jpush.setup( - appKey: "a1703c14b186a68a66ef86c1", - channel: "theChannel", - production: false, - debug: true, - ); - jpush.applyPushAuthority(new NotificationSettingsIOS( - sound: true, - alert: true, - badge: true)); try { - jpush.addEventHandler( onReceiveNotification: (Map message) async { - print("flutter onReceiveNotification: $message"); - setState(() { + print("flutter onReceiveNotification: $message"); + setState(() { debugLable = "flutter onReceiveNotification: $message"; }); - }, - onOpenNotification: (Map message) async { - print("flutter onOpenNotification: $message"); - setState(() { + }, + onOpenNotification: (Map message) async { + print("flutter onOpenNotification: $message"); + setState(() { debugLable = "flutter onOpenNotification: $message"; }); - }, - onReceiveMessage: (Map message) async { - print("flutter onReceiveMessage: $message"); - setState(() { + }, + onReceiveMessage: (Map message) async { + print("flutter onReceiveMessage: $message"); + setState(() { debugLable = "flutter onReceiveMessage: $message"; }); - }, + }, ); } on PlatformException { platformVersion = 'Failed to get platform version.'; } + + jpush.setup( + appKey: "你自己应用的 AppKey", + channel: "theChannel", + production: false, + debug: true, + ); + jpush.applyPushAuthority(new NotificationSettingsIOS( + sound: true, + alert: true, + badge: true)); + + + // Platform messages may fail, so we use a try/catch PlatformException. + jpush.getRegistrationID().then((rid) { + print("flutter get registration id : $rid"); + setState(() { + debugLable = "flutter getRegistrationID: $rid"; + }); + }); + + // If the widget was removed from the tree while the asynchronous platform // message was in flight, we want to discard the reply rather than calling // setState to update our non-existent appearance. @@ -93,206 +96,214 @@ final JPush jpush = new JPush(); body: new Center( child: new Column( children:[ - new Text('result: $debugLable\n'), - new FlatButton( - child: new Text('sendLocalNotification\n'), - onPressed: () { - // 三秒后出发本地推送 - var fireDate = DateTime.fromMillisecondsSinceEpoch(DateTime.now().millisecondsSinceEpoch + 3000); - var localNotification = LocalNotification( - id: 234, - title: 'fadsfa', - buildId: 1, - content: 'fdas', - fireTime: fireDate, - subtitle: 'fasf', - badge: 5, - extra: {"fa": "0"} - ); - jpush.sendLocalNotification(localNotification).then((res) { - setState(() { - debugLable = res; - }); - }); - - }), - new FlatButton( - child: new Text('getLaunchAppNotification\n'), - onPressed: () { - - jpush.getLaunchAppNotification().then((map) { - setState(() { - debugLable = "getLaunchAppNotification success: $map"; + new Text('result: $debugLable\n'), + new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Text(" "), + new CustomButton(title: "sendLocalNotification", onPressed: (){ + // 三秒后出发本地推送 + var fireDate = DateTime.fromMillisecondsSinceEpoch(DateTime.now().millisecondsSinceEpoch + 3000); + var localNotification = LocalNotification( + id: 234, + title: 'fadsfa', + buildId: 1, + content: 'fdas', + fireTime: fireDate, + subtitle: 'fasf', + badge: 5, + extra: {"fa": "0"} + ); + jpush.sendLocalNotification(localNotification).then((res) { + setState(() { + debugLable = res; + }); }); - }) - .catchError((error) { - setState(() { - debugLable = "getLaunchAppNotification error: $error"; + }), + new Text(" "), + new CustomButton(title: "getLaunchAppNotification", onPressed: (){ + jpush.getLaunchAppNotification().then((map) { + setState(() { + debugLable = "getLaunchAppNotification success: $map"; + }); + }) + .catchError((error) { + setState(() { + debugLable = "getLaunchAppNotification error: $error"; + }); }); - }); - - }), - new FlatButton( - child: new Text('applyPushAuthority\n'), - onPressed: () { - jpush.applyPushAuthority(NotificationSettingsIOS(badge: true, alert: true, sound: true)); - }), - new FlatButton( - child: new Text('setTags\n'), - onPressed: () { - jpush.setTags(["lala","haha"]).then((map) { - var tags = map['tags']; - setState(() { - debugLable = "set tags success: $map $tags"; - }); - }) - .catchError((error) { - setState(() { - debugLable = "set tags error: $error"; - }); - }) ; - }), - new FlatButton( - child: new Text('cleanTags\n'), - onPressed: () { - jpush.cleanTags().then((map) { - var tags = map['tags']; - setState(() { - debugLable = "cleanTags success: $map $tags"; - }); - }) - .catchError((error) { - setState(() { - debugLable = "cleanTags error: $error"; - }); - }) ; - }), - new FlatButton( - child: new Text('addTags\n'), - onPressed: () { - + }), + ]), + new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Text(" "), + new CustomButton(title: "setTags", onPressed: (){ + jpush.setTags(["lala","haha"]).then((map) { + var tags = map['tags']; + setState(() { + debugLable = "set tags success: $map $tags"; + }); + }) + .catchError((error) { + setState(() { + debugLable = "set tags error: $error"; + }); + }) ; + }), + new Text(" "), + new CustomButton(title: "addTags", onPressed: (){ jpush.addTags(["lala","haha"]).then((map) { - var tags = map['tags']; - setState(() { - debugLable = "addTags success: $map $tags"; - }); - }) - .catchError((error) { - setState(() { - debugLable = "addTags error: $error"; - }); - }) ; - - }), - new FlatButton( - child: new Text('deleteTags\n'), - onPressed: () { - - jpush.deleteTags(["lala","haha"]).then((map) { - var tags = map['tags']; - setState(() { - debugLable = "deleteTags success: $map $tags"; - }); - }) - .catchError((error) { - setState(() { - debugLable = "deleteTags error: $error"; - }); - }) ; - - }), - new FlatButton( - child: new Text('getAllTags\n'), - onPressed: () { - - jpush.getAllTags().then((map) { - setState(() { - debugLable = "getAllTags success: $map"; - }); - }) - .catchError((error) { - setState(() { - debugLable = "getAllTags error: $error"; - }); - }) ; - - }), - new FlatButton( - child: new Text('setAlias\n'), - onPressed: () { - - jpush.setAlias("thealias11").then((map) { - setState(() { - debugLable = "setAlias success: $map"; - }); - }) - .catchError((error) { - setState(() { - debugLable = "setAlias error: $error"; - }); - }) ; - - }), - new FlatButton( - child: new Text('deleteAlias\n'), - onPressed: () { - - jpush.deleteAlias().then((map) { - setState(() { - debugLable = "deleteAlias success: $map"; - }); - }) - .catchError((error) { - setState(() { - debugLable = "deleteAlias error: $error"; - }); - }) ; + var tags = map['tags']; + setState(() { + debugLable = "addTags success: $map $tags"; + }); + }).catchError((error) { + setState(() { + debugLable = "addTags error: $error"; + }); + }) ; + }), + new Text(" "), + new CustomButton(title: "deleteTags", onPressed: (){ + jpush.deleteTags(["lala","haha"]).then((map) { + var tags = map['tags']; + setState(() { + debugLable = "deleteTags success: $map $tags"; + }); + }) + .catchError((error) { + setState(() { + debugLable = "deleteTags error: $error"; + }); + }) ; + }), + ] + ), + new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Text(" "), + new CustomButton(title: "getAllTags", onPressed: (){ + jpush.getAllTags().then((map) { + setState(() { + debugLable = "getAllTags success: $map"; + }); + }) + .catchError((error) { + setState(() { + debugLable = "getAllTags error: $error"; + }); + }) ; + }), + new Text(" "), + new CustomButton(title: "cleanTags", onPressed: (){ + jpush.cleanTags().then((map) { + var tags = map['tags']; + setState(() { + debugLable = "cleanTags success: $map $tags"; + }); + }) + .catchError((error) { + setState(() { + debugLable = "cleanTags error: $error"; + }); + }) ; + }), + ] + ), + new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Text(" "), + new CustomButton(title: "setAlias", onPressed: (){ + jpush.setAlias("thealias11").then((map) { + setState(() { + debugLable = "setAlias success: $map"; + }); + }) + .catchError((error) { + setState(() { + debugLable = "setAlias error: $error"; + }); + }) ; + }), + new Text(" "), + new CustomButton(title: "deleteAlias", onPressed: (){ + jpush.deleteAlias().then((map) { + setState(() { + debugLable = "deleteAlias success: $map"; + }); + }) + .catchError((error) { + setState(() { + debugLable = "deleteAlias error: $error"; + }); + }) ; + }), - }), - new FlatButton( - child: new Text('setBadge\n'), - onPressed: () { - - jpush.setBadge(66).then((map) { - setState(() { - debugLable = "setBadge success: $map"; + ] + ), + new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Text(" "), + new CustomButton(title: "stopPush",onPressed: (){ + jpush.stopPush(); + }), + new Text(" "), + new CustomButton(title: "resumePush", onPressed: (){ + jpush.resumePush(); + }), + ], + ), + new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Text(" "), + new CustomButton(title: "clearAllNotifications",onPressed: (){ + jpush.clearAllNotifications(); + }), + new Text(" "), + new CustomButton(title: "setBadge", onPressed: (){ + jpush.setBadge(66).then((map) { + setState(() { + debugLable = "setBadge success: $map"; + }); + }) + .catchError((error) { + setState(() { + debugLable = "setBadge error: $error"; + }); }); - }) - .catchError((error) { - setState(() { - debugLable = "setBadge error: $error"; - }); - }) ; - - }), - new FlatButton( - child: new Text('stopPush\n'), - onPressed: () { - - jpush.stopPush(); - - }), - new FlatButton( - child: new Text('resumePush\n'), - onPressed: () { - - jpush.resumePush(); - - }), - new FlatButton( - child: new Text('clearAllNotifications\n'), - onPressed: () { - - jpush.clearAllNotifications(); - - }), - - + }), + ], + ), ] ) - ), ), ); } } +/// 封装控件 +class CustomButton extends StatelessWidget { + + final VoidCallback onPressed; + final String title; + + const CustomButton({@required this.onPressed, @required this.title}); + + @override + Widget build(BuildContext context) { + return new FlatButton( + onPressed: onPressed, + child: new Text("$title"), + color: Color(0xff585858), + highlightColor: Color(0xff888888), + splashColor: Color(0xff888888), + textColor: Colors.white, + //padding: EdgeInsets.fromLTRB(5, 5, 5, 5), + ); + } +} \ No newline at end of file diff --git a/example/pubspec.lock b/example/pubspec.lock index 47bdf62f..69254f3d 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -21,14 +21,14 @@ packages: name: async url: "https://pub.flutter-io.cn" source: hosted - version: "2.2.0" + version: "2.3.0" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.4" + version: "1.0.5" charcode: dependency: transitive description: @@ -136,7 +136,7 @@ packages: path: ".." relative: true source: path - version: "0.2.0" + version: "0.3.0" js: dependency: transitive description: @@ -171,7 +171,7 @@ packages: name: meta url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.6" + version: "1.1.7" mime: dependency: transitive description: @@ -220,14 +220,14 @@ packages: name: path url: "https://pub.flutter-io.cn" source: hosted - version: "1.6.2" + version: "1.6.4" pedantic: dependency: transitive description: name: pedantic url: "https://pub.flutter-io.cn" source: hosted - version: "1.7.0" + version: "1.8.0+1" platform: dependency: transitive description: @@ -255,7 +255,7 @@ packages: name: quiver url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.3" + version: "2.0.5" shelf: dependency: transitive description: @@ -330,7 +330,7 @@ packages: name: string_scanner url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.4" + version: "1.0.5" term_glyph: dependency: transitive description: diff --git a/ios/Classes/JPushPlugin.m b/ios/Classes/JPushPlugin.m index be884918..83528665 100644 --- a/ios/Classes/JPushPlugin.m +++ b/ios/Classes/JPushPlugin.m @@ -5,7 +5,7 @@ #import -#define JPLog(fmt, ...) NSLog((@"| JPUSH | iOS | " fmt), ##__VA_ARGS__) +#define JPLog(fmt, ...) NSLog((@"| JPUSH | Flutter | iOS | " fmt), ##__VA_ARGS__) @interface NSError (FlutterError) @property(readonly, nonatomic) FlutterError *flutterError; @@ -13,9 +13,9 @@ @interface NSError (FlutterError) @implementation NSError (FlutterError) - (FlutterError *)flutterError { - return [FlutterError errorWithCode:[NSString stringWithFormat:@"Error %d", (int)self.code] - message:self.domain - details:self.localizedDescription]; + return [FlutterError errorWithCode:[NSString stringWithFormat:@"Error %d", (int)self.code] + message:self.domain + details:self.localizedDescription]; } @end @@ -28,489 +28,518 @@ @interface JPushPlugin () static NSMutableArray* getRidResults; @implementation JPushPlugin { - NSDictionary *_launchNotification; - BOOL _isJPushDidLogin; - JPAuthorizationOptions notificationTypes; + NSDictionary *_launchNotification; + BOOL _isJPushDidLogin; + JPAuthorizationOptions notificationTypes; } + (void)registerWithRegistrar:(NSObject*)registrar { - getRidResults = @[].mutableCopy; - FlutterMethodChannel* channel = [FlutterMethodChannel - methodChannelWithName:@"jpush" - binaryMessenger:[registrar messenger]]; - JPushPlugin* instance = [[JPushPlugin alloc] init]; - instance.channel = channel; - - - [registrar addApplicationDelegate:instance]; - [registrar addMethodCallDelegate:instance channel:channel]; + getRidResults = @[].mutableCopy; + FlutterMethodChannel* channel = [FlutterMethodChannel + methodChannelWithName:@"jpush" + binaryMessenger:[registrar messenger]]; + JPushPlugin* instance = [[JPushPlugin alloc] init]; + instance.channel = channel; + + + [registrar addApplicationDelegate:instance]; + [registrar addMethodCallDelegate:instance channel:channel]; } - (id)init { - self = [super init]; - notificationTypes = 0; - NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; - - [defaultCenter removeObserver:self]; - - - [defaultCenter addObserver:self - selector:@selector(networkConnecting:) - name:kJPFNetworkIsConnectingNotification - object:nil]; - - [defaultCenter addObserver:self - selector:@selector(networkRegister:) - name:kJPFNetworkDidRegisterNotification - object:nil]; - - [defaultCenter addObserver:self - selector:@selector(networkDidSetup:) - name:kJPFNetworkDidSetupNotification - object:nil]; - [defaultCenter addObserver:self - selector:@selector(networkDidClose:) - name:kJPFNetworkDidCloseNotification - object:nil]; - [defaultCenter addObserver:self - selector:@selector(networkDidLogin:) - name:kJPFNetworkDidLoginNotification - object:nil]; - [defaultCenter addObserver:self - selector:@selector(networkDidReceiveMessage:) - name:kJPFNetworkDidReceiveMessageNotification - object:nil]; - return self; + self = [super init]; + notificationTypes = 0; + NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter]; + + [defaultCenter removeObserver:self]; + + + [defaultCenter addObserver:self + selector:@selector(networkConnecting:) + name:kJPFNetworkIsConnectingNotification + object:nil]; + + [defaultCenter addObserver:self + selector:@selector(networkRegister:) + name:kJPFNetworkDidRegisterNotification + object:nil]; + + [defaultCenter addObserver:self + selector:@selector(networkDidSetup:) + name:kJPFNetworkDidSetupNotification + object:nil]; + [defaultCenter addObserver:self + selector:@selector(networkDidClose:) + name:kJPFNetworkDidCloseNotification + object:nil]; + [defaultCenter addObserver:self + selector:@selector(networkDidLogin:) + name:kJPFNetworkDidLoginNotification + object:nil]; + [defaultCenter addObserver:self + selector:@selector(networkDidReceiveMessage:) + name:kJPFNetworkDidReceiveMessageNotification + object:nil]; + return self; } - (void)networkConnecting:(NSNotification *)notification { - _isJPushDidLogin = false; + _isJPushDidLogin = false; } - (void)networkRegister:(NSNotification *)notification { - _isJPushDidLogin = false; + _isJPushDidLogin = false; } - (void)networkDidSetup:(NSNotification *)notification { - _isJPushDidLogin = false; + _isJPushDidLogin = false; } - (void)networkDidClose:(NSNotification *)notification { - _isJPushDidLogin = false; + _isJPushDidLogin = false; } - (void)networkDidLogin:(NSNotification *)notification { - _isJPushDidLogin = YES; - for (FlutterResult result in getRidResults) { - result([JPUSHService registrationID]); - } - [getRidResults removeAllObjects]; + _isJPushDidLogin = YES; + for (FlutterResult result in getRidResults) { + result([JPUSHService registrationID]); + } + [getRidResults removeAllObjects]; } - (void)networkDidReceiveMessage:(NSNotification *)notification { - [_channel invokeMethod:@"onReceiveMessage" arguments: [notification userInfo]]; + [_channel invokeMethod:@"onReceiveMessage" arguments: [notification userInfo]]; } - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { JPLog(@"handleMethodCall:%@",call.method); - if ([@"getPlatformVersion" isEqualToString:call.method]) { - result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]); - } else if([@"setup" isEqualToString:call.method]) { - [self setup:call result: result]; - } else if([@"applyPushAuthority" isEqualToString:call.method]) { - [self applyPushAuthority:call result:result]; - } else if([@"setTags" isEqualToString:call.method]) { - [self setTags:call result:result]; - } else if([@"cleanTags" isEqualToString:call.method]) { - [self cleanTags:call result:result]; - } else if([@"addTags" isEqualToString:call.method]) { - [self addTags:call result:result]; - } else if([@"deleteTags" isEqualToString:call.method]) { - [self deleteTags:call result:result]; - } else if([@"getAllTags" isEqualToString:call.method]) { - [self getAllTags:call result:result]; - } else if([@"setAlias" isEqualToString:call.method]) { - [self setAlias:call result:result]; - } else if([@"deleteAlias" isEqualToString:call.method]) { - [self deleteAlias:call result:result]; - } else if([@"setBadge" isEqualToString:call.method]) { - [self setBadge:call result:result]; - } else if([@"stopPush" isEqualToString:call.method]) { - [self stopPush:call result:result]; - } else if([@"resumePush" isEqualToString:call.method]) { - [self applyPushAuthority:call result:result]; - } else if([@"clearAllNotifications" isEqualToString:call.method]) { - [self clearAllNotifications:call result:result]; - } else if([@"getLaunchAppNotification" isEqualToString:call.method]) { - [self getLaunchAppNotification:call result:result]; - } else if([@"getRegistrationID" isEqualToString:call.method]) { - [self getRegistrationID:call result:result]; - } else if([@"sendLocalNotification"isEqualToString:call.method]) { - [self sendLocalNotification:call result:result]; - } else{ - result(FlutterMethodNotImplemented); - } + if ([@"getPlatformVersion" isEqualToString:call.method]) { + result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]); + } else if([@"setup" isEqualToString:call.method]) { + [self setup:call result: result]; + } else if([@"applyPushAuthority" isEqualToString:call.method]) { + [self applyPushAuthority:call result:result]; + } else if([@"setTags" isEqualToString:call.method]) { + [self setTags:call result:result]; + } else if([@"cleanTags" isEqualToString:call.method]) { + [self cleanTags:call result:result]; + } else if([@"addTags" isEqualToString:call.method]) { + [self addTags:call result:result]; + } else if([@"deleteTags" isEqualToString:call.method]) { + [self deleteTags:call result:result]; + } else if([@"getAllTags" isEqualToString:call.method]) { + [self getAllTags:call result:result]; + } else if([@"setAlias" isEqualToString:call.method]) { + [self setAlias:call result:result]; + } else if([@"deleteAlias" isEqualToString:call.method]) { + [self deleteAlias:call result:result]; + } else if([@"setBadge" isEqualToString:call.method]) { + [self setBadge:call result:result]; + } else if([@"stopPush" isEqualToString:call.method]) { + [self stopPush:call result:result]; + } else if([@"resumePush" isEqualToString:call.method]) { + JPLog(@"ios platform not support resume push."); + //[self applyPushAuthority:call result:result]; + } else if([@"clearAllNotifications" isEqualToString:call.method]) { + [self clearAllNotifications:call result:result]; + } else if ([@"clearNotification" isEqualToString:call.method]) { + [self clearNotification:call result:result]; + } else if([@"getLaunchAppNotification" isEqualToString:call.method]) { + [self getLaunchAppNotification:call result:result]; + } else if([@"getRegistrationID" isEqualToString:call.method]) { + [self getRegistrationID:call result:result]; + } else if([@"sendLocalNotification"isEqualToString:call.method]) { + [self sendLocalNotification:call result:result]; + } else{ + result(FlutterMethodNotImplemented); + } } - (void)setup:(FlutterMethodCall*)call result:(FlutterResult)result { - JPLog(@"setup:"); - NSDictionary *arguments = call.arguments; - NSNumber *debug = arguments[@"debug"]; - if ([debug boolValue]) { - [JPUSHService setDebugMode]; - } else { - [JPUSHService setLogOFF]; - } - - [JPUSHService setupWithOption:_launchNotification - appKey:arguments[@"appKey"] - channel:arguments[@"channel"] - apsForProduction:[arguments[@"production"] boolValue]]; + JPLog(@"setup:"); + NSDictionary *arguments = call.arguments; + NSNumber *debug = arguments[@"debug"]; + if ([debug boolValue]) { + [JPUSHService setDebugMode]; + } else { + [JPUSHService setLogOFF]; + } + + [JPUSHService setupWithOption:_launchNotification + appKey:arguments[@"appKey"] + channel:arguments[@"channel"] + apsForProduction:[arguments[@"production"] boolValue]]; } - (void)applyPushAuthority:(FlutterMethodCall*)call result:(FlutterResult)result { JPLog(@"applyPushAuthority:%@",call.arguments); - notificationTypes = 0; - NSDictionary *arguments = call.arguments; - if ([arguments[@"sound"] boolValue]) { - notificationTypes |= JPAuthorizationOptionSound; - } - if ([arguments[@"alert"] boolValue]) { - notificationTypes |= JPAuthorizationOptionAlert; - } - if ([arguments[@"badge"] boolValue]) { - notificationTypes |= JPAuthorizationOptionBadge; - } - JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init]; - entity.types = notificationTypes; - [JPUSHService registerForRemoteNotificationConfig:entity delegate:self]; + notificationTypes = 0; + NSDictionary *arguments = call.arguments; + if ([arguments[@"sound"] boolValue]) { + notificationTypes |= JPAuthorizationOptionSound; + } + if ([arguments[@"alert"] boolValue]) { + notificationTypes |= JPAuthorizationOptionAlert; + } + if ([arguments[@"badge"] boolValue]) { + notificationTypes |= JPAuthorizationOptionBadge; + } + JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init]; + entity.types = notificationTypes; + [JPUSHService registerForRemoteNotificationConfig:entity delegate:self]; } - (void)setTags:(FlutterMethodCall*)call result:(FlutterResult)result { JPLog(@"setTags:%@",call.arguments); - NSSet *tagSet; - - if (call.arguments != NULL) { - tagSet = [NSSet setWithArray: call.arguments]; - } - - [JPUSHService setTags:tagSet completion:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) { - if (iResCode == 0) { - result(@{@"tags": [iTags allObjects] ?: @[]}); - } else { - NSError *error = [[NSError alloc] initWithDomain:@"JPush.Flutter" code:iResCode userInfo:nil]; - result([error flutterError]); + NSSet *tagSet; + + if (call.arguments != NULL) { + tagSet = [NSSet setWithArray: call.arguments]; } - } seq: 0]; + + [JPUSHService setTags:tagSet completion:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) { + if (iResCode == 0) { + result(@{@"tags": [iTags allObjects] ?: @[]}); + } else { + NSError *error = [[NSError alloc] initWithDomain:@"JPush.Flutter" code:iResCode userInfo:nil]; + result([error flutterError]); + } + } seq: 0]; } - (void)cleanTags:(FlutterMethodCall*)call result:(FlutterResult)result { JPLog(@"cleanTags:"); - [JPUSHService cleanTags:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) { - if (iResCode == 0) { - result(@{@"tags": iTags ? [iTags allObjects] : @[]}); - } else { - NSError *error = [[NSError alloc] initWithDomain:@"JPush.Flutter" code:iResCode userInfo:nil]; - result([error flutterError]); - } - } seq: 0]; + [JPUSHService cleanTags:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) { + if (iResCode == 0) { + result(@{@"tags": iTags ? [iTags allObjects] : @[]}); + } else { + NSError *error = [[NSError alloc] initWithDomain:@"JPush.Flutter" code:iResCode userInfo:nil]; + result([error flutterError]); + } + } seq: 0]; } - (void)addTags:(FlutterMethodCall*)call result:(FlutterResult)result { JPLog(@"addTags:%@",call.arguments); - NSSet *tagSet; - - if (call.arguments != NULL) { - tagSet = [NSSet setWithArray:call.arguments]; - } - - [JPUSHService addTags:tagSet completion:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) { - if (iResCode == 0) { - result(@{@"tags": [iTags allObjects] ?: @[]}); - } else { - NSError *error = [[NSError alloc] initWithDomain:@"JPush.Flutter" code:iResCode userInfo:nil]; - result([error flutterError]); + NSSet *tagSet; + + if (call.arguments != NULL) { + tagSet = [NSSet setWithArray:call.arguments]; } - } seq: 0]; + + [JPUSHService addTags:tagSet completion:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) { + if (iResCode == 0) { + result(@{@"tags": [iTags allObjects] ?: @[]}); + } else { + NSError *error = [[NSError alloc] initWithDomain:@"JPush.Flutter" code:iResCode userInfo:nil]; + result([error flutterError]); + } + } seq: 0]; } - (void)deleteTags:(FlutterMethodCall*)call result:(FlutterResult)result { JPLog(@"deleteTags:%@",call.arguments); - NSSet *tagSet; - - if (call.arguments != NULL) { - tagSet = [NSSet setWithArray:call.arguments]; - } - - [JPUSHService deleteTags:tagSet completion:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) { - if (iResCode == 0) { - result(@{@"tags": [iTags allObjects] ?: @[]}); - } else { - NSError *error = [[NSError alloc] initWithDomain:@"JPush.Flutter" code:iResCode userInfo:nil]; - result([error flutterError]); + NSSet *tagSet; + + if (call.arguments != NULL) { + tagSet = [NSSet setWithArray:call.arguments]; } - } seq: 0]; + + [JPUSHService deleteTags:tagSet completion:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) { + if (iResCode == 0) { + result(@{@"tags": [iTags allObjects] ?: @[]}); + } else { + NSError *error = [[NSError alloc] initWithDomain:@"JPush.Flutter" code:iResCode userInfo:nil]; + result([error flutterError]); + } + } seq: 0]; } - (void)getAllTags:(FlutterMethodCall*)call result:(FlutterResult)result { JPLog(@"getAllTags:"); - [JPUSHService getAllTags:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) { - if (iResCode == 0) { - result(@{@"tags": iTags ? [iTags allObjects] : @[]}); - } else { - NSError *error = [[NSError alloc] initWithDomain:@"JPush.Flutter" code:iResCode userInfo:nil]; - result([error flutterError]); - } - } seq: 0]; + [JPUSHService getAllTags:^(NSInteger iResCode, NSSet *iTags, NSInteger seq) { + if (iResCode == 0) { + result(@{@"tags": iTags ? [iTags allObjects] : @[]}); + } else { + NSError *error = [[NSError alloc] initWithDomain:@"JPush.Flutter" code:iResCode userInfo:nil]; + result([error flutterError]); + } + } seq: 0]; } - (void)setAlias:(FlutterMethodCall*)call result:(FlutterResult)result { JPLog(@"setAlias:%@",call.arguments); - NSString *alias = call.arguments; - [JPUSHService setAlias:alias completion:^(NSInteger iResCode, NSString *iAlias, NSInteger seq) { - if (iResCode == 0) { - result(@{@"alias": iAlias ?: @""}); - } else { - NSError *error = [[NSError alloc] initWithDomain:@"JPush.Flutter" code:iResCode userInfo:nil]; - result([error flutterError]); - } - } seq: 0]; + NSString *alias = call.arguments; + [JPUSHService setAlias:alias completion:^(NSInteger iResCode, NSString *iAlias, NSInteger seq) { + if (iResCode == 0) { + result(@{@"alias": iAlias ?: @""}); + } else { + NSError *error = [[NSError alloc] initWithDomain:@"JPush.Flutter" code:iResCode userInfo:nil]; + result([error flutterError]); + } + } seq: 0]; } - (void)deleteAlias:(FlutterMethodCall*)call result:(FlutterResult)result { JPLog(@"deleteAlias:%@",call.arguments); - [JPUSHService deleteAlias:^(NSInteger iResCode, NSString *iAlias, NSInteger seq) { - if (iResCode == 0) { - result(@{@"alias": iAlias ?: @""}); - } else { - NSError *error = [[NSError alloc] initWithDomain:@"JPush.Flutter" code:iResCode userInfo:nil]; - result([error flutterError]); - } - } seq: 0]; + [JPUSHService deleteAlias:^(NSInteger iResCode, NSString *iAlias, NSInteger seq) { + if (iResCode == 0) { + result(@{@"alias": iAlias ?: @""}); + } else { + NSError *error = [[NSError alloc] initWithDomain:@"JPush.Flutter" code:iResCode userInfo:nil]; + result([error flutterError]); + } + } seq: 0]; } - (void)setBadge:(FlutterMethodCall*)call result:(FlutterResult)result { JPLog(@"setBadge:%@",call.arguments); - NSInteger badge = [call.arguments[@"badge"] integerValue]; - if (badge < 0) { - badge = 0; - } - [[UIApplication sharedApplication] setApplicationIconBadgeNumber: badge]; - [JPUSHService setBadge: badge]; + NSInteger badge = [call.arguments[@"badge"] integerValue]; + if (badge < 0) { + badge = 0; + } + [[UIApplication sharedApplication] setApplicationIconBadgeNumber: badge]; + [JPUSHService setBadge: badge]; } - (void)stopPush:(FlutterMethodCall*)call result:(FlutterResult)result { JPLog(@"stopPush:"); - [[UIApplication sharedApplication] unregisterForRemoteNotifications]; + [[UIApplication sharedApplication] unregisterForRemoteNotifications]; } - - (void)clearAllNotifications:(FlutterMethodCall*)call result:(FlutterResult)result { JPLog(@"clearAllNotifications:"); - [[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0]; + + if (@available(iOS 10.0, *)) { + //iOS 10 以上支持 + JPushNotificationIdentifier *identifier = [[JPushNotificationIdentifier alloc] init]; + identifier.identifiers = nil; + identifier.delivered = YES; //等于 YES 则移除所有在通知中心显示的,等于 NO 则为移除所有待推送的 + [JPUSHService removeNotification:identifier]; + } else { + // iOS 10 以下移除所有推送;iOS 10 以上移除所有在通知中心显示推送和待推送请求 + [JPUSHService removeNotification:nil]; + } +} +- (void)clearNotification:(FlutterMethodCall*)call result:(FlutterResult)result { + JPLog(@"clearNotification:"); + + NSNumber *notificationId = call.arguments; + if (!notificationId) { + return ; + } + JPushNotificationIdentifier *identifier = [[JPushNotificationIdentifier alloc] init]; + identifier.identifiers = @[notificationId.stringValue]; + + if (@available(iOS 10.0, *)) { + //iOS 10 以上有效,等于 YES 则在通知中心显示的里面移除,等于 NO 则为在待推送的里面移除;iOS 10 以下无效 + identifier.delivered = YES; + } else { + // Fallback on earlier versions + } + [JPUSHService removeNotification:identifier]; } - (void)getLaunchAppNotification:(FlutterMethodCall*)call result:(FlutterResult)result { JPLog(@"getLaunchAppNotification"); - result(_launchNotification == nil ? @{}: _launchNotification); + result(_launchNotification == nil ? @{}: _launchNotification); } - (void)getRegistrationID:(FlutterMethodCall*)call result:(FlutterResult)result { JPLog(@"getRegistrationID:"); #if TARGET_IPHONE_SIMULATOR//模拟器 - NSLog(@"simulator can not get registrationid"); - result(@""); + NSLog(@"simulator can not get registrationid"); + result(@""); #elif TARGET_OS_IPHONE//真机 - - - if ([JPUSHService registrationID] != nil && ![[JPUSHService registrationID] isEqualToString:@""]) { - // 如果已经成功获取 registrationID,从本地获取直接缓存 - result([JPUSHService registrationID]); - return; - } - - if (_isJPushDidLogin) {// 第一次获取未登录情况 - result(@[[JPUSHService registrationID]]); - } else { - [getRidResults addObject:result]; - } + + + if ([JPUSHService registrationID] != nil && ![[JPUSHService registrationID] isEqualToString:@""]) { + // 如果已经成功获取 registrationID,从本地获取直接缓存 + result([JPUSHService registrationID]); + return; + } + + if (_isJPushDidLogin) {// 第一次获取未登录情况 + result(@[[JPUSHService registrationID]]); + } else { + [getRidResults addObject:result]; + } #endif } - (void)sendLocalNotification:(FlutterMethodCall*)call result:(FlutterResult)result { JPLog(@"sendLocalNotification:%@",call.arguments); - JPushNotificationContent *content = [[JPushNotificationContent alloc] init]; + JPushNotificationContent *content = [[JPushNotificationContent alloc] init]; NSDictionary *params = call.arguments; - if (params[@"title"]) { - content.title = params[@"title"]; - } - - if (params[@"subtitle"] && ![params[@"subtitle"] isEqualToString:@""]) { - content.subtitle = params[@"subtitle"]; - } - - if (params[@"content"]) { - content.body = params[@"content"]; - } - - if (params[@"badge"]) { - content.badge = params[@"badge"]; - } - - if (params[@"action"] && ![params[@"action"] isEqualToString:@""]) { - content.action = params[@"action"]; - } - + if (params[@"title"]) { + content.title = params[@"title"]; + } + + if (params[@"subtitle"] && ![params[@"subtitle"] isEqualToString:@""]) { + content.subtitle = params[@"subtitle"]; + } + + if (params[@"content"]) { + content.body = params[@"content"]; + } + + if (params[@"badge"]) { + content.badge = params[@"badge"]; + } + + if (params[@"action"] && ![params[@"action"] isEqualToString:@""]) { + content.action = params[@"action"]; + } + if ([params[@"extra"] isKindOfClass:[NSDictionary class]]) { content.userInfo = params[@"extra"]; } - - if (params[@"sound"] && ![params[@"sound"] isEqualToString:@""]) { - content.sound = params[@"sound"]; - } - - JPushNotificationTrigger *trigger = [[JPushNotificationTrigger alloc] init]; - if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0) { - if (params[@"fireTime"]) { - NSNumber *date = params[@"fireTime"]; - NSTimeInterval currentInterval = [[NSDate date] timeIntervalSince1970]; - NSTimeInterval interval = [date doubleValue]/1000 - currentInterval; - interval = interval>0?interval:0; - trigger.timeInterval = interval; + + if (params[@"sound"] && ![params[@"sound"] isEqualToString:@""]) { + content.sound = params[@"sound"]; } - } - - else { - if (params[@"fireTime"]) { - NSNumber *date = params[@"fireTime"]; - trigger.fireDate = [NSDate dateWithTimeIntervalSince1970: [date doubleValue]/1000]; + + JPushNotificationTrigger *trigger = [[JPushNotificationTrigger alloc] init]; + if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0) { + if (params[@"fireTime"]) { + NSNumber *date = params[@"fireTime"]; + NSTimeInterval currentInterval = [[NSDate date] timeIntervalSince1970]; + NSTimeInterval interval = [date doubleValue]/1000 - currentInterval; + interval = interval>0?interval:0; + trigger.timeInterval = interval; + } } - } - JPushNotificationRequest *request = [[JPushNotificationRequest alloc] init]; - request.content = content; - request.trigger = trigger; - - if (params[@"id"]) { - NSNumber *identify = params[@"id"]; - request.requestIdentifier = [identify stringValue]; - } - request.completionHandler = ^(id result) { - NSLog(@"result"); - }; - - [JPUSHService addNotification:request]; - - result(@[@[]]); + + else { + if (params[@"fireTime"]) { + NSNumber *date = params[@"fireTime"]; + trigger.fireDate = [NSDate dateWithTimeIntervalSince1970: [date doubleValue]/1000]; + } + } + JPushNotificationRequest *request = [[JPushNotificationRequest alloc] init]; + request.content = content; + request.trigger = trigger; + + if (params[@"id"]) { + NSNumber *identify = params[@"id"]; + request.requestIdentifier = [identify stringValue]; + } + request.completionHandler = ^(id result) { + NSLog(@"result"); + }; + + [JPUSHService addNotification:request]; + + result(@[@[]]); } - (void)dealloc { - _isJPushDidLogin = NO; - [[NSNotificationCenter defaultCenter] removeObserver:self]; + _isJPushDidLogin = NO; + [[NSNotificationCenter defaultCenter] removeObserver:self]; } #pragma mark - AppDelegate -- (BOOL)application:(UIApplication *)application -didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - - if (launchOptions != nil) { - _launchNotification = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]; - _launchNotification = [self jpushFormatAPNSDic:_launchNotification.copy]; - } - - if ([launchOptions valueForKey:UIApplicationLaunchOptionsLocalNotificationKey]) { - UILocalNotification *localNotification = [launchOptions valueForKey:UIApplicationLaunchOptionsLocalNotificationKey]; - NSMutableDictionary *localNotificationEvent = @{}.mutableCopy; - localNotificationEvent[@"content"] = localNotification.alertBody; - localNotificationEvent[@"badge"] = @(localNotification.applicationIconBadgeNumber); - localNotificationEvent[@"extras"] = localNotification.userInfo; - localNotificationEvent[@"fireTime"] = [NSNumber numberWithLong:[localNotification.fireDate timeIntervalSince1970] * 1000]; - localNotificationEvent[@"soundName"] = [localNotification.soundName isEqualToString:UILocalNotificationDefaultSoundName] ? @"" : localNotification.soundName; - - if (@available(iOS 8.2, *)) { - localNotificationEvent[@"title"] = localNotification.alertTitle; +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + + if (launchOptions != nil) { + _launchNotification = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]; + _launchNotification = [self jpushFormatAPNSDic:_launchNotification.copy]; + } + + if ([launchOptions valueForKey:UIApplicationLaunchOptionsLocalNotificationKey]) { + UILocalNotification *localNotification = [launchOptions valueForKey:UIApplicationLaunchOptionsLocalNotificationKey]; + NSMutableDictionary *localNotificationEvent = @{}.mutableCopy; + localNotificationEvent[@"content"] = localNotification.alertBody; + localNotificationEvent[@"badge"] = @(localNotification.applicationIconBadgeNumber); + localNotificationEvent[@"extras"] = localNotification.userInfo; + localNotificationEvent[@"fireTime"] = [NSNumber numberWithLong:[localNotification.fireDate timeIntervalSince1970] * 1000]; + localNotificationEvent[@"soundName"] = [localNotification.soundName isEqualToString:UILocalNotificationDefaultSoundName] ? @"" : localNotification.soundName; + + if (@available(iOS 8.2, *)) { + localNotificationEvent[@"title"] = localNotification.alertTitle; + } + _launchNotification = localNotificationEvent; } - _launchNotification = localNotificationEvent; - } - return YES; + return YES; } - (void)applicationDidEnterBackground:(UIApplication *)application { -// _resumingFromBackground = YES; + // _resumingFromBackground = YES; } - (void)applicationDidBecomeActive:(UIApplication *)application { -// application.applicationIconBadgeNumber = 1; -// application.applicationIconBadgeNumber = 0; + // application.applicationIconBadgeNumber = 1; + // application.applicationIconBadgeNumber = 0; } - (bool)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler { - - [_channel invokeMethod:@"onReceiveNotification" arguments:userInfo]; - completionHandler(UIBackgroundFetchResultNoData); - return YES; + + [_channel invokeMethod:@"onReceiveNotification" arguments:userInfo]; + completionHandler(UIBackgroundFetchResultNoData); + return YES; } - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { - [JPUSHService registerDeviceToken:deviceToken]; + [JPUSHService registerDeviceToken:deviceToken]; } - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { - NSDictionary *settingsDictionary = @{ - @"sound" : [NSNumber numberWithBool:notificationSettings.types & UIUserNotificationTypeSound], - @"badge" : [NSNumber numberWithBool:notificationSettings.types & UIUserNotificationTypeBadge], - @"alert" : [NSNumber numberWithBool:notificationSettings.types & UIUserNotificationTypeAlert], - }; - [_channel invokeMethod:@"onIosSettingsRegistered" arguments:settingsDictionary]; + NSDictionary *settingsDictionary = @{ + @"sound" : [NSNumber numberWithBool:notificationSettings.types & UIUserNotificationTypeSound], + @"badge" : [NSNumber numberWithBool:notificationSettings.types & UIUserNotificationTypeBadge], + @"alert" : [NSNumber numberWithBool:notificationSettings.types & UIUserNotificationTypeAlert], + }; + [_channel invokeMethod:@"onIosSettingsRegistered" arguments:settingsDictionary]; } - (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler API_AVAILABLE(ios(10.0)){ - - NSDictionary * userInfo = notification.request.content.userInfo; - if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) { - [JPUSHService handleRemoteNotification:userInfo]; - [_channel invokeMethod:@"onReceiveNotification" arguments: [self jpushFormatAPNSDic:userInfo]]; - } - - completionHandler(notificationTypes); + + NSDictionary * userInfo = notification.request.content.userInfo; + if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) { + [JPUSHService handleRemoteNotification:userInfo]; + [_channel invokeMethod:@"onReceiveNotification" arguments: [self jpushFormatAPNSDic:userInfo]]; + } + + completionHandler(notificationTypes); } - (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler API_AVAILABLE(ios(10.0)){ - NSDictionary * userInfo = response.notification.request.content.userInfo; - if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) { - [JPUSHService handleRemoteNotification:userInfo]; - [_channel invokeMethod:@"onOpenNotification" arguments: [self jpushFormatAPNSDic:userInfo]]; - } - completionHandler(); + NSDictionary * userInfo = response.notification.request.content.userInfo; + if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) { + [JPUSHService handleRemoteNotification:userInfo]; + [_channel invokeMethod:@"onOpenNotification" arguments: [self jpushFormatAPNSDic:userInfo]]; + } + completionHandler(); } - (NSMutableDictionary *)jpushFormatAPNSDic:(NSDictionary *)dic { - NSMutableDictionary *extras = @{}.mutableCopy; - for (NSString *key in dic) { - if([key isEqualToString:@"_j_business"] || - [key isEqualToString:@"_j_msgid"] || - [key isEqualToString:@"_j_uid"] || - [key isEqualToString:@"actionIdentifier"] || - [key isEqualToString:@"aps"]) { - continue; + NSMutableDictionary *extras = @{}.mutableCopy; + for (NSString *key in dic) { + if([key isEqualToString:@"_j_business"] || + [key isEqualToString:@"_j_msgid"] || + [key isEqualToString:@"_j_uid"] || + [key isEqualToString:@"actionIdentifier"] || + [key isEqualToString:@"aps"]) { + continue; + } + extras[key] = dic[key]; } - extras[key] = dic[key]; - } - NSMutableDictionary *formatDic = dic.mutableCopy; - formatDic[@"extras"] = extras; - return formatDic; + NSMutableDictionary *formatDic = dic.mutableCopy; + formatDic[@"extras"] = extras; + return formatDic; } @end diff --git a/ios/jpush_flutter.podspec b/ios/jpush_flutter.podspec index 2ab6dcb7..f8265ab3 100644 --- a/ios/jpush_flutter.podspec +++ b/ios/jpush_flutter.podspec @@ -10,7 +10,7 @@ A new flutter plugin project. DESC s.homepage = 'http://example.com' s.license = { :file => '../LICENSE' } - s.author = { 'huminios' => '380108184@qq.com' } + s.author = { 'xudong.rao' => 'xudong.rao@outlook.com' } s.source = { :path => '.' } s.source_files = 'Classes/**/*' s.public_header_files = 'Classes/**/*.h' @@ -19,5 +19,4 @@ A new flutter plugin project. s.ios.deployment_target = '8.0' s.static_framework = true -end - +end \ No newline at end of file diff --git a/lib/jpush_flutter.dart b/lib/jpush_flutter.dart index 52e72c45..b5fa9738 100644 --- a/lib/jpush_flutter.dart +++ b/lib/jpush_flutter.dart @@ -3,257 +3,281 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:platform/platform.dart'; - typedef Future EventHandler(Map event); class JPush { - final String flutter_log = "| JPUSH | Flutter | "; - factory JPush() => _instance; - - final MethodChannel _channel; - final Platform _platform; - - @visibleForTesting - JPush.private(MethodChannel channel, Platform platform) - : _channel = channel, - _platform = platform; - - static final JPush _instance = new JPush.private( - const MethodChannel('jpush'), - const LocalPlatform()); - - EventHandler _onReceiveNotification; - EventHandler _onOpenNotification; - EventHandler _onReceiveMessage; - - void setup({ - String appKey, - bool production, - String channel = '', - bool debug = false, - }) { - print(flutter_log + "setup:"); - - _channel.invokeMethod('setup', { 'appKey': appKey, 'channel': channel, 'production': production, 'debug': debug}); - } - /// - /// 初始化 JPush 必须先初始化才能执行其他操作(比如接收事件传递) - /// - void addEventHandler({ - EventHandler onReceiveNotification, - EventHandler onOpenNotification, - EventHandler onReceiveMessage, - }) { - print(flutter_log + "addEventHandler:"); - - _onReceiveNotification = onReceiveNotification; - _onOpenNotification = onOpenNotification; - _onReceiveMessage = onReceiveMessage; - _channel.setMethodCallHandler(_handleMethod); + final String flutter_log = "| JPUSH | Flutter | "; + factory JPush() => _instance; + + final MethodChannel _channel; + final Platform _platform; + + @visibleForTesting + JPush.private(MethodChannel channel, Platform platform) + : _channel = channel, + _platform = platform; + + static final JPush _instance = + new JPush.private(const MethodChannel('jpush'), const LocalPlatform()); + + EventHandler _onReceiveNotification; + EventHandler _onOpenNotification; + EventHandler _onReceiveMessage; + + void setup({ + String appKey, + bool production, + String channel = '', + bool debug = false, + }) { + print(flutter_log + "setup:"); + + _channel.invokeMethod('setup', { + 'appKey': appKey, + 'channel': channel, + 'production': production, + 'debug': debug + }); + } + + /// + /// 初始化 JPush 必须先初始化才能执行其他操作(比如接收事件传递) + /// + void addEventHandler({ + EventHandler onReceiveNotification, + EventHandler onOpenNotification, + EventHandler onReceiveMessage, + }) { + print(flutter_log + "addEventHandler:"); + + _onReceiveNotification = onReceiveNotification; + _onOpenNotification = onOpenNotification; + _onReceiveMessage = onReceiveMessage; + _channel.setMethodCallHandler(_handleMethod); + } + + Future _handleMethod(MethodCall call) async { + print(flutter_log + "_handleMethod:"); + + switch (call.method) { + case "onReceiveNotification": + return _onReceiveNotification(call.arguments.cast()); + case "onOpenNotification": + return _onOpenNotification(call.arguments.cast()); + case "onReceiveMessage": + return _onReceiveMessage(call.arguments.cast()); + default: + throw new UnsupportedError("Unrecognized Event"); } + } + + /// + /// 申请推送权限,注意这个方法只会向用户弹出一次推送权限请求(如果用户不同意,之后只能用户到设置页面里面勾选相应权限),需要开发者选择合适的时机调用。 + /// + void applyPushAuthority( + [NotificationSettingsIOS iosSettings = const NotificationSettingsIOS()]) { + print(flutter_log + "applyPushAuthority:"); - Future _handleMethod(MethodCall call) async { - print(flutter_log + "_handleMethod:"); - - switch (call.method) { - case "onReceiveNotification": - return _onReceiveNotification(call.arguments.cast()); - case "onOpenNotification": - return _onOpenNotification(call.arguments.cast()); - case "onReceiveMessage": - return _onReceiveMessage(call.arguments.cast()); - default: - throw new UnsupportedError("Unrecognized Event"); - } + if (!_platform.isIOS) { + return; } - /// - /// 申请推送权限,注意这个方法只会向用户弹出一次推送权限请求(如果用户不同意,之后只能用户到设置页面里面勾选相应权限),需要开发者选择合适的时机调用。 - /// - void applyPushAuthority([NotificationSettingsIOS iosSettings = const NotificationSettingsIOS()]) { - print(flutter_log + "applyPushAuthority:"); + _channel.invokeMethod('applyPushAuthority', iosSettings.toMap()); + } - if (!_platform.isIOS) { - return; - } + /// + /// 设置 Tag (会覆盖之前设置的 tags) + /// + /// @param {Array} params = [String] + /// @param {Function} success = ({"tags":[String]}) => { } + /// @param {Function} fail = ({"errorCode":int}) => { } + /// + Future> setTags(List tags) async { + print(flutter_log + "setTags:"); + + final Map result = + await _channel.invokeMethod('setTags', tags); + return result; + } - _channel.invokeMethod('applyPushAuthority', iosSettings.toMap()); - } - - /// - /// 设置 Tag (会覆盖之前设置的 tags) - /// - /// @param {Array} params = [String] - /// @param {Function} success = ({"tags":[String]}) => { } - /// @param {Function} fail = ({"errorCode":int}) => { } - /// - Future> setTags(List tags) async { - print(flutter_log + "setTags:"); - - final Map result = await _channel.invokeMethod('setTags', tags); - return result; - } + /// + /// 清空所有 tags。 + /// + /// @param {Function} success = ({"tags":[String]}) => { } + /// @param {Function} fail = ({"errorCode":int}) => { } + /// + Future> cleanTags() async { + print(flutter_log + "cleanTags:"); + + final Map result = + await _channel.invokeMethod('cleanTags'); + return result; + } - /// - /// 清空所有 tags。 - /// - /// @param {Function} success = ({"tags":[String]}) => { } - /// @param {Function} fail = ({"errorCode":int}) => { } - /// - Future> cleanTags() async { - print(flutter_log + "cleanTags:"); - - final Map result = await _channel.invokeMethod('cleanTags'); - return result; - } - - /// - /// 在原有 tags 的基础上添加 tags - /// - /// @param {Array} tags = [String] - /// @param {Function} success = ({"tags":[String]}) => { } - /// @param {Function} fail = ({"errorCode":int}) => { } - /// - - Future> addTags(List tags) async { - print(flutter_log + "addTags:"); - - final Map result = await _channel.invokeMethod('addTags', tags); - return result; - } - - /// - /// 删除指定的 tags - /// - /// @param {Array} tags = [String] - /// @param {Function} success = ({"tags":[String]}) => { } - /// @param {Function} fail = ({"errorCode":int}) => { } - /// - Future> deleteTags(List tags) async { - print(flutter_log + "deleteTags:"); - - final Map result = await _channel.invokeMethod('deleteTags', tags); - return result; - } - - /// - /// 获取所有当前绑定的 tags - /// - /// @param {Function} success = ({"tags":[String]}) => { } - /// @param {Function} fail = ({"errorCode":int}) => { } - /// - Future> getAllTags() async { - print(flutter_log + "getAllTags:"); - - final Map result = await _channel.invokeMethod('getAllTags'); - return result; - } - - /// - /// 重置 alias. - /// - /// @param {String} alias - /// - /// @param {Function} success = ({"alias":String}) => { } - /// @param {Function} fail = ({"errorCode":int}) => { } - /// - Future> setAlias(String alias) async { - print(flutter_log + "setAlias:"); - - final Map result = await _channel.invokeMethod('setAlias', alias); - return result; - } + /// + /// 在原有 tags 的基础上添加 tags + /// + /// @param {Array} tags = [String] + /// @param {Function} success = ({"tags":[String]}) => { } + /// @param {Function} fail = ({"errorCode":int}) => { } + /// - /// - /// 删除原有 alias - /// - /// @param {Function} success = ({"alias":String}) => { } - /// @param {Function} fail = ({"errorCode":int}) => { } - /// - Future> deleteAlias() async { - print(flutter_log + "deleteAlias:"); - - final Map result = await _channel.invokeMethod('deleteAlias'); - return result; - } + Future> addTags(List tags) async { + print(flutter_log + "addTags:"); - /// - /// 设置应用 Badge(小红点) - /// - /// @param {Int} badge - /// - /// 注意:如果是 Android 手机,目前仅支持华为手机 - /// - Future setBadge(int badge) async { - print(flutter_log + "setBadge:"); - - await _channel.invokeMethod('setBadge', {"badge":badge}); - } + final Map result = + await _channel.invokeMethod('addTags', tags); + return result; + } - /// - /// 停止接收推送,调用该方法后应用将不再受到推送,如果想要重新收到推送可以调用 resumePush。 - /// - Future stopPush() async { - print(flutter_log + "stopPush:"); + /// + /// 删除指定的 tags + /// + /// @param {Array} tags = [String] + /// @param {Function} success = ({"tags":[String]}) => { } + /// @param {Function} fail = ({"errorCode":int}) => { } + /// + Future> deleteTags(List tags) async { + print(flutter_log + "deleteTags:"); + + final Map result = + await _channel.invokeMethod('deleteTags', tags); + return result; + } - await _channel.invokeMethod('stopPush'); - } - - /// - /// 恢复推送功能。 - /// - Future resumePush() async { - print(flutter_log + "resumePush:"); - - await _channel.invokeMethod('resumePush'); - } - - /// - /// 清空通知栏上的所有通知。 - /// - Future clearAllNotifications() async { - print(flutter_log + "clearAllNotifications:"); - - await _channel.invokeMethod('clearAllNotifications'); - } - - /// - /// iOS Only - /// 点击推送启动应用的时候原生会将该 notification 缓存起来,该方法用于获取缓存 notification - /// 注意:notification 可能是 remoteNotification 和 localNotification,两种推送字段不一样。 - /// 如果不是通过点击推送启动应用,比如点击应用 icon 直接启动应用,notification 会返回 @{}。 - /// @param {Function} callback = (Object) => {} - /// - Future> getLaunchAppNotification() async { - print(flutter_log + "getLaunchAppNotification:"); - - final Map result = await _channel.invokeMethod('getLaunchAppNotification'); - return result; - } + /// + /// 获取所有当前绑定的 tags + /// + /// @param {Function} success = ({"tags":[String]}) => { } + /// @param {Function} fail = ({"errorCode":int}) => { } + /// + Future> getAllTags() async { + print(flutter_log + "getAllTags:"); + + final Map result = + await _channel.invokeMethod('getAllTags'); + return result; + } - /// - /// 获取 RegistrationId, JPush 可以通过制定 RegistrationId 来进行推送。 - /// - /// @param {Function} callback = (String) => {} - /// - Future getRegistrationID() async { - print(flutter_log + "getRegistrationID:"); + /// + /// 重置 alias. + /// + /// @param {String} alias + /// + /// @param {Function} success = ({"alias":String}) => { } + /// @param {Function} fail = ({"errorCode":int}) => { } + /// + Future> setAlias(String alias) async { + print(flutter_log + "setAlias:"); + + final Map result = + await _channel.invokeMethod('setAlias', alias); + return result; + } - final String rid = await _channel.invokeMethod('getRegistrationID'); - return rid; - } + /// + /// 删除原有 alias + /// + /// @param {Function} success = ({"alias":String}) => { } + /// @param {Function} fail = ({"errorCode":int}) => { } + /// + Future> deleteAlias() async { + print(flutter_log + "deleteAlias:"); + + final Map result = + await _channel.invokeMethod('deleteAlias'); + return result; + } + + /// + /// 设置应用 Badge(小红点) + /// + /// @param {Int} badge + /// + /// 注意:如果是 Android 手机,目前仅支持华为手机 + /// + Future setBadge(int badge) async { + print(flutter_log + "setBadge:"); + + await _channel.invokeMethod('setBadge', {"badge": badge}); + } + + /// + /// 停止接收推送,调用该方法后应用将不再受到推送,如果想要重新收到推送可以调用 resumePush。 + /// + Future stopPush() async { + print(flutter_log + "stopPush:"); - /// - /// 发送本地通知到调度器,指定时间出发该通知。 - /// @param {Notification} notification - /// - Future sendLocalNotification(LocalNotification notification) async { - print(flutter_log + "sendLocalNotification:"); + await _channel.invokeMethod('stopPush'); + } + + /// + /// 恢复推送功能。 + /// + Future resumePush() async { + print(flutter_log + "resumePush:"); + + await _channel.invokeMethod('resumePush'); + } + + /// + /// 清空通知栏上的所有通知。 + /// + Future clearAllNotifications() async { + print(flutter_log + "clearAllNotifications:"); + + await _channel.invokeMethod('clearAllNotifications'); + } + + /// + /// 清空通知栏上某个通知 + /// @param notificationId 通知 id,即:LocalNotification id + /// + void clearNotification({@required int notificationId}) { + print(flutter_log + "clearNotification:"); + _channel.invokeListMethod("clearNotification",notificationId); + } + + /// + /// iOS Only + /// 点击推送启动应用的时候原生会将该 notification 缓存起来,该方法用于获取缓存 notification + /// 注意:notification 可能是 remoteNotification 和 localNotification,两种推送字段不一样。 + /// 如果不是通过点击推送启动应用,比如点击应用 icon 直接启动应用,notification 会返回 @{}。 + /// @param {Function} callback = (Object) => {} + /// + Future> getLaunchAppNotification() async { + print(flutter_log + "getLaunchAppNotification:"); + + final Map result = + await _channel.invokeMethod('getLaunchAppNotification'); + return result; + } - await _channel.invokeMethod('sendLocalNotification', notification.toMap()); + /// + /// 获取 RegistrationId, JPush 可以通过制定 RegistrationId 来进行推送。 + /// + /// @param {Function} callback = (String) => {} + /// + Future getRegistrationID() async { + print(flutter_log + "getRegistrationID:"); + + final String rid = await _channel.invokeMethod('getRegistrationID'); + return rid; + } + + /// + /// 发送本地通知到调度器,指定时间出发该通知。 + /// @param {Notification} notification + /// + Future sendLocalNotification(LocalNotification notification) async { + print(flutter_log + "sendLocalNotification:"); + + await _channel.invokeMethod('sendLocalNotification', notification.toMap()); return notification.toMap().toString(); - } + } + + } @@ -262,7 +286,7 @@ class NotificationSettingsIOS { final bool alert; final bool badge; - const NotificationSettingsIOS ({ + const NotificationSettingsIOS({ this.sound = true, this.alert = true, this.badge = true, @@ -273,54 +297,47 @@ class NotificationSettingsIOS { } } - - - - - - /// @property {number} [buildId] - 通知样式:1 为基础样式,2 为自定义样式(需先调用 `setStyleCustom` 设置自定义样式) - /// @property {number} [id] - 通知 id, 可用于取消通知 - /// @property {string} [title] - 通知标题 - /// @property {string} [content] - 通知内容 - /// @property {object} [extra] - extra 字段 - /// @property {number} [fireTime] - 通知触发时间(毫秒) - /// // iOS Only - /// @property {number} [badge] - 本地推送触发后应用角标值 - /// // iOS Only - /// @property {string} [soundName] - 指定推送的音频文件 - /// // iOS 10+ Only - /// @property {string} [subtitle] - 子标题 +/// @property {number} [buildId] - 通知样式:1 为基础样式,2 为自定义样式(需先调用 `setStyleCustom` 设置自定义样式) +/// @property {number} [id] - 通知 id, 可用于取消通知 +/// @property {string} [title] - 通知标题 +/// @property {string} [content] - 通知内容 +/// @property {object} [extra] - extra 字段 +/// @property {number} [fireTime] - 通知触发时间(毫秒) +/// // iOS Only +/// @property {number} [badge] - 本地推送触发后应用角标值 +/// // iOS Only +/// @property {string} [soundName] - 指定推送的音频文件 +/// // iOS 10+ Only +/// @property {string} [subtitle] - 子标题 class LocalNotification { - - final int buildId;//? + final int buildId; //? final int id; final String title; final String content; - final Map extra;//? + final Map extra; //? final DateTime fireTime; - final int badge;//? - final String soundName;//? - final String subtitle;//? - - const LocalNotification ({ - @required this.id, - @required this.title, - @required this.content, - @required this.fireTime, - this.buildId, - this.extra, - this.badge = 0, - this.soundName, - this.subtitle - }): - assert(id != null), - assert(title != null), - assert(content != null), - assert(fireTime != null); + final int badge; //? + final String soundName; //? + final String subtitle; //? + + const LocalNotification( + {@required this.id, + @required this.title, + @required this.content, + @required this.fireTime, + this.buildId, + this.extra, + this.badge = 0, + this.soundName, + this.subtitle}) + : assert(id != null), + assert(title != null), + assert(content != null), + assert(fireTime != null); Map toMap() { return { - 'id': id, + 'id': id, 'title': title, 'content': content, 'fireTime': fireTime.millisecondsSinceEpoch, @@ -329,7 +346,6 @@ class LocalNotification { 'badge': badge, 'soundName': soundName, 'subtitle': subtitle - }..removeWhere((key, value)=>value==null); + }..removeWhere((key, value) => value == null); } - } diff --git a/pubspec.lock b/pubspec.lock index 6bb80792..330b2653 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -145,7 +145,7 @@ packages: name: meta url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.6" + version: "1.1.7" mime: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 88c31b67..2f3c2322 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: jpush_flutter description: Offically supported JPush Flutter plugin. -version: 0.2.0 -author: huminios +version: 0.3.0 +author: xudong.rao homepage: https://www.jiguang.cn environment: