Skip to content

Commit

Permalink
[flutter_local_notifications] add ability to resolve platform-specifi…
Browse files Browse the repository at this point in the history
…c implementation (#494)

* add ability to resolve platform-specific implementation of plugin with tests, removed instance property

* revert plugin_platform_interface bump

* make the pedantic dev_dependency explicit

* make CI task names more readable

* refactor plugin to use resolvePlatformSpecificImplementation() method where possible

*  update changelog entry on removal of new keyword
  • Loading branch information
MaikuB authored Feb 23, 2020
1 parent ac6563c commit 8f1f54f
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 118 deletions.
12 changes: 8 additions & 4 deletions .cirrus.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
build_example_android_task:
task:
name: Build Android example app
container:
image: cirrusci/flutter:stable
pub_cache:
Expand All @@ -7,7 +8,8 @@ build_example_android_task:
- cd flutter_local_notifications/example
- flutter build apk --debug

build_example_ios_task:
task:
name: Build iOS example app
osx_instance:
image: catalina-flutter
pub_cache:
Expand All @@ -16,14 +18,16 @@ build_example_ios_task:
- cd flutter_local_notifications/example
- flutter build ios --no-codesign --debug

test_platform_interface_task:
task:
name: Run platform interface tests
container:
image: cirrusci/flutter:stable
test_script:
- cd flutter_local_notifications_platform_interface
- flutter test

test_plugin_task:
task:
name: Run plugin unit tests
container:
image: cirrusci/flutter:stable
pub_cache:
Expand Down
9 changes: 9 additions & 0 deletions flutter_local_notifications/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
# [1.2.0]

* Added the `resolvePlatformSpecificImplementation()` method to the `FlutterLocalNotificationsPlugin` class. This can be used to resolve the underlying platform implementation in order to access platform-specific APIs.
* **BREAKING CHANGE* the static `instance` properties in the `IOSFlutterLocalNotificationsPlugin` and `AndroidFlutterLocalNotificationsPlugin` classes have been removed due to addition of the `resolvePlatformSpecificImplementation()`
* Updated readme to remove use of `new` keyword in code snippets
* Bumped e2e dependency
* Bumped example app dependencies
* Make the pedantic dev_dependency explicit

# [1.1.7+1]

* Minor update to readme on description around requesting notification permissions
Expand Down
96 changes: 50 additions & 46 deletions flutter_local_notifications/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,9 @@ The GitHub repository has an example app that should demonstrate of all the supp
The following samples will demonstrate the more commonly used functionalities. The first step is to create a new instance of the plugin class and then initialise it with the settings to use for each platform

```dart
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = new FlutterLocalNotificationsPlugin();
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
// initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project
var initializationSettingsAndroid =
new AndroidInitializationSettings('app_icon');
var initializationSettingsAndroid = AndroidInitializationSettings('app_icon');
var initializationSettingsIOS = IOSInitializationSettings(
onDidReceiveLocalNotification: onDidReceiveLocalNotification);
var initializationSettings = InitializationSettings(
Expand All @@ -91,7 +90,7 @@ Future onSelectNotification(String payload) async {
}
await Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new SecondScreen(payload)),
MaterialPageRoute(builder: (context) => SecondScreen(payload)),
);
}
```
Expand All @@ -108,19 +107,19 @@ By default this plugin will request notification permissions when it is initiali
1. `requestAlertPermission`
that control this behaviour.

If you want to request permissions at a later point in your application, set all of the above to false.
If you want to request permissions at a later point in your application on iOS, set all of the above to false.

```dart
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = new FlutterLocalNotificationsPlugin();
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
var initializationSettingsAndroid =
new AndroidInitializationSettings('app_icon');
var initializationSettingsIOS = new IOSInitializationSettings(
AndroidInitializationSettings('app_icon');
var initializationSettingsIOS = IOSInitializationSettings(
requestSoundPermission: false,
requestBadgePermission: false,
requestAlertPermission: false,
onDidReceiveLocalNotification: onDidReceiveLocalNotification,
);
var initializationSettings = new InitializationSettings(
var initializationSettings = InitializationSettings(
initializationSettingsAndroid, initializationSettingsIOS);
await flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: onSelectNotification);
Expand All @@ -129,13 +128,18 @@ await flutterLocalNotificationsPlugin.initialize(initializationSettings,
Then call `requestPermissions` method with desired permissions at the appropriate point in your application

```dart
var result = await IOSFlutterLocalNotificationsPlugin.instance?.requestPermissions(
sound: true,
badge: true,
alert: true,
);
var result = await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
```

Here the call to `flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>()` returns the iOS implementation of the plugin that contains APIs specific to iOS, provided that the application is running on iOS. The `?.` operator is used here as the result will be null when run on other platforms. Developers may alternative choose to guard this call by checking the platform their application is running on.

### Displaying a notification

```dart
Expand All @@ -156,13 +160,13 @@ In this block of code, the details for each platform have been specified. This i

```dart
var scheduledNotificationDateTime =
new DateTime.now().add(new Duration(seconds: 5));
DateTime.now().add(Duration(seconds: 5));
var androidPlatformChannelSpecifics =
new AndroidNotificationDetails('your other channel id',
AndroidNotificationDetails('your other channel id',
'your other channel name', 'your other channel description');
var iOSPlatformChannelSpecifics =
new IOSNotificationDetails();
NotificationDetails platformChannelSpecifics = new NotificationDetails(
IOSNotificationDetails();
NotificationDetails platformChannelSpecifics = NotificationDetails(
androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.schedule(
0,
Expand All @@ -179,11 +183,11 @@ Note that on Android devices, the default behaviour is that the notification may
```dart
// Show a notification every minute with the first appearance happening a minute after invoking the method
var androidPlatformChannelSpecifics =
new AndroidNotificationDetails('repeating channel id',
AndroidNotificationDetails('repeating channel id',
'repeating channel name', 'repeating description');
var iOSPlatformChannelSpecifics =
new IOSNotificationDetails();
var platformChannelSpecifics = new NotificationDetails(
IOSNotificationDetails();
var platformChannelSpecifics = NotificationDetails(
androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.periodicallyShow(0, 'repeating title',
'repeating body', RepeatInterval.EveryMinute, platformChannelSpecifics);
Expand All @@ -192,13 +196,13 @@ await flutterLocalNotificationsPlugin.periodicallyShow(0, 'repeating title',
### Show a daily notification at a specific time

```dart
var time = new Time(10, 0, 0);
var time = Time(10, 0, 0);
var androidPlatformChannelSpecifics =
new AndroidNotificationDetails('repeatDailyAtTime channel id',
AndroidNotificationDetails('repeatDailyAtTime channel id',
'repeatDailyAtTime channel name', 'repeatDailyAtTime description');
var iOSPlatformChannelSpecifics =
new IOSNotificationDetails();
var platformChannelSpecifics = new NotificationDetails(
IOSNotificationDetails();
var platformChannelSpecifics = NotificationDetails(
androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.showDailyAtTime(
0,
Expand All @@ -211,13 +215,13 @@ await flutterLocalNotificationsPlugin.showDailyAtTime(
### Show a weekly notification on specific day and time

```dart
var time = new Time(10, 0, 0);
var time = Time(10, 0, 0);
var androidPlatformChannelSpecifics =
new AndroidNotificationDetails('show weekly channel id',
AndroidNotificationDetails('show weekly channel id',
'show weekly channel name', 'show weekly description');
var iOSPlatformChannelSpecifics =
new IOSNotificationDetails();
var platformChannelSpecifics = new NotificationDetails(
IOSNotificationDetails();
var platformChannelSpecifics = NotificationDetails(
androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.showWeeklyAtDayAndTime(
0,
Expand Down Expand Up @@ -247,46 +251,46 @@ String groupChannelName = 'grouped channel name';
String groupChannelDescription = 'grouped channel description';
// example based on https://developer.android.com/training/notify-user/group.html
AndroidNotificationDetails firstNotificationAndroidSpecifics =
new AndroidNotificationDetails(
AndroidNotificationDetails(
groupChannelId, groupChannelName, groupChannelDescription,
importance: Importance.Max,
priority: Priority.High,
groupKey: groupKey);
NotificationDetails firstNotificationPlatformSpecifics =
new NotificationDetails(firstNotificationAndroidSpecifics, null);
NotificationDetails(firstNotificationAndroidSpecifics, null);
await flutterLocalNotificationsPlugin.show(1, 'Alex Faarborg',
'You will not believe...', firstNotificationPlatformSpecifics);
AndroidNotificationDetails secondNotificationAndroidSpecifics =
new AndroidNotificationDetails(
AndroidNotificationDetails(
groupChannelId, groupChannelName, groupChannelDescription,
importance: Importance.Max,
priority: Priority.High,
groupKey: groupKey);
NotificationDetails secondNotificationPlatformSpecifics =
new NotificationDetails(secondNotificationAndroidSpecifics, null);
NotificationDetails(secondNotificationAndroidSpecifics, null);
await flutterLocalNotificationsPlugin.show(
2,
'Jeff Chang',
'Please join us to celebrate the...',
secondNotificationPlatformSpecifics);
// create the summary notification required for older devices that pre-date Android 7.0 (API level 24)
List<String> lines = new List<String>();
List<String> lines = List<String>();
lines.add('Alex Faarborg Check this out');
lines.add('Jeff Chang Launch Party');
InboxStyleInformation inboxStyleInformation = new InboxStyleInformation(
InboxStyleInformation inboxStyleInformation = InboxStyleInformation(
lines,
contentTitle: '2 new messages',
summaryText: '[email protected]');
AndroidNotificationDetails androidPlatformChannelSpecifics =
new AndroidNotificationDetails(
AndroidNotificationDetails(
groupChannelId, groupChannelName, groupChannelDescription,
style: NotificationStyleAndroid.Inbox,
styleInformation: inboxStyleInformation,
groupKey: groupKey,
setAsGroupSummary: true);
NotificationDetails platformChannelSpecifics =
new NotificationDetails(androidPlatformChannelSpecifics, null);
NotificationDetails(androidPlatformChannelSpecifics, null);
await flutterLocalNotificationsPlugin.show(
3, 'Attention', 'Two new messages', platformChannelSpecifics);
```
Expand Down Expand Up @@ -389,10 +393,10 @@ By design, iOS applications do not display notifications when they're in the for
```dart
// initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project
var initializationSettingsAndroid =
new AndroidInitializationSettings('app_icon');
var initializationSettingsIOS = new IOSInitializationSettings(
AndroidInitializationSettings('app_icon');
var initializationSettingsIOS = IOSInitializationSettings(
onDidReceiveLocalNotification: onDidReceiveLocalNotification);
var initializationSettings = new InitializationSettings(
var initializationSettings = InitializationSettings(
initializationSettingsAndroid, initializationSettingsIOS);
flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: onSelectNotification);
Expand All @@ -404,19 +408,19 @@ flutterLocalNotificationsPlugin.initialize(initializationSettings,
// display a dialog with the notification details, tap ok to go to another page
showDialog(
context: context,
builder: (BuildContext context) => new CupertinoAlertDialog(
title: new Text(title),
content: new Text(body),
builder: (BuildContext context) => CupertinoAlertDialog(
title: Text(title),
content: Text(body),
actions: [
CupertinoDialogAction(
isDefaultAction: true,
child: new Text('Ok'),
child: Text('Ok'),
onPressed: () async {
Navigator.of(context, rootNavigator: true).pop();
await Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new SecondScreen(payload),
MaterialPageRoute(
builder: (context) => SecondScreen(payload),
),
);
},
Expand Down
7 changes: 1 addition & 6 deletions flutter_local_notifications/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1 @@
include: package:pedantic/analysis_options.1.8.0.yaml

linter:
rules:
- camel_case_types
- unnecessary_new
include: package:pedantic/analysis_options.1.8.0.yaml
20 changes: 10 additions & 10 deletions flutter_local_notifications/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,13 @@ Future<void> main() async {
});
var initializationSettings = InitializationSettings(
initializationSettingsAndroid, initializationSettingsIOS);
var initialised = await flutterLocalNotificationsPlugin.initialize(
initializationSettings, onSelectNotification: (String payload) async {
await flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: (String payload) async {
if (payload != null) {
debugPrint('notification payload: ' + payload);
}
selectNotificationSubject.add(payload);
});
print('initialised: $initialised');
runApp(
MaterialApp(
home: HomePage(),
Expand Down Expand Up @@ -105,13 +104,14 @@ class _HomePageState extends State<HomePage> {
}

void _requestIOSPermissions() {
if (Platform.isIOS) {
IOSFlutterLocalNotificationsPlugin.instance?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
}
flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
}

void _configureDidReceiveLocalNotificationSubject() {
Expand Down
9 changes: 5 additions & 4 deletions flutter_local_notifications/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.3
http: ^0.12.0+2
path_provider: ^1.5.1
shared_preferences: ^0.5.6
http: ^0.12.0+4
path_provider: ^1.6.1
shared_preferences: ^0.5.6+2
rxdart: ^0.23.1
flutter_local_notifications:
path: ../
Expand All @@ -18,7 +18,8 @@ dev_dependencies:
sdk: flutter
flutter_test:
sdk: flutter
e2e: ^0.2.3
e2e: ^0.2.4+2
pedantic: ^1.8.0

flutter:
uses-material-design: true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import 'dart:io';

import 'package:e2e/e2e.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
E2EWidgetsFlutterBinding.ensureInitialized();
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;

setUp(() async {
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
final initializationSettingsAndroid =
AndroidInitializationSettings('app_icon');
final initializationSettingsIOS = IOSInitializationSettings();
final initializationSettings = InitializationSettings(
initializationSettingsAndroid, initializationSettingsIOS);
await flutterLocalNotificationsPlugin.initialize(initializationSettings);
});

testWidgets(
'Can resolve platform-specific plugin implementation when run on appropriate platform',
(WidgetTester tester) async {
if (Platform.isIOS) {
expect(
flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
.runtimeType,
IOSFlutterLocalNotificationsPlugin);
} else if (Platform.isAndroid) {
expect(
flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
.runtimeType,
AndroidFlutterLocalNotificationsPlugin);
}
});
}
Loading

0 comments on commit 8f1f54f

Please sign in to comment.