Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[flutter_local_notifications_windows] Fix URIs on Windows -- images and audio #2511

Merged
merged 37 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
6743e8f
Updated _windows to use proper URIs for images and audio
Levi-Lesches Dec 31, 2024
14aa3b7
Lints and format
Levi-Lesches Dec 31, 2024
86d1028
Consolidated consdtructors
Levi-Lesches Dec 31, 2024
4e1bf65
Bumped versions
Levi-Lesches Dec 31, 2024
3b9caad
Configure melos to use flutter test for Windows
Levi-Lesches Dec 31, 2024
0e3da90
Update changelog
Levi-Lesches Dec 31, 2024
0cdb65d
Updated changelog again
Levi-Lesches Dec 31, 2024
17d175c
Elaborated on changelogs
Levi-Lesches Dec 31, 2024
46e5ce3
Updated docs
Levi-Lesches Dec 31, 2024
155f17f
Converted WindowsImage back to URIs
Levi-Lesches Dec 31, 2024
f5809e9
Updated examples and tests
Levi-Lesches Dec 31, 2024
016fcc0
Moved docs
Levi-Lesches Dec 31, 2024
7b72c88
Updated changelogs
Levi-Lesches Dec 31, 2024
97c3827
Formatted
Levi-Lesches Dec 31, 2024
ae6368a
temporarily enable verbose logging
MaikuB Dec 31, 2024
0e128a2
Updated to use new package:msix functions
Levi-Lesches Dec 31, 2024
052d9c6
Use Msix.hasPackageIdentity for WindowsNotificationAudio.asset
Levi-Lesches Jan 1, 2025
5b0dacd
Implemented hasPackageIdentity() and assetUri()
Levi-Lesches Jan 1, 2025
8e4b5ca
Formatted
Levi-Lesches Jan 1, 2025
dd71976
Updated changelogs
Levi-Lesches Jan 1, 2025
ba19492
Disabled avoid_classes_with_only_static_members
Levi-Lesches Jan 1, 2025
35a1324
Bumped minimum dart: ^3.4, flutter: ^3.22
Levi-Lesches Jan 1, 2025
b966b1d
Bumped to dart: 3.5, flutter: 3.24
Levi-Lesches Jan 1, 2025
1fa7152
Moved FFI code around to not need package:win32
Levi-Lesches Jan 1, 2025
7428d92
Revert "Bumped to dart: 3.5, flutter: 3.24"
Levi-Lesches Jan 1, 2025
cca327b
Revert "Bumped minimum dart: ^3.4, flutter: ^3.22"
Levi-Lesches Jan 1, 2025
db49078
Made WindowsPlugin.isValidXml
Levi-Lesches Jan 1, 2025
fd38bdb
Stabilized flaky tests
Levi-Lesches Jan 1, 2025
3cc7e61
Updated melos and changelogs
Levi-Lesches Jan 1, 2025
c67ee5a
Cancel notif after schedule test
Levi-Lesches Jan 1, 2025
78c0733
Skip flaky test
Levi-Lesches Jan 1, 2025
348d5f8
Added Windows XML validation to the example
Levi-Lesches Jan 1, 2025
ef5f691
Deleted problematic tests
Levi-Lesches Jan 1, 2025
e7b5e21
Update melos.yaml
MaikuB Jan 1, 2025
d7c7883
Addressed feedback
Levi-Lesches Jan 2, 2025
183762a
Removed enableMultithreading()
Levi-Lesches Jan 2, 2025
ff7a0ee
remove more enableMultithreading
Levi-Lesches Jan 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions flutter_local_notifications/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## [19.0.0-dev.4]

* [Windows] Reworked the APIs around custom images and audio. Use the new `.asset()` or `.network()` constructors. This is a breaking change from `19.0.0-dev.1`.
Levi-Lesches marked this conversation as resolved.
Show resolved Hide resolved

## [19.0.0-dev.3]

* [iOS][macOS] **Breaking changes** the `DarwinNotificationActionOption` and `DarwinNotificationCategoryOption` are now enhanced enums with values accessible through the `value` property that are exactly the same as their native representations. Previously a bitwise left shift operation was applied to the index value
Expand All @@ -13,7 +17,7 @@

