Skip to content

Commit

Permalink
Fix read access violation
Browse files Browse the repository at this point in the history
  • Loading branch information
kennethnym committed Mar 5, 2022
1 parent 0c21c9d commit d2f66e9
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 208 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,159 +23,216 @@
#include <sstream>

using namespace winrt::Windows::Data::Xml::Dom;
namespace {

class FlutterLocalNotificationsPlugin : public flutter::Plugin {
public:
static void RegisterWithRegistrar(flutter::PluginRegistrarWindows* registrar);

FlutterLocalNotificationsPlugin(std::shared_ptr<PluginMethodChannel> channel);

virtual ~FlutterLocalNotificationsPlugin();

private:
std::wstring _aumid;
std::optional<winrt::Windows::UI::Notifications::ToastNotifier> toastNotifier;
std::optional<winrt::Windows::UI::Notifications::ToastNotificationHistory> toastNotificationHistory;
std::shared_ptr<PluginMethodChannel> channel;

// Called when a method is called on this plugin's channel from Dart.
void HandleMethodCall(
const flutter::MethodCall<flutter::EncodableValue>& method_call,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);

/// <summary>
/// Initializes this plugin.
/// </summary>
/// <param name="aumid">The app user model ID that identifies the app.</param>
/// <param name="appName">The display name of the app.</param>
/// <param name="iconPath">An optional path to the icon of the app.</param>
/// <param name="iconBgColor">An optional background color of the icon, in AARRGGBB format.</param>
void Initialize(
const std::string& appName,
const std::string& aumid,
const std::optional<std::string>& iconPath,
const std::optional<std::string>& iconBgColor);

/// <summary>
/// Displays a single notification toast.
/// </summary>
/// <param name="id">A unique ID that identifies this notification. It can be used to cancel/dismiss the notification.</param>
/// <param name="title">An optional title of the notification.</param>
/// <param name="body">An optional body of the notification.</param>
/// <param name="payload"></param>
void ShowNotification(
const int id,
const std::optional<std::string>& title,
const std::optional<std::string>& body,
const std::optional<std::string>& payload,
const std::optional<std::string>& group);

/// <summary>
/// Dismisses the notification that has the given ID.
/// </summary>
/// <param name="id">The ID of the notification to be dismissed.</param>
/// <param name="group">The group the notification is in. Default is the aumid of this app.</param>
void CancelNotification(const int id, const std::optional<std::string>& group);

/// <summary>
/// Dismisses all currently active notifications.
/// </summary>
void CancelAllNotifications();
};

// static
void FlutterLocalNotificationsPlugin::RegisterWithRegistrar(
flutter::PluginRegistrarWindows* registrar) {
auto channel =
std::make_shared<PluginMethodChannel>(
registrar->messenger(), "dexterous.com/flutter/local_notifications",
&flutter::StandardMethodCodec::GetInstance());

auto plugin = std::make_unique<FlutterLocalNotificationsPlugin>(channel);

channel->SetMethodCallHandler(
[plugin_pointer = plugin.get()](const auto& call, auto result) {
plugin_pointer->HandleMethodCall(call, std::move(result));
});

registrar->AddPlugin(std::move(plugin));
}

// static
void FlutterLocalNotificationsPlugin::RegisterWithRegistrar(
flutter::PluginRegistrarWindows* registrar) {
auto channel =
std::make_unique<PluginMethodChannel>(
registrar->messenger(), "dexterous.com/flutter/local_notifications",
&flutter::StandardMethodCodec::GetInstance());

auto plugin = std::make_unique<FlutterLocalNotificationsPlugin>(*channel);

channel->SetMethodCallHandler(
[plugin_pointer = plugin.get()](const auto& call, auto result) {
plugin_pointer->HandleMethodCall(call, std::move(result));
});

registrar->AddPlugin(std::move(plugin));
}

FlutterLocalNotificationsPlugin::FlutterLocalNotificationsPlugin(PluginMethodChannel& channel) :
channel(channel) {}

FlutterLocalNotificationsPlugin::~FlutterLocalNotificationsPlugin() {}
FlutterLocalNotificationsPlugin::FlutterLocalNotificationsPlugin(std::shared_ptr<PluginMethodChannel> channel) :
channel(channel) {}

PluginMethodChannel& FlutterLocalNotificationsPlugin::GetPluginMethodChannel() {
return channel;
}
FlutterLocalNotificationsPlugin::~FlutterLocalNotificationsPlugin() {}

void FlutterLocalNotificationsPlugin::HandleMethodCall(
const flutter::MethodCall<flutter::EncodableValue>& method_call,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result
) {
const auto& method_name = method_call.method_name();
if (method_name == Method::GET_NOTIFICATION_APP_LAUNCH_DETAILS) {
result->Success();
}
else if (method_name == Method::INITIALIZE) {
const auto args = std::get_if<flutter::EncodableMap>(method_call.arguments());
if (args != nullptr) {
const auto appName = Utils::GetMapValue<std::string>("appName", args).value();
const auto aumid = Utils::GetMapValue<std::string>("aumid", args).value();
const auto iconPath = Utils::GetMapValue<std::string>("iconPath", args);
const auto iconBgColor = Utils::GetMapValue<std::string>("iconBgColor", args);

Initialize(appName, aumid, iconPath, iconBgColor);
result->Success(true);
void FlutterLocalNotificationsPlugin::HandleMethodCall(
const flutter::MethodCall<flutter::EncodableValue>& method_call,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result
) {
const auto& method_name = method_call.method_name();
if (method_name == Method::GET_NOTIFICATION_APP_LAUNCH_DETAILS) {
result->Success();
}
else {
result->Error("INTERNAL", "flutter_local_notifications encountered an internal error.");
else if (method_name == Method::INITIALIZE) {
const auto args = std::get_if<flutter::EncodableMap>(method_call.arguments());
if (args != nullptr) {
const auto appName = Utils::GetMapValue<std::string>("appName", args).value();
const auto aumid = Utils::GetMapValue<std::string>("aumid", args).value();
const auto iconPath = Utils::GetMapValue<std::string>("iconPath", args);
const auto iconBgColor = Utils::GetMapValue<std::string>("iconBgColor", args);

Initialize(appName, aumid, iconPath, iconBgColor);
result->Success(true);
}
else {
result->Error("INTERNAL", "flutter_local_notifications encountered an internal error.");
}
}
}
else if (method_name == Method::SHOW) {
channel.InvokeMethod("test", nullptr, nullptr);

const auto args = std::get_if<flutter::EncodableMap>(method_call.arguments());
if (args != nullptr && toastNotifier.has_value()) {
const auto id = Utils::GetMapValue<int>("id", args).value();
const auto title = Utils::GetMapValue<std::string>("title", args);
const auto body = Utils::GetMapValue<std::string>("body", args);
const auto payload = Utils::GetMapValue<std::string>("payload", args);
const auto group = Utils::GetMapValue<std::string>("group", args);

ShowNotification(id, title, body, payload, group);
result->Success();
else if (method_name == Method::SHOW) {
channel->InvokeMethod("test", nullptr);

const auto args = std::get_if<flutter::EncodableMap>(method_call.arguments());
if (args != nullptr && toastNotifier.has_value()) {
const auto id = Utils::GetMapValue<int>("id", args).value();
const auto title = Utils::GetMapValue<std::string>("title", args);
const auto body = Utils::GetMapValue<std::string>("body", args);
const auto payload = Utils::GetMapValue<std::string>("payload", args);
const auto group = Utils::GetMapValue<std::string>("group", args);

ShowNotification(id, title, body, payload, group);
result->Success();
}
else {
result->Error("INTERNAL", "flutter_local_notifications encountered an internal error.");
}
}
else {
result->Error("INTERNAL", "flutter_local_notifications encountered an internal error.");
else if (method_name == Method::CANCEL && toastNotifier.has_value()) {
const auto args = std::get_if<flutter::EncodableMap>(method_call.arguments());
if (args != nullptr) {
const auto id = Utils::GetMapValue<int>("id", args).value();
const auto group = Utils::GetMapValue<std::string>("group", args);

CancelNotification(id, group);
result->Success();
}
else {
result->Error("INTERNAL", "flutter_local_notifications encountered an internal error.");
}
}
}
else if (method_name == Method::CANCEL && toastNotifier.has_value()) {
const auto args = std::get_if<flutter::EncodableMap>(method_call.arguments());
if (args != nullptr) {
const auto id = Utils::GetMapValue<int>("id", args).value();
const auto group = Utils::GetMapValue<std::string>("group", args);

CancelNotification(id, group);
else if (method_name == Method::CANCEL_ALL && toastNotifier.has_value()) {
CancelAllNotifications();
result->Success();
}
else {
result->Error("INTERNAL", "flutter_local_notifications encountered an internal error.");
result->NotImplemented();
}
}
else if (method_name == Method::CANCEL_ALL && toastNotifier.has_value()) {
CancelAllNotifications();
result->Success();
}
else {
result->NotImplemented();
}
}

void FlutterLocalNotificationsPlugin::Initialize(
const std::string& appName,
const std::string& aumid,
const std::optional<std::string>& iconPath,
const std::optional<std::string>& iconBgColor
) {
_aumid = winrt::to_hstring(aumid);
PluginRegistration::RegisterApp(aumid, appName, iconPath, iconBgColor, this);
toastNotifier = winrt::Windows::UI::Notifications::ToastNotificationManager::CreateToastNotifier(winrt::to_hstring(aumid));
}

void FlutterLocalNotificationsPlugin::ShowNotification(
const int id,
const std::optional<std::string>& title,
const std::optional<std::string>& body,
const std::optional<std::string>& payload,
const std::optional<std::string>& group
) {
// obtain a notification template with a title and a body
const auto doc = winrt::Windows::UI::Notifications::ToastNotificationManager::GetTemplateContent(winrt::Windows::UI::Notifications::ToastTemplateType::ToastText02);
// find all <text /> tags
const auto nodes = doc.GetElementsByTagName(L"text");

if (title.has_value()) {
// change the text of the first <text></text>, which will be the title
nodes.Item(0).AppendChild(doc.CreateTextNode(winrt::to_hstring(title.value())));
}
if (body.has_value()) {
// change the text of the second <text></text>, which will be the body
nodes.Item(1).AppendChild(doc.CreateTextNode(winrt::to_hstring(body.value())));
void FlutterLocalNotificationsPlugin::Initialize(
const std::string& appName,
const std::string& aumid,
const std::optional<std::string>& iconPath,
const std::optional<std::string>& iconBgColor
) {
_aumid = winrt::to_hstring(aumid);
PluginRegistration::RegisterApp(aumid, appName, iconPath, iconBgColor, channel);
toastNotifier = winrt::Windows::UI::Notifications::ToastNotificationManager::CreateToastNotifier(winrt::to_hstring(aumid));
}

winrt::Windows::UI::Notifications::ToastNotification notif{ doc };
notif.Tag(winrt::to_hstring(id));
if (group.has_value()) {
notif.Group(winrt::to_hstring(group.value()));
}
else {
notif.Group(_aumid);
}
void FlutterLocalNotificationsPlugin::ShowNotification(
const int id,
const std::optional<std::string>& title,
const std::optional<std::string>& body,
const std::optional<std::string>& payload,
const std::optional<std::string>& group
) {
// obtain a notification template with a title and a body
const auto doc = winrt::Windows::UI::Notifications::ToastNotificationManager::GetTemplateContent(winrt::Windows::UI::Notifications::ToastTemplateType::ToastText02);
// find all <text /> tags
const auto nodes = doc.GetElementsByTagName(L"text");

if (title.has_value()) {
// change the text of the first <text></text>, which will be the title
nodes.Item(0).AppendChild(doc.CreateTextNode(winrt::to_hstring(title.value())));
}
if (body.has_value()) {
// change the text of the second <text></text>, which will be the body
nodes.Item(1).AppendChild(doc.CreateTextNode(winrt::to_hstring(body.value())));
}

toastNotifier.value().Show(notif);
}
winrt::Windows::UI::Notifications::ToastNotification notif{ doc };
notif.Tag(winrt::to_hstring(id));
if (group.has_value()) {
notif.Group(winrt::to_hstring(group.value()));
}
else {
notif.Group(_aumid);
}

void FlutterLocalNotificationsPlugin::CancelNotification(const int id, const std::optional<std::string>& group) {
if (!toastNotificationHistory.has_value()) {
toastNotificationHistory = winrt::Windows::UI::Notifications::ToastNotificationManager::History();
toastNotifier.value().Show(notif);
}

if (group.has_value()) {
toastNotificationHistory.value().Remove(winrt::to_hstring(id), winrt::to_hstring(group.value()), _aumid);
}
else {
toastNotificationHistory.value().Remove(winrt::to_hstring(id), _aumid, _aumid);
void FlutterLocalNotificationsPlugin::CancelNotification(const int id, const std::optional<std::string>& group) {
if (!toastNotificationHistory.has_value()) {
toastNotificationHistory = winrt::Windows::UI::Notifications::ToastNotificationManager::History();
}

if (group.has_value()) {
toastNotificationHistory.value().Remove(winrt::to_hstring(id), winrt::to_hstring(group.value()), _aumid);
}
else {
toastNotificationHistory.value().Remove(winrt::to_hstring(id), _aumid, _aumid);
}
}
}

void FlutterLocalNotificationsPlugin::CancelAllNotifications() {
if (!toastNotificationHistory.has_value()) {
toastNotificationHistory = winrt::Windows::UI::Notifications::ToastNotificationManager::History();
void FlutterLocalNotificationsPlugin::CancelAllNotifications() {
if (!toastNotificationHistory.has_value()) {
toastNotificationHistory = winrt::Windows::UI::Notifications::ToastNotificationManager::History();
}
toastNotificationHistory.value().Clear(_aumid);
}
toastNotificationHistory.value().Clear(_aumid);
}

void FlutterLocalNotificationsPluginRegisterWithRegistrar(
Expand Down
Loading

0 comments on commit d2f66e9

Please sign in to comment.