feat: Enable APNS registration + notification delivery in macOS apps (#33574)
This commit is contained in:
parent
5314ae5342
commit
afd08c9450
11 changed files with 302 additions and 0 deletions
77
shell/browser/api/electron_api_push_notifications.cc
Normal file
77
shell/browser/api/electron_api_push_notifications.cc
Normal file
|
@ -0,0 +1,77 @@
|
|||
// Copyright (c) 2022 Asana, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/api/electron_api_push_notifications.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "shell/common/gin_converters/value_converter.h"
|
||||
#include "shell/common/gin_helper/dictionary.h"
|
||||
#include "shell/common/node_includes.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace api {
|
||||
|
||||
PushNotifications* g_push_notifications = nullptr;
|
||||
|
||||
gin::WrapperInfo PushNotifications::kWrapperInfo = {gin::kEmbedderNativeGin};
|
||||
|
||||
PushNotifications::PushNotifications() = default;
|
||||
|
||||
PushNotifications::~PushNotifications() {
|
||||
g_push_notifications = nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
PushNotifications* PushNotifications::Get() {
|
||||
if (!g_push_notifications)
|
||||
g_push_notifications = new PushNotifications();
|
||||
return g_push_notifications;
|
||||
}
|
||||
|
||||
// static
|
||||
gin::Handle<PushNotifications> PushNotifications::Create(v8::Isolate* isolate) {
|
||||
return gin::CreateHandle(isolate, PushNotifications::Get());
|
||||
}
|
||||
|
||||
// static
|
||||
gin::ObjectTemplateBuilder PushNotifications::GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) {
|
||||
auto builder = gin_helper::EventEmitterMixin<
|
||||
PushNotifications>::GetObjectTemplateBuilder(isolate);
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
builder
|
||||
.SetMethod("registerForAPNSNotifications",
|
||||
&PushNotifications::RegisterForAPNSNotifications)
|
||||
.SetMethod("unregisterForAPNSNotifications",
|
||||
&PushNotifications::UnregisterForAPNSNotifications);
|
||||
#endif
|
||||
return builder;
|
||||
}
|
||||
|
||||
const char* PushNotifications::GetTypeName() {
|
||||
return "PushNotifications";
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace electron
|
||||
|
||||
namespace {
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports,
|
||||
v8::Local<v8::Value> unused,
|
||||
v8::Local<v8::Context> context,
|
||||
void* priv) {
|
||||
v8::Isolate* isolate = context->GetIsolate();
|
||||
gin::Dictionary dict(isolate, exports);
|
||||
dict.Set("pushNotifications",
|
||||
electron::api::PushNotifications::Create(isolate));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NODE_LINKED_MODULE_CONTEXT_AWARE(electron_browser_push_notifications,
|
||||
Initialize)
|
64
shell/browser/api/electron_api_push_notifications.h
Normal file
64
shell/browser/api/electron_api_push_notifications.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Copyright (c) 2016 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ELECTRON_SHELL_BROWSER_API_ELECTRON_API_PUSH_NOTIFICATIONS_H_
|
||||
#define ELECTRON_SHELL_BROWSER_API_ELECTRON_API_PUSH_NOTIFICATIONS_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <vector>
|
||||
#include "gin/handle.h"
|
||||
#include "gin/wrappable.h"
|
||||
#include "shell/browser/browser_observer.h"
|
||||
#include "shell/browser/electron_browser_client.h"
|
||||
#include "shell/browser/event_emitter_mixin.h"
|
||||
#include "shell/common/gin_helper/promise.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace api {
|
||||
|
||||
class PushNotifications
|
||||
: public ElectronBrowserClient::Delegate,
|
||||
public gin::Wrappable<PushNotifications>,
|
||||
public gin_helper::EventEmitterMixin<PushNotifications>,
|
||||
public BrowserObserver {
|
||||
public:
|
||||
static PushNotifications* Get();
|
||||
static gin::Handle<PushNotifications> Create(v8::Isolate* isolate);
|
||||
|
||||
// gin::Wrappable
|
||||
static gin::WrapperInfo kWrapperInfo;
|
||||
gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
|
||||
v8::Isolate* isolate) override;
|
||||
const char* GetTypeName() override;
|
||||
|
||||
// disable copy
|
||||
PushNotifications(const PushNotifications&) = delete;
|
||||
PushNotifications& operator=(const PushNotifications&) = delete;
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
void OnDidReceiveAPNSNotification(const base::DictionaryValue& user_info);
|
||||
void ResolveAPNSPromiseSetWithToken(const std::string& token_string);
|
||||
void RejectAPNSPromiseSetWithError(const std::string& error_message);
|
||||
#endif
|
||||
|
||||
private:
|
||||
PushNotifications();
|
||||
~PushNotifications() override;
|
||||
// This set maintains all the promises that should be fulfilled
|
||||
// once macOS registers, or fails to register, for APNS
|
||||
std::vector<gin_helper::Promise<std::string>> apns_promise_set_;
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
v8::Local<v8::Promise> RegisterForAPNSNotifications(v8::Isolate* isolate);
|
||||
void UnregisterForAPNSNotifications();
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // ELECTRON_SHELL_BROWSER_API_ELECTRON_API_PUSH_NOTIFICATIONS_H_
|
62
shell/browser/api/electron_api_push_notifications_mac.mm
Normal file
62
shell/browser/api/electron_api_push_notifications_mac.mm
Normal file
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) 2022 Asana, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/api/electron_api_push_notifications.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#import "shell/browser/mac/electron_application.h"
|
||||
#include "shell/common/gin_converters/value_converter.h"
|
||||
#include "shell/common/gin_helper/promise.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
namespace api {
|
||||
|
||||
v8::Local<v8::Promise> PushNotifications::RegisterForAPNSNotifications(
|
||||
v8::Isolate* isolate) {
|
||||
gin_helper::Promise<std::string> promise(isolate);
|
||||
v8::Local<v8::Promise> handle = promise.GetHandle();
|
||||
|
||||
[[AtomApplication sharedApplication]
|
||||
registerForRemoteNotificationTypes:NSRemoteNotificationTypeBadge |
|
||||
NSRemoteNotificationTypeAlert |
|
||||
NSRemoteNotificationTypeSound];
|
||||
|
||||
PushNotifications::apns_promise_set_.emplace_back(std::move(promise));
|
||||
return handle;
|
||||
}
|
||||
|
||||
void PushNotifications::ResolveAPNSPromiseSetWithToken(
|
||||
const std::string& token_string) {
|
||||
std::vector<gin_helper::Promise<std::string>> promises =
|
||||
std::move(PushNotifications::apns_promise_set_);
|
||||
for (auto& promise : promises) {
|
||||
promise.Resolve(token_string);
|
||||
}
|
||||
}
|
||||
|
||||
void PushNotifications::RejectAPNSPromiseSetWithError(
|
||||
const std::string& error_message) {
|
||||
std::vector<gin_helper::Promise<std::string>> promises =
|
||||
std::move(PushNotifications::apns_promise_set_);
|
||||
for (auto& promise : promises) {
|
||||
promise.RejectWithErrorMessage(error_message);
|
||||
}
|
||||
}
|
||||
|
||||
void PushNotifications::UnregisterForAPNSNotifications() {
|
||||
[[AtomApplication sharedApplication] unregisterForRemoteNotifications];
|
||||
}
|
||||
|
||||
void PushNotifications::OnDidReceiveAPNSNotification(
|
||||
const base::DictionaryValue& user_info) {
|
||||
Emit("received-apns-notification", user_info);
|
||||
}
|
||||
|
||||
} // namespace api
|
||||
|
||||
} // namespace electron
|
Loading…
Add table
Add a link
Reference in a new issue