How to change settings to receive Notifications in background state from within Expo app? - expo

I am receiving push notifications via expo-notification. I created a button within the app that allows you to set whether or not to receive notifications.
This app is made to not receive notifications while in the foreground state. I would like to implement a notification so that when that button is in the ON state, notifications can be received in the Background state, and in the OFF state, notifications cannot be received in the Background state.
const BACKGROUND_NOTIFICATION_TASK = "BACKGROUND-NOTIFICATION-TASK";
TaskManager.defineTask(BACKGROUND_NOTIFICATION_TASK, ({ data, error, executionInfo }) => {
if (error) {
console.log("error occurred");
}
if (data) {
console.log("data-----", data);
}
});
Notifications.registerTaskAsync(BACKGROUND_NOTIFICATION_TASK);
The above function is a function set for background reception.
I tried unregisterTaskAsync when the button is in OFF state and I still receive the notification in the background. What method should I use to implement changing notification settings in-app?

Related

Handle up/down buttons of Chromecast Voice Remote on Chromecast receiver side

I'm casting from iOS/Android to Google Chromecast device and trying to switch channels by clicking up/down buttons, but can not catch an event if Up or Down button has been clicked.
Tried to listen for all events from cast.framework.events.EventType.ALL but I receive only final events like (PLAY, PAUSE, TIME_UPDATE, etc.)
const context = cast.framework.CastReceiverContext.getInstance();
const playerManager = context?.getPlayerManager();
playerManager?.addEventListener(cast.framework.events.EventType.ALL, (event) => {
logScreen.info(`event: ${event.type}`);
});
Maybe somebody knows how to catch an event/message that up/down button called on Chromecast Voice Remote?
Thanks

AWS Lambda Function invoked by SQS trigger is not respecting the visibility timeout I'm manually setting within the function

I'm implementing my own webhooks service which will send out events to subscribed webhooks.
Overview of architecture:
events are pushed onto an SQS queue
a lambda function is triggered by SQS messages (event source mapping)
for each event, I make outgoing http requests to subscribed webhooks
non-2xx responses must be retried with exponential backoff (in such event, I change the message visibility on the received message)
since lambdas that are invoked by SQS will automatically delete the message upon completion I throw an error at the end of the function to prevent the automatic delete
As far as I can tell, the call to change the message visibility is succeeding. I'm wondering if there's something else baked into lambdas that are invoked by SQS. Upon failure from the lambda, is it internally changing the message visibility again? Or do lambdas that are invoked by SQS not respect message visibility changes (this really doesn't make any sense to me). Curious if anyone has any insight into this problem. I was quite surprised to find out that lambda automatically deletes messages upon success since it makes my particular use-case a little clunky feeling - throwing an error to fail the lambda function to prevent the message from being deleted.
Thanks in advance!
The nature of the SQS integration with Lambda is that the integration controls the polling of the messages. The mechanism used to determine if the message should be deleted is that the response from the lambda is not an error. It's not clearly stated in the documentation, but I believe when an error occurs the integration is going to set the visibility timeout to zero in order to make it immediately available for another process to pick it up. So in your example you are setting it to some number that allows you to retry, but when you return an error the integration is setting the timeout back to zero. If you need to have more control over that process you probably should not use the integration.
Update: This is actually not the case. I was failing to properly wait for the call to adjust the timeout to finish. As such the lambda was closing before that request was completing. The timeout I'm setting on the message within the lambda is being respected. I'm then throwing an error to prevent the message from being deleted.
Since SQS triggers for lambdas process messages in batches, using await in a standard forEach doesn't work (forEach does not await the callbacks if they are async). To bypass that, you can create your own version of an async forEach:
var AWS = require('aws-sdk');
exports.handler = async function(event, context) {
var sqs = new AWS.SQS({apiVersion: '2012-11-05'});
await asyncForEach(event.Records, async record => {
const { receiptHandle } = record;
const sqsParams = {
QueueUrl: '<YOUR_QUEUE_URL>', /* required */
ReceiptHandle: receiptHandle, /* required */
VisibilityTimeout: '<in seconds>' /* required */
};
try {
let res = await sqs.changeMessageVisibility(sqsParams).promise();
console.log(res);
} catch (err) {
console.log(err, err.stack);
throw new Error('Fail.');
}
}
});
return {};
};
async function asyncForEach(array, callback) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index, array);
}
}

How to send an event to all running instances of a AWS Lambda function

I have a Lambda function whose configuration is located in an external source (say S3).
In order to save some computing time, the function loads and keeps in memory the configuration at first execution.
I want to be able to tell all running instances of this Lambda function to reload the configuration on demand.
In the snippet below, the Lambda function reloads the configuration when the event has an attribute 'reload'. But obviously only one of the running instances gets the event.
How can I send the event to all running instances?
Is there a way to broadcast an event?
Is there another way to tackle the problem?
// Function to process events
var processEvent = function(event,callback) {
// process event
}
// Function to update configuration
var config; // global object representing configuration
var updateConfiguration = function(callback) {
// ... load asynchronously from S3
}
// Handle events
exports.handler = function(event, context, callback) {
if (event.reload) {
updateConfiguration(callback); // load configuration
} else if (!config) {
updateConfiguration(function() { // load configuration
processEvent(event,callback); // ... then process event
});
} else {
processEvent(event,callback); // process event directly
}
}
There is no capability to send messages to AWS Lambda containers. When they are not running, they are effectively "frozen" with no compute happening.
The closest option would be to have the handler check somewhere (parameter store?) whenever a function is invoked, to see whether it should reload.
Maybe you could subscribe to an SNS-Topic and send the event through this topic. The function inside your lambda that subscribes to this topic can then update the config variable.
Keep in mind that lambda functions have some special caching behaviour regarding global variables. You can read more on this topic here: https://medium.com/tensult/aws-lambda-function-issues-with-global-variables-eb5785d4b876