* **Breaking change** bumped minimum Flutter SDK requirement to 3.19.0 and Dart SDK requirement to 3.3.0
* **Breaking change** [iOS] removed `uiLocalNotificationDateInterpretation` parameter from `zonedSchedule()` method. This was done as it actually no relevant as of the 18.0.0 that dropped support for iOS versions older than 10, which in turn meant that the deprecated `UILocalNotification` APIs from Apple were no longer used. The corresponding `UILocalNotificationDateInterpretation` enum has already been removed as well
* [Windows] Added support for Windows. Thanks to the PR from [Levi Lesches](https://github.com/Levi-Lesches/) that continued from the contributions from
* [Windows] Added support for Windows. Thanks to the PR from [Levi Lesches](https://github.com/Levi-Lesches/) that continued from the contributions from
* Bumped `timezone` dependency so that minimum version is now 0.10.0

## [18.0.1]
Expand Down Expand Up @@ -167,7 +171,7 @@
# [15.1.0]

* [iOS][macOS] added the ability to request provisional permissions. On iOS, this is only applicable to iOS 12 or newer. On macOS, this property is only applicable to macOS 10.14 or newer. Thanks to the PR from [Tokenyet](https://github.com/MaikuB/flutter_local_notifications/pull/2022)

# [15.0.1]

* [Android] fixed issue [2033](https://github.com/MaikuB/flutter_local_notifications/issues/2033) where notifications on scheduled using older version of the plugin would fail to have the next subsequent ones scheduled. This issue started occuring in 14.0 where support for inexact notifications was added using the `ScheduleMode` enum that was added and resulted in the deprecation of `androidAllowWhileIdle`. A mechanism was added to help "migrate" old notifications that had `androidAllowWhileIdle` specified but didn't account for how there are recurring notifications that were scheduled using older versions of the plugin prior to `androidAllowWhile` being added. This was also released part of the 14.1.2 hotfix release
Expand All @@ -176,7 +180,7 @@

* **Breaking change** removed deprecated `schedule()`, `showDailyAtTime()` and `showWeeklyAtDayAndTime()` methods. Notifications that were scheduled prior to this release should still work
* **Breaking change** removed `Time` class
* [Linux] **Breaking change** calling `zonedSchedule()` on Linux will now throw an `UnimplementedError` to align with how their is a Linux implementation but the method hasn't been implemented
* [Linux] **Breaking change** calling `zonedSchedule()` on Linux will now throw an `UnimplementedError` to align with how their is a Linux implementation but the method hasn't been implemented
* [iOS][macOS] **Breaking change** added supported for banner and list presentation options for iOS and macOS that is applicable for iOS 14.0 or newer and macOS 11 or newer. This is a breaking change as the values default to true and the alert presentation option is no longer applicable on these OS versions as Apple has deprecated it to be replaced by the banner and list presentations. Please ensure that if you target these OS versions that you configure the options appropriately for your application.
* [Android] updated tags used when writing error logs. For corrupt scheduled notifications and error is logged the tag is now `ScheduledNotifReceiver` instead of `ScheduledNotifReceiver`. When logging that exact alarm permissions have been revoked the the tag is now `FLTLocalNotifPlugin` instead of `notification`
* Updated API documentation related to the iOS/macOS notification presentation options to include links to Apple's documentations to show what they correspond to
Expand Down Expand Up @@ -272,10 +276,10 @@
...
}
```

# [12.0.4]

* Fixed issue [1796](https://github.com/MaikuB/flutter_local_notifications/issues/1796) where a `java.lang.ClassCastException` may be thrown on some Android devices when the `onDidReceiveBackgroundNotificationResponse` has been specified when calling `initialize()`
* Fixed issue [1796](https://github.com/MaikuB/flutter_local_notifications/issues/1796) where a `java.lang.ClassCastException` may be thrown on some Android devices when the `onDidReceiveBackgroundNotificationResponse` has been specified when calling `initialize()`

# [12.0.3+1]

Expand All @@ -299,7 +303,7 @@

# [12.0.1]

* [Android][iOS] fixed issue [1721](https://github.com/MaikuB/flutter_local_notifications/issues/1721) where a crash occurs upon tapping on a notification action fbut the `onDidReceiveBackgroundNotificationResponse` optional callback hasn't been specified.
* [Android][iOS] fixed issue [1721](https://github.com/MaikuB/flutter_local_notifications/issues/1721) where a crash occurs upon tapping on a notification action fbut the `onDidReceiveBackgroundNotificationResponse` optional callback hasn't been specified.
* [iOS] suppressed deprecation warnings where plugin was Apple's old notification APIs to support older iOS devices

# [12.0.0]
Expand Down Expand Up @@ -333,7 +337,7 @@
* `GET_ACTIVE_NOTIFICATION_MESSAGING_STYLE_ERROR_CODE` -> `getActiveNotificationMessagingStyle`
* `PERMISSION_REQUEST_IN_PROGRESS` -> `permissionRequestInProgress`
* [Android] **Breaking change** the `category` of the `AndroidNotificationDetails` now requires an instance of the newly added `AndroidNotificationCategory` class instead of a string. This was to improve the discoverability of the APIs and improve the semantics as the category can specified in a similar fashion to using an enum value
* **Breaking change** callbacks have now been reworked. There are now the following callbacks and both will pass an instance of the `NotificationResponse` class
* **Breaking change** callbacks have now been reworked. There are now the following callbacks and both will pass an instance of the `NotificationResponse` class
* `onDidReceiveNotificationResponse`: invoked only when the app is running. This works for when a user has selected a notification or notification action. This replaces the `onSelectNotification` callback that existed before. For notification actions, the action needs to be configured to indicate the the app or user interface should be shown on invoking the action for this callback to be invoked i.e. by specifying the `DarwinNotificationActionOption.foreground` option on iOS and the `showsUserInterface` property on Android. On macOS and Linux, as there's no support for background isolates it will always invoke this callback
* `onDidReceiveBackgroundNotificationResponse`: invoked on a background isolate for when a user has selected a notification action. This replaces the `onSelectNotificationAction` callback
* **Breaking change** the `NotificationAppLaunchDetails` has been updated to contain an instance `NotificationResponse` class with the `payload` belonging to the `NotificationResponse` class. This is to allow knowing more details about what caused the app to launch e.g. if a notification action was used to do so
Expand Down Expand Up @@ -435,7 +439,7 @@
# [9.2.0]

* [Android] Added `areNotificationsEnabled()` method to `AndroidFlutterLocalNotificationsPlugin`. This allows querying if notifications are enabled for the app calling the method. Thanks to the PR from [Konstantin Pelz](https://github.com/komape)
* [Linux] Fix `initialize()` returning null all the time instead of returning an appropriate boolean value to indicate if plugin has been initialised
* [Linux] Fix `initialize()` returning null all the time instead of returning an appropriate boolean value to indicate if plugin has been initialised

# [9.1.5]

Expand Down Expand Up @@ -836,7 +840,7 @@ Please note that there are a number of breaking changes in this release to impro
* `BitmapSource.Drawable` -> `DrawableResourceAndroidBitmap`
* `BitmapSource.FilePath` -> `FilePathAndroidBitmap`

Each of these subclasses has a constructor that an argument referring to the bitmap itself. For example, if you previously had the following code
Each of these subclasses has a constructor that an argument referring to the bitmap itself. For example, if you previously had the following code

```dart
var androidPlatformChannelSpecifics = AndroidNotificationDetails(
Expand Down Expand Up @@ -888,7 +892,7 @@ Please note that there are a number of breaking changes in this release to impro
* The `DefaultStyleInformation` class now implements the `StyleInformation` class instead of extending it
* Where possible, classes in the plugins have been updated to provide `const` constructors
* Updates to API docs and readme
* Bump Android dependencies
* Bump Android dependencies
* Fixed a grammar issue 0.9.1 changelog entry

# [1.3.0]
Expand Down Expand Up @@ -1164,7 +1168,7 @@ Please note that there are a number of breaking changes in this release to impro

# [0.4.2]

* **Breaking change** Fix issue [127](https://github.com/MaikuB/flutter_local_notifications/issues/127) by changing plugin to Android Support Library version 27.1.1, compile and target SDK version to 27 due to issues Flutter has with API 28.
* **Breaking change** Fix issue [127](https://github.com/MaikuB/flutter_local_notifications/issues/127) by changing plugin to Android Support Library version 27.1.1, compile and target SDK version to 27 due to issues Flutter has with API 28.

# [0.4.1+1]
* Remove unused code in example app
Expand All @@ -1174,7 +1178,7 @@ Please note that there are a number of breaking changes in this release to impro
* **Breaking change** renamed the `selectNotification` callback exposed by the `initialize` function to `onSelectNotification`
* **Breaking change** renamed the `MessageHandler` typedef to `SelectNotificationCallback`
* **Breaking change** updated plugin to Android Support Library version 28.0, compile and target SDK version to 28
* Address issue [115](https://github.com/MaikuB/flutter_local_notifications/issues/115) by adding validation to the notification ID values. This ensure they're within the range of a 32-bit integer as notification IDs on Android need to be within that range. Note that an `ArgumentError` is thrown when a value is out of range.
* Address issue [115](https://github.com/MaikuB/flutter_local_notifications/issues/115) by adding validation to the notification ID values. This ensure they're within the range of a 32-bit integer as notification IDs on Android need to be within that range. Note that an `ArgumentError` is thrown when a value is out of range.
* Updated the Android Integration section around registering receivers via the Android manifest as per the suggestion in [116](https://github.com/MaikuB/flutter_local_notifications/issues/116)
* Updated version of the http dependency for used by the example app

Expand Down
6 changes: 4 additions & 2 deletions flutter_local_notifications/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1331,8 +1331,10 @@ class _HomePageState extends State<HomePage> {
);
final WindowsNotificationDetails windowsNotificationDetails =
WindowsNotificationDetails(
audio: WindowsNotificationAudio.preset(
sound: WindowsNotificationSound.alarm5),
audio: WindowsNotificationAudio.asset(
'sound/slow_spring_board.mp3',
debugModeFallback: WindowsNotificationSound.alarm5,
),
);
final NotificationDetails notificationDetails = NotificationDetails(
android: androidNotificationDetails,
Expand Down
26 changes: 14 additions & 12 deletions flutter_local_notifications/example/lib/windows.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
Expand Down Expand Up @@ -202,12 +201,12 @@ Future<void> _showWindowsNotificationWithImages() =>
flutterLocalNotificationsPlugin.show(
id++,
'This notification has an image',
'You can only show images from files',
'You can show images from assets or the network. See the columns example as well.',
NotificationDetails(
windows: WindowsNotificationDetails(
images: <WindowsImage>[
WindowsImage.file(
File('./icons/4.0x/app_icon_density.png').absolute,
WindowsImage.asset(
'icons/4.0x/app_icon_density.png',
altText: 'A beautiful image',
),
],
Expand All @@ -219,23 +218,26 @@ Future<void> _showWindowsNotificationWithGroups() =>
flutterLocalNotificationsPlugin.show(
id++,
'This notification has many groups',
'Each group stays together',
'Each group stays together. Web images only load in MSIX builds',
NotificationDetails(
windows: WindowsNotificationDetails(
subtitle: 'Caption text is fainter',
rows: <WindowsRow>[
WindowsRow(<WindowsColumn>[
WindowsColumn(<WindowsNotificationPart>[
WindowsImage.file(File('icons/coworker.png').absolute,
altText: 'A coworker'),
WindowsImage.asset(
'icons/coworker.png',
altText: 'A local image',
),
const WindowsNotificationText(
text: 'A coworker', isCaption: true),
text: 'A local image', isCaption: true),
]),
WindowsColumn(<WindowsNotificationPart>[
WindowsImage.file(
File('icons/4.0x/app_icon_density.png').absolute,
altText: 'The icon'),
const WindowsNotificationText(text: 'The icon'),
WindowsImage.network(
Uri.parse('https://picsum.photos/100'),
altText: 'A web image',
),
const WindowsNotificationText(text: 'A web image'),
]),
]),
],
Expand Down
4 changes: 2 additions & 2 deletions flutter_local_notifications/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: flutter_local_notifications
description: A cross platform plugin for displaying and scheduling local
notifications for Flutter applications with the ability to customise for each
platform.
version: 19.0.0-dev.3
version: 19.0.0-dev.4
homepage: https://github.com/MaikuB/flutter_local_notifications/tree/master/flutter_local_notifications
issue_tracker: https://github.com/MaikuB/flutter_local_notifications/issues

Expand All @@ -11,7 +11,7 @@ dependencies:
flutter:
sdk: flutter
flutter_local_notifications_linux: ^5.0.1-dev.1
flutter_local_notifications_windows: ^1.0.0-dev.2
flutter_local_notifications_windows: ^1.0.0-dev.3
flutter_local_notifications_platform_interface: ^8.1.0-dev.1
timezone: ^0.10.0

Expand Down
4 changes: 4 additions & 0 deletions flutter_local_notifications_windows/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## [1.0.0-dev.3]

* Reworked the APIs around custom images and audio. Use the new `.asset()` or `.network()` constructors

## [1.0.0-dev.2]

* Fixed an issue that happens with MSIX app builds. Thanks to PR from [Levi Lesches](https://github.com/Levi-Lesches)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
extension on Uri {
String get filename => pathSegments.last;
String get extension => pathSegments.last.split('.').last;
}
import 'package:flutter/foundation.dart';

/// A preset sound for a Windows notification.
enum WindowsNotificationSound {
Expand Down Expand Up @@ -101,41 +98,22 @@ class WindowsNotificationAudio {
}) : isSilent = false,
source = sound.name;

/// Audio from a file. See [allowedSchemes] and [allowedExtensions].
WindowsNotificationAudio.fromFile({
required Uri file,
/// Uses an audio file from a Flutter asset.
///
/// Note that this will only work in release builds that have been packaged as
/// an MSIX installer. Currently, there is no way to test this in debug mode.
///
/// Windows supports the following formats: `.aac`, `.flac`, `.m4a`, `.mp3`,
/// `.wav`, and `.wma`.
WindowsNotificationAudio.asset(
String assetName, {
this.shouldLoop = false,
WindowsNotificationSound debugModeFallback =
WindowsNotificationSound.defaultSound,
Levi-Lesches marked this conversation as resolved.
Show resolved Hide resolved
}) : isSilent = false,
source = file.toFilePath() {
if (!allowedSchemes.contains(file.scheme)) {
throw ArgumentError.value(
file.toString(),
'WindowsNotificationAudio.file',
'URI scheme must be one of the following schemes: $allowedSchemes',
);
}
if (!file.filename.contains('.') ||
!allowedExtensions.contains(file.extension)) {
throw ArgumentError.value(
file.toString(),
'WindowsNotificationAudio.file',
'File extension must be one of the following: $allowedExtensions',
);
}
}

/// Allowed Uri schemes for [WindowsNotificationAudio.fromFile].
static const Set<String> allowedSchemes = <String>{'ms-appx', 'ms-resource'};

/// Allowed file extensions for [WindowsNotificationAudio.fromFile].
static const Set<String> allowedExtensions = <String>{
'aac',
'flac',
'm4a',
'mp3',
'wav',
'wma'
};
source = kDebugMode
? debugModeFallback.name
: 'ms-appx:///data/flutter_assets/$assetName';

/// Whether this audio should loop.
final bool shouldLoop;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'dart:io';

import 'package:flutter/foundation.dart';

/// A text or image element in a Windows notification.
///
/// Note: This should not be used for anything else as notification
Expand Down Expand Up @@ -30,23 +32,37 @@ enum WindowsImageCrop {

/// An image in a Windows notification.
class WindowsImage extends WindowsNotificationPart {
/// Creates a Windows notification image.
const WindowsImage.file(
this.file, {
/// Creates a Windows notification image from a network image.
const WindowsImage.network(
this.uri, {
required this.altText,
this.addQueryParams = false,
this.placement,
this.crop,
});

/// Creates a Windows notification image from a [Flutter asset](https://docs.flutter.dev/ui/assets/assets-and-images#loading-images).
///
/// In debug builds, this will use a `file:///` URI, but in release builds, it will use an
/// `ms-appx:///` URI. Note that release builds must be packaged in an MSIX installer to work.
WindowsImage.asset(
String assetName, {
required this.altText,
this.addQueryParams = false,
this.placement,
this.crop,
}) : uri = kDebugMode
? Uri.file(File(assetName).absolute.path, windows: true)
: Uri.parse('ms-appx:///data/flutter_assets/$assetName');

/// Whether Windows should add URL query parameters when fetching the image.
final bool addQueryParams;

/// A description of the image to be used by assistive technology.
final String altText;

/// The source of the image.
final File file;
final Uri uri;

/// Where this image will be placed. Null indicates below the notification.
final WindowsImagePlacement? placement;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,10 @@ extension ImageToXml on WindowsImage {
///
/// See: https://learn.microsoft.com/en-us/uwp/schemas/tiles/toastschema/element-image
void buildXml(XmlBuilder builder) {
if (!file.isAbsolute) {
throw ArgumentError.value(
file.path,
'WindowsImage.file',
'File path must be absolute',
);
}
builder.element(
'image',
attributes: <String, String>{
'src': Uri.file(file.absolute.path, windows: true).toFilePath(),
'src': uri.toString(),
'alt': altText,
'addImageQuery': addQueryParams.toString(),
if (placement != null) 'placement': placement!.name,
Expand Down
4 changes: 3 additions & 1 deletion flutter_local_notifications_windows/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
name: flutter_local_notifications_windows
description: Windows implementation of the flutter_local_notifications plugin
version: 1.0.0-dev.2
version: 1.0.0-dev.3
homepage: https://github.com/MaikuB/flutter_local_notifications/tree/master/flutter_local_notifications_windows

environment:
sdk: ">=3.3.0 <4.0.0"
flutter: ">=3.19.0"

dependencies:
flutter:
sdk: flutter
ffi: ^2.1.2
flutter_local_notifications_platform_interface: ^8.1.0-dev.1
meta: ^1.11.0
Expand Down
Loading
Loading