-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #150 from breez/savage-notification-plugin
Notification Plugin docs
- Loading branch information
Showing
18 changed files
with
1,075 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,114 +1,14 @@ | ||
# Receiving payments via mobile notifications | ||
# Introduction | ||
|
||
The Breez SDK provides users the ability to receive Lightning payments via mobile notifications. It uses a webhook that allows your application to be notified (via a pre-specified URL) when a payment is about to be received. To use this feature, you need to set up a webhook that an LSP can call when a payment is received and [register it in the Breez SDK](payment_notification.html#step-3-register-a-webhook). This webhook, a URL endpoint in your application, will handle incoming payment notifications. This URL should be capable of receiving POST requests. The payment received webhook payload is json formatted and contains the following structure: | ||
|
||
<section> | ||
<pre> | ||
{ | ||
"template": "payment_received", | ||
"data": { | ||
"payment_hash": [payment hash] | ||
} | ||
} | ||
</pre> | ||
</section> | ||
|
||
## Webhook integration for receiving payments while the app isn't running | ||
You can use this webhook to allow mobile users to receive Lightning payments even if they aren't running the app at the time of the payment. This process involves using a Notification Delivery Service (NDS) acting as an intermediary. When a payment is made to a user, the LSP sends a notification to the NDS configured with a specific webhook URL. The NDS then processes this information and dispatches a push notification to the intended mobile device, ensuring the user receives timely updates about incoming payments. This architecture necessitates vendors setting up and maintaining their own NDS, tailored to handle and forward these notifications efficiently. | ||
The Breez SDK Notification Plugin provides vendors the ability to receive events via mobile notifications even while the application is in the background or closed. This plugin processes several different notification types like receiving payments, LNURL-pay flows and swap confirmations. You can even extend the functionality to handle your own notification types within your application. | ||
|
||
![receive via notifications_2](https://github.com/breez/breez-sdk-docs/assets/31890660/75e7cac6-4480-453d-823b-f52bd6757ce9) | ||
|
||
### Step 1: Run your own NDS | ||
You will need to run your own NDS because the NDS is configured to send push notifications to your app users and therefore should be configured with the required keys and certificates. | ||
|
||
You can use our [reference NDS implementation](https://github.com/breez/notify). | ||
|
||
Our NDS implementation expects URLs in the following format: | ||
<section> | ||
<pre> | ||
https://your-nds-service.com/notify?platform=<ios|android>&token=[PUSH_TOKEN] | ||
</pre> | ||
</section> | ||
|
||
Once the NDS has received such request it will send a push notification to the corresponding devices. | ||
|
||
### Step 2: Obtain a mobile push token | ||
Ensure that your mobile application is set up to receive push notifications and can generate a push token. This token uniquely identifies the device for push notifications. | ||
* For iOS, use [Apple Push Notification Service (APNs)](https://developer.apple.com/documentation/usernotifications/registering_your_app_with_apns) to get the token. | ||
* For Android, use [Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging/manage-tokens) to obtain the token. | ||
|
||
### Step 3: Register a webhook | ||
Register the constructed URL with the Breez SDK By calling the register-payment-webook API as follows: | ||
|
||
<custom-tabs category="lang"> | ||
<div slot="title">Rust</div> | ||
<section> | ||
|
||
```rust,ignore | ||
{{#include ../../snippets/rust/src/webhook.rs:register-payment-webook}} | ||
``` | ||
</section> | ||
|
||
<div slot="title">Swift</div> | ||
<section> | ||
|
||
```swift,ignore | ||
{{#include ../../snippets/swift/BreezSDKExamples/Sources/Webhook.swift:register-payment-webook}} | ||
``` | ||
</section> | ||
|
||
<div slot="title">Kotlin</div> | ||
<section> | ||
|
||
```kotlin,ignore | ||
{{#include ../../snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/Webhook.kt:register-payment-webook}} | ||
``` | ||
</section> | ||
|
||
<div slot="title">React Native</div> | ||
<section> | ||
|
||
```typescript | ||
{{#include ../../snippets/react-native/webhook.ts:register-payment-webook}} | ||
``` | ||
</section> | ||
|
||
<div slot="title">Dart</div> | ||
<section> | ||
|
||
```dart,ignore | ||
{{#include ../../snippets/dart_snippets/lib/webhook.dart:register-payment-webook}} | ||
``` | ||
</section> | ||
|
||
<div slot="title">Python</div> | ||
<section> | ||
|
||
```python,ignore | ||
{{#include ../../snippets/python/src/webhook.py:register-payment-webook}} | ||
``` | ||
</section> | ||
|
||
<div slot="title">Go</div> | ||
<section> | ||
|
||
```go,ignore | ||
{{#include ../../snippets/go/webhook.go:register-payment-webook}} | ||
``` | ||
</section> | ||
|
||
<div slot="title">C#</div> | ||
<section> | ||
|
||
```cs,ignore | ||
{{#include ../../snippets/csharp/Webhook.cs:register-payment-webook}} | ||
``` | ||
</section> | ||
|
||
</custom-tabs> | ||
## How it works | ||
|
||
### Step 4: Handling notifications when the app isn't running | ||
To ensure that your mobile application can handle payment notifications even when it is not actively running, specific implementations are required for both iOS and Android platforms. This involves waking up the app upon receiving a push notification, connecting with the Breez SDK, and then waiting for the payment to be fully received. | ||
* For iOS, please follow the steps in [iOS NotificationServiceExtension](ios_notification_service_extension.md). | ||
This process involves using a Notification Delivery Service (NDS) acting as an intermediary host by the application developer. The NDS must provide a public facing webhook URL where a POST request can be sent to when a notification needs to be delivered to the application. The NDS then forwards the data sent in the webhook POST request via push notification to the application. When the application then receives the push notification then Breez SDK Notification Plugin can be used to process the event. | ||
|
||
* For Android, please follow the steps in [Android foreground service](android_notification_foreground_service.md). | ||
## Next Steps | ||
- **[Setup an NDS](/notifications/setup_nds.md)** to receive webhook requests | ||
- **[Register a webhook](/notifications/register_webhook.md)** in your main application | ||
- **[Project integration](/notifications/setup_plugin.md)** using a notification service extension or foreground service |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
# Add the Android Notification Plugin | ||
|
||
Add the `breez-sdk` dependency to your application's `build.gradle` file in the `app` directory. | ||
|
||
```gradle | ||
android { | ||
defaultConfig { | ||
// Add a build config field to read the Breez API key | ||
// from a git ignored `gradle.properties` file | ||
buildConfigField "String", "BREEZ_SDK_API_KEY", project.property('BREEZ_SDK_API_KEY') | ||
} | ||
// This might help building if duplicate libraries are found | ||
packagingOptions { | ||
pickFirst "lib/armeabi-v7a/libc++_shared.so" | ||
pickFirst "lib/arm64-v8a/libc++_shared.so" | ||
pickFirst "lib/x86/libc++_shared.so" | ||
pickFirst "lib/x86_64/libc++_shared.so" | ||
exclude "META-INF/*" | ||
} | ||
} | ||
dependencies { | ||
// Add the breez-sdk dependency | ||
implementation "com.github.breez:breez-sdk" | ||
} | ||
``` | ||
|
||
## Integrate the Notification Plugin | ||
|
||
You're ready to add some Kotlin code to implement the Notification Plugin in your application. In the example below, we are using the `FirebaseMessagingService` to receive the message intents. First, let's implement the Notification Plugin's `MessagingService` class along with `FirebaseMessagingService`. | ||
|
||
```kotlin | ||
package com.example.application | ||
|
||
import android.annotation.SuppressLint | ||
import android.content.Intent | ||
import androidx.core.content.ContextCompat | ||
import breez_sdk_notification.Constants | ||
import breez_sdk_notification.Message | ||
import breez_sdk_notification.MessagingService | ||
import com.google.firebase.messaging.FirebaseMessagingService | ||
import com.google.firebase.messaging.RemoteMessage | ||
|
||
@SuppressLint("MissingFirebaseInstanceTokenRefresh") | ||
class ExampleFcmService : MessagingService, FirebaseMessagingService() { | ||
companion object { | ||
private const val TAG = "FcmService" | ||
} | ||
|
||
// Override the `onMessageReceived` to handle the remote message | ||
override fun onMessageReceived(remoteMessage: RemoteMessage) { | ||
super.onMessageReceived(remoteMessage) | ||
|
||
// Check if the message is high priority and can be handled | ||
if (remoteMessage.priority == RemoteMessage.PRIORITY_HIGH) { | ||
remoteMessage.asMessage()?.also { message -> | ||
// Call `startServiceIfNeeded` to check if the foreground | ||
// service is needed depending on the message type and | ||
// foreground state of the application | ||
startServiceIfNeeded(applicationContext, message) | ||
} | ||
} | ||
} | ||
|
||
// A helper function the convert the `RemoteMessage` | ||
// to a notification plugin 'Message' | ||
private fun RemoteMessage.asMessage(): Message? { | ||
return data[Constants.MESSAGE_DATA_TYPE]?.let { | ||
Message( | ||
data[Constants.MESSAGE_DATA_TYPE], data[Constants.MESSAGE_DATA_PAYLOAD] | ||
) | ||
} | ||
} | ||
|
||
// Override the `startForegroundService` function to start the foreground service | ||
// using the `ExampleForegroundService` handler | ||
override fun startForegroundService(message: Message) { | ||
val intent = Intent(applicationContext, ExampleForegroundService::class.java) | ||
intent.putExtra(Constants.EXTRA_REMOTE_MESSAGE, message) | ||
ContextCompat.startForegroundService(applicationContext, intent) | ||
} | ||
} | ||
``` | ||
|
||
Now lets add the foreground service implementation. This should implement the notification plugin `ForegroundService` class, which handles the incoming notification intent and processes the event. To properly implement this, your class needs to override the `onCreate`, `getConnectRequest` and `getServiceConfig` functions. The `getConnectRequest` function is called by the `ForegroundService` to get a BreezSDK `ConnectRequest` which contains the data necessary to connect the SDK to the node. This data includes the Breez API key, the `Config` with it's workingDir and the node seed. | ||
|
||
<div class="warning"> | ||
<h4>Developer note</h4> | ||
In Android reading from secured storage can vary a lot depending if it is a Kotlin, Flutter or React Native based application and the dependencies used to write to the secured storage. Consult the dependency used to write to the secured storage on how to read data back from them. | ||
</div> | ||
|
||
```kotlin | ||
package com.example.application | ||
|
||
import breez_sdk.ConnectRequest | ||
import breez_sdk.EnvironmentType | ||
import breez_sdk.GreenlightNodeConfig | ||
import breez_sdk.NodeConfig | ||
import breez_sdk.defaultConfig | ||
import breez_sdk.mnemonicToSeed | ||
import breez_sdk_notification.ForegroundService | ||
import breez_sdk_notification.NotificationHelper.Companion.registerNotificationChannels | ||
import breez_sdk_notification.ServiceConfig | ||
|
||
class ExampleForegroundService : ForegroundService() { | ||
companion object { | ||
private const val TAG = "ForegroundService" | ||
private const val ACCOUNT_MNEMONIC = "BREEZ_SDK_SEED_MNEMONIC" | ||
} | ||
|
||
// Override the `onCreate` function | ||
override fun onCreate() { | ||
super.onCreate() | ||
// Register the default notification channels | ||
registerNotificationChannels(applicationContext, DEFAULT_CLICK_ACTION) | ||
} | ||
|
||
// Override the `getConnectRequest` function | ||
override fun getConnectRequest(): ConnectRequest? { | ||
// Get the Breez API key from the build config | ||
val apiKey = BuildConfig.BREEZ_SDK_API_KEY | ||
val glNodeConf = GreenlightNodeConfig(null, null) | ||
val nodeConf = NodeConfig.Greenlight(glNodeConf) | ||
val config = defaultConfig(EnvironmentType.PRODUCTION, apiKey, nodeConf) | ||
|
||
// Set the workingDir as the same directory as the main application | ||
config.workingDir = "${applicationContext.applicationInfo.dataDir}/breezSdk" | ||
|
||
// Get the mnemonic from secured storage using an implementation of | ||
// `readSecuredValue` depending on how data is written to secured storage. | ||
// See Developer Note | ||
return readSecuredValue(applicationContext, ACCOUNT_MNEMONIC) | ||
?.let { mnemonic -> | ||
ConnectRequest(config, mnemonicToSeed(mnemonic)) | ||
} | ||
} | ||
|
||
// Override the `getServiceConfig` function | ||
override fun getServiceConfig(): ServiceConfig? { | ||
// For now just return the default config | ||
return ServiceConfig.default() | ||
} | ||
} | ||
``` | ||
|
||
## Reference implementation | ||
For a complete reference, see how we implemented it in c-breez wallet: [BreezFcmService.kt](https://github.com/breez/c-breez/blob/main/android/app/src/main/kotlin/com/cBreez/client/BreezFcmService.kt). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# Android Foreground Service | ||
|
||
In the `AndroidManifest.xml` file of the application's `app/src/main` directory, add the user permissions necessary to handle notifications `POST_NOTIFICATIONS` as a foreground service `FOREGROUND_SERVICE`. Then to your main application add two services, one to handle messaging events and one to handle the foreground service. | ||
|
||
```xml | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
xmlns:tools="http://schemas.android.com/tools"> | ||
|
||
<!-- Add these permissions --> | ||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> | ||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> | ||
|
||
<application | ||
android:label="Custom App" | ||
android:name="${applicationName}" | ||
android:roundIcon="@mipmap/ic_launcher" | ||
android:icon="@mipmap/ic_launcher"> | ||
|
||
<!-- Add a service to handle messaging events --> | ||
<service | ||
android:name=".ExampleFcmService" | ||
android:exported="false"> | ||
<intent-filter> | ||
<action android:name="com.google.firebase.MESSAGING_EVENT" /> | ||
</intent-filter> | ||
</service> | ||
|
||
<!-- Add a service to handle the foreground service --> | ||
<service | ||
android:name=".ExampleForegroundService" | ||
android:foregroundServiceType="shortService" | ||
android:exported="false" | ||
android:stopWithTask="false"> | ||
</service> | ||
</application> | ||
</manifest> | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# Setup the Android Notification Plugin | ||
|
||
In order to add the Notification Plugin to your Android application, first you need to setup the Foreground Service, then add the Notification Plugin dependency and integrate it: | ||
|
||
## Next Steps | ||
- **[Setup the Foreground Service](android_service.md)** | ||
- **[Add the Notification Plugin](android_plugin.md)** |
Oops, something went wrong.