Apollo GraphQL unsubscribe seems to be broken

We are using Apollo GraphQL with subscriptions (via websockets) in a node.js backend and a react frontend.
The app provides a list of devices. When a user clicks on one device he gets the monitoring data for the device with live updates (from the subscription). When the user clicks on another device the subscription is stoppen, the data for the next device is being loaded and subscribed.
I pasted the messages from the websocket connection below. I first tried to paste the raw log here, but the screenshot is much easier to read.
Please ignore the ids 1-5. Important for my problem is id 6 and 7. The id is created when clicking on the first device (at 11:15:35) and then the details are closed so the subscription is stopped (at 11:15:36). Now the user clicks another device and starts subscription 7. Some seconds later the system pushes data for both, the 6th and 7th subscription.
Is there something I can do so "stop" actually means "stop" or is this a bug?
Edit: as requested, here is the code I use to subscribe/unsubscribe (I had to cut some parts due to company regulations)
const subscription = useRef(null)
const { loading, data, error, subscribeToMore } = useQuery(getDevice, { variables: { deviceId } })
useEffect(() => {
return () => {
if (!subscription.current) return
subscription.current()
subscription.current = null
}
}, [deviceId])
if (!subscription.current) {
subscription.current = subscribeToMore({
document: geDeviceSubscription,
variables: {
deviceId
},
updateQuery: (prev, { subscriptionData }) => ({ device: subscriptionData.data.subscribeDevice })
})
}
Edit 2: It is for sure not my clients issue as it also happens if the use the GraphiQL gui, start a subscription and stop it again. The new data is not displayed but it is visible in the websocket connection in the network tab of the browser (chrome).
It seems to have been a bug in an older apollo graphql or nestjs-apollo-graphql version (We use those frameworks in the backend). After upgrading all the backend dependencies to "latest", the bug doesn't seem to persist.

How to intercept AWS SNS messages to iOs mobile endpoints in Xamarin?

The documentation on AWS -SNS for use of SNS within Xamarin iOS projects shows how to register an iOS device to receive messages from SNS, but not clear how to intercept those messages within the application and programtically respond to the message. How do I capture the incoming message, and process appropriately rather than just showing the text of the message received? Is this done by sending a different message than is shown in the AWS console, and where can I intercept it in my application?
This is the example I've been following:
public override bool FinishedLaunching(UIApplication app, NSDictionary options) {
// do something
var pushSettings = UIUserNotificationSettings.GetSettingsForTypes (
UIUserNotificationType.Alert |
UIUserNotificationType.Badge |
UIUserNotificationType.Sound,
null
);
app.RegisterUserNotifications(pushSettings);
app.RegisterForRemoteNotifications();
// do something
return true;
}
public override void RegisteredForRemoteNotifications(UIApplication application, NSData token) {
var deviceToken = token.Description.Replace("<", "").Replace(">", "").Replace(" ", "");
if (!string.IsNullOrEmpty(deviceToken)) {
//register with SNS to create an endpoint ARN
var response = await SnsClient.CreatePlatformEndpointAsync(
new CreatePlatformEndpointRequest {
Token = deviceToken,
PlatformApplicationArn = "YourPlatformArn" /* insert your platform application ARN here */
});
}
}
Here is the message I'm sending:
{
"APNS_SANDBOX":"{\"aps\":{\"alert\":\"This is my message\"}}"
}
This seems to work fine for displaying a text message sent from the AWS console, whether the app is running or not, but that's not what I need for my app. (e.g. a chess app, where the SNS messages are used to exchange moves made by a pair of users and the app displays them.)
The FinishedLaunching method contains several not altogether helpful "do something" , but I can't figure out how to, say call some method in my PCL when a particular message is received and pass the content of the message to that method.
You can subscribe the DidReceiveRemoteNotification() event in AppDelegate.cs to get your content you sent on SNS.
public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
{
// retrieve something from a server somewhere
}
This event will trigger when user taps the notification to open the app and when this app is on background state or foreground state.
If this app is closed this event will not trigger, but we can also get the content in public override bool FinishedLaunching(UIApplication app, NSDictionary options) with the parameter options.
Moreover if you want to get it in PCL, we can make a MessagingCenter to achieve this:
Send content on native platform:
MessagingCenter.Send<object, NSDictionary>(this, "Notification", userInfo);
Then receive this MessagingCenter on PCL somewhere you like:
MessagingCenter.Subscribe<object, NSDictionary>(this, "Notification", (sender, dic) =>
{
});