react-native-onesignal receive push notification without opening notification - reactjs

I have checked react-native-onesignal github README and it seems the only way to get the notification is to open which is through the onNotificationOpened() callback.
Their documentation stated that:
When any notification is opened or received the callback onNotification is called passing an object with the notification data.
But onNotification clearly does not work.
Is there any way to get the notification without opening the push notification or enabling the in-app alert notification?

The onNotification function will only be called when opening a notification or when one is received while the app is in focus.
If you need to handle a notification in the background before it is opened you will need to do so with native code.
iOS - set content_available to true on the OneSignal create notification REST API POST call, this will fire the
- application:didReceiveRemoteNotification:fetchCompletionHandler: selector.
Android - Setup a NotificationExtenderService by following the OneSignal Background Data and Notification Overriding instructions.

Regarding implementation of NotificationExtenderService in android (not answering the original question, but the question asked by #ryeballar), as explained in https://documentation.onesignal.com/docs/android-customizations#section-background-data-and-notification-overriding:
I am getting notifications when the app is closed/swiped-out/not-started without implementing NotificationExtenderService
However, in order to implement NotificationExtenderService you need to do the following (as described in the onesignal documentation referenced above, note that there is a typo there, fixed below):
Create a file called NotificationExtender.java in node_modules\react-native-onesignal\android\src\main\java\com\geektime\rnonesignalandroid, with the following contents:
.
import com.onesignal.OSNotificationPayload;
package com.geektime.rnonesignalandroid;
import com.onesignal.OSNotificationPayload;
import com.onesignal.OSNotificationPayload;
import com.onesignal.NotificationExtenderService;
import com.onesignal.OSNotificationReceivedResult;
public class NotificationExtender extends NotificationExtenderService {
#Override
protected boolean onNotificationProcessing(OSNotificationReceivedResult receivedResult) {
// Read properties from result.
// Return true to stop the notification from displaying.
return false;
}
}
Add the following to android\app\src\main\AndroidManifest.xml:
.
<service android:name=".NotificationExtender"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="false">
<intent-filter>
<action android:name="com.onesignal.NotificationExtenderService" />
</intent-filter>
</service>
rebuild your app

Related

Onesignal Webpush Notification : This site has been updated in the background

I have some concerns & questions about web push notifications using onesignal, because sometimes the notification show "this site has been updated in the background".
First what caused the notif shown like that, is that from settings device phone or from my code?
Second how to fix the message content like that?
i implement like this in head.js
if (navigator.serviceWorker) {
navigator.serviceWorker.register(`https://test.com/OneSignalSDKWorker.js?appId=test123`).then(function (registration) {
console.log(registration);
});
}
<script src="https://cdn.onesignal.com/sdks/OneSignalSDK.js"></script>
is i call double sdk caused that?

Salesforce - Call external API on button click and update custom field from response

So I'll start by saying I'm a C# .Net/Javascript developer with a lot of experience, but I have zero experience with Salesforce. Never ever seen it before today. So, I've been asked by another team to add a custom button to a Contact object, which when clicked calls an external API and updates a custom field in the Contact with the response. It was pitched as "just write some Javascript that calls an API when a button is clicked, it's literally embedded into the page, 15 minute job...".
Following what appears to be quite an outdated document, I've ended up in the Object Manager, selected the Contact object and I'm into the Buttons, Links and Actions page. I'm assuming before this was done using the Execute Javascript behaviour, which in the Lightning version I'm advised against using. So after much Googling I've read about APEX classes, Visualforce Components, Lightning Components, the Salesforce REST API, etc, etc. Not a 15 min job.
Essentially the requirements are to embed a button (or action, or..?) into this Contact page, so that when the sales guy clicks it, it gathers some of the Contact's details and uses them to form an API call to an external service. The data will be used to form a response, which must then be read (as JSON, then parsed) and written into a custom field on the Contact.
What would be the best approach for developing a solution? In the Apex Debug environment I've put together the code to call the API and parse the JSON response, I'm assuming I need to wrap this in an Apex class, with a method that calls this code and returns the response. What I'm not sure of is how to call into this from the button, and update the field in the Contact.
Do I need to do all that from the Apex Class method? passing in a reference to the Contact, or is there another component that needs to sit in between and do this.
Am I right in assuming I'll need to use the Salesforce API to update the Contact?
Any pointers appreciated.
Oh man. It can be a 15 min job but it's definitely "easy when you know how" or have some examples ;)
What's your user interface, Classic or Lightning? Do they have plans to migrate to Lightning soon? I'm assuming it's Lightning if you figured out the "Execute JavaScript" hacks are passé.
Do you care where the button/action will be? Is the top right corner with all other buttons fine or do you want it to be droppable to pretty much any area in the page?
Does the API callout need username, password, maybe certificate? It'll determine whether you need just to whitelist the endpoint on firewall (Setup -> Remote Site Settings) or you'll need something more advanced (Setup -> Named Credentials).
Do you have SFDX command line (CLI), VSCode / are determined to install some tooling? The Lightning Web Components are cutting edge, most sleek etc but you can't create them straight in the browser (at least not yet), you need tooling. Visualforce is OK but nothing special for this use case, Aura components are bit clunky to write - but you can do both in Developer Console without extra tooling.
Parsing the JSON response - depends how complex it is, you can hand-craft parser with JSON.deserializeUntyped() but life's too short for this. Here's nice apex code generator similar to what you'd get from parsing WSDL: https://json2apex.herokuapp.com/
We'll try to do Aura component way. It's ugly, LWC is future but hey, it'll get you started.
Go to Setup -> Remote Site Settings and add new entry with https://en.wikipedia.org/
Create new Apex class:
public with sharing class Stack63364119 {
static final String endpoint = 'https://en.wikipedia.org/w/api.php?action=query&format=json&list=search&srsearch=';
#AuraEnabled
public static String doCallout(Id contactId){
if(contactId == null){
throw new MyException('Missing record id');
}
List<Contact> contacts = [SELECT MailingCountry FROM Contact WHERE Id = :contactId];
if(contacts.isEmpty() || String.isBlank(contacts[0].MailingCountry)){
throw new MyException('Could not find the contact');
}
Contact c = contacts[0];
HttpRequest req = new HttpRequest();
req.setEndpoint(endpoint + c.MailingCountry);
req.setMethod('GET');
HTTPResponse res = new Http().send(req);
System.debug(res.getStatus());
System.debug(res.getBody());
// no special parsing, just chuck it into Description field
// no error handling
if(res.getStatusCode() == 200){
c.Description = res.getBody().abbreviate(32000);
update c;
}
return res.getBody();
}
public class MyException extends Exception{}
}
Make new "Lighning Component" in developer console (it'll be Aura, not LWC). You can tick the last checkbox about "lightning quick action". Name can be same as class but doesn't have to be.
For component (~ html part) paste this
<!-- Loosely based on https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/controllers_server_actions_call.htm -->
<aura:component controller="Stack63364119" implements="force:hasRecordId,force:lightningQuickAction" >
<!-- in the name of all that is holy do not name the JS function same as the Apex class function, it'll give you very cryptic errors to debug -->
<aura:handler name="init" value="{!this}" action="{!c.runCallout}"/>
</aura:component>
For controller (~ JavaScript) paste this
({
runCallout : function(cmp) {
let action = cmp.get('c.doCallout');
action.setParams({contactId : cmp.get('v.recordId')});
action.setCallback(this, function(response){
let state = response.getState();
if (state === "SUCCESS") {
alert('Saved OK: ' + response.getReturnValue());
$A.get("e.force:closeQuickAction").fire(); // if you want to self-close
} else if (state === "ERROR") {
var errors = response.getError();
if (errors) {
if (errors[0] && errors[0].message) {
console.log("Error message: " + errors[0].message);
}
} else {
console.log("Unknown error");
}
}
});
$A.enqueueAction(action);
}
})
Finally go Object Manager -> Contact -> Buttons Links and Actions. Create new Quick Action.
And add it to page layout(s)!
It should get you started. Maybe you'll decide to split it a bit, Apex would only do the callout, return results to UI and if user is happy - updating the contact can be done with one of these: https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/data_service_save_record.htm. Separation of concerns blah blah (but will the user be happy with 2 clicks).
P.S. If you tweak it and it dies but it's hard to see any JavaScript errors - it'll be because default is to run in release mode, SF rewrites your source code a bit, optimises, polyfills for "browsers" like IE11... Go to Setup -> Debug Mode and enable for your user.
P.P.S. In sandbox / dev org it's good idea to go Setup -> Session Settings -> and untick "Enable secure and persistent browser caching to improve performance". Your component will be always fresh, saves some frantic hitting Ctrl+R. Don't do it in prod ;)
I will write to you my approach
Button on the record page/page layout -> lighting component or flow -> Apex class for collecting data -> apex class request & response API(don't forget to add the endpoint to remote site settings)-> parse response and update contact (you can use queries and DML operations inside Apex)
lighting component it will be very simple just have a the apex class as the controller example
<aura:component implements="force:appHostable,lightning:isUrlAddressable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" controller="contactController" access="global" >
<aura:handler name="init" value="{!this}" action="{!c.fetchContact}"/>
</aura:component>
controller
({
fetchContact : function(component, event, helper) {
helper.fetchContactHelper(component, event, helper);
}
})
helper
({
fetchAccHelper : function(component, event, helper) {
var action = component.get("c.fetchContacts");
action.setParams({
});
action.setCallback(this, function(response){
var state = response.getState();
if (state === "SUCCESS") {
}
});
$A.enqueueAction(action);
}
})
assuming is apex function is fetchContacts and class contactController

symfony 5 web debug toolbar showing anonymous and cannot redirect after onAuthenticationSuccess

I have been following along with the following Symfony tutorials, but I believe they are using version 4 and I am using version 5. They reach a point in the tutorial which shows that the web debug toolbar shows the user's email logged and they even pointed out that if you see logged as anonymous, then just refresh. I did refresh, but it still shows as anon.
As you can see by the following screen shot, login was successful and it shows the correct username as well:
I started to watch the first part of the tutorial - listed below - when I reached a point in the second part that pointed out that I should watch the first part, which made sense, that I might have missed something, but that was an even older version of Symfony and things have changed in version 5.
First part of the tutorial
Second part of the tutorial
After going through the tutorials, I still have the web debug tool showing anon. Now, I am using React as a form to POST the email and password - see next screen shot - would that effect how the web debug toolbar, but I do not see how, because the console shows that the system knows the user.
Does anyone know a config that needs to be changed?
I have tried changing the following within src\Security\TokenAuthenticator - getUser from:
return $this->em->getRepository(User::class)
->findOneBy(['apiToken' => $credentials])
;
To:
return $this->em->getRepository(User::class)->findOneBy(['email' => $credentials['email']]);
But no change, still shows anon
Also, as the subject states, I cannot redirect via onAuthenticationSuccess
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
// on success, let the request continue
return new RedirectResponse($this->urlGenerator->generate('app_homepage'));
}
I do not see why this does not work. Again, is it because I am posting via a React app?
Turns that it is because I am running an older version of the browser Firefox and the log in is working. You can see by the screen shot of both Firefox and Chrome, that it is working Chrome
As far as the redirect goes, PHPStorm was saying that I did not have urlGenerator available in the TokenAuthenticator class. As a result, I should have noticed before and this is what I did to correct it:
In my src\Security\TokenAuthenticator I have the following:
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
In my constructor:
private $em;
private $urlGenerator;
public function __construct(EntityManagerInterface $em, UrlGeneratorInterface $urlGenerator)
{
$this->em = $em;
$this->urlGenerator = $urlGenerator;
}
My onAuthenticationSuccess:
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
// on success, let the request continue
// redirect to some "app_homepage" route - of wherever you want
return new RedirectResponse($this->urlGenerator->generate('app_homepage'));
}
But it is still not working
I have tried
use Symfony\Component\HttpFoundation\RedirectResponse;
private $redirectResponse;
public function __construct(EntityManagerInterface $em, RedirectResponse $redirectResponse)
{
$this->em = $em;
$this->redirectResponse = $redirectResponse;
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
// on success, let the request continue
// redirect to some "app_homepage" route - of wherever you want
return $this->redirectResponse->redirectToRoute('app_homepage');
}
But PHPStorm tells me that it cannot find method redirectToRoute within class RedirectResponse
The only thing that I have found to work with redirecting users to the home page after successful is login, is within my React login app. I have an async to my handleClick method, after the fetch POST, I have a setTimeout of 3000 that uses a plain javascript:
window.location.href = '/';
I would love to know the answer to why I cannot redirect via the Authenticator class that I have created, but at least someone who is using Firefox will not have to wonder why their web debug tool is not showing that the user has successfully logged in while still showing anon

HostListener and Angular Universal

I'm trying to listen to a MessageEvent sent with postMessage in my Angular 2 component.
My first attempt was simply doing:
window.addEventListener("message", this.handlePostMessage.bind(this));
And then in ngOnDestroy:
window.removeEventListener("message", this.handlePostMessage.bind(this));
However this didn't work as expected. If I navigated to another route and back, there would be two event listeners registered.
So instead I've been trying to decorate the method with HostListener, but I can't get this working when using prerendering (Angular Universal with .NET Core using the asp-prerender-module).
#HostListener('window:message', ['$event'])
private handlePostMessage(msg: MessageEvent) {
...
}
That gives me the following error on page load:
Exception: Call to Node module failed with error: Prerendering failed because of error: ReferenceError: MessageEvent is not defined
Is there a workaround for this?
You're getting this error because MessageEvent is not defined. You must import whatever file defines this.
My #HostListeners look like this:
#HostListener("window:savePDF", ["$event"]) savePDF(event) {
this.savePDFButtonPushed();
}
and you can read more about them here:
https://angular.io/guide/attribute-directives
However, I'm currently experiencing the same issue you are -- that if I navigate to another route and back, I now receive two events. And that is using #HostListener. :-( However I haven't upgraded Angular in a while (currently using 4.4.6), so maybe they've fixed it since that release.
**Edit: Just upgraded to Angular 5.1.0. The 'duplicate events' #HostListener issue remains. :-(
Edit #2: I tried also using window.addEventListener like you tried, and also had the same issue, despite using window.removeEventListener in ngOnDestroy().
This lead me to dig a little deeper, where I found some code I had added to listen to messages from a child iFrame. Any chance you have something similar in your code?
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
// Listen to messages from child window ("unsign" and "savePDF") and pass those along as events to Angular can pick them up in its context
eventer(messageEvent,function(e) {
window.dispatchEvent( new Event( e.data ) );
},false);
This had been in my page's constructor. I protected it so it only executed the first time the page was constructor, and now all is well.

Refreshing web page in real time in sails.js

In my project I am using sails.js. From test1.ejs I am calling a web service which in turn calls another ejs(test2.ejs) using res.view().
Now android user is inputting some values which affects the database and needs to reflect on the web page in real time. I am not able to figure out how this can be achieved using sails.js.
Also I need to even show the android user response and at the same time refresh the web page. In short I want a dynamic UI like share market where any changes on the server is reflected on the front end.
Will I need to use anything else like angularjs?
You can use JavaScript Interface if I understand your problem right.
You should create the class like this:
public class WebAppInterface {
Context mContext;
/** Instantiate the interface and set the context */
WebAppInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
#JavascriptInterface
public void showToast(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}
}
After this you should connect this interface to your webview like this:
webView.addJavascriptInterface(new WebAppInterface(this), "Android");
Now you can call Java code from JS like this:
<script type="text/javascript">
function showAndroidToast(toast) {
Android.showToast(toast);
}
</script>
Or call JS code from Java like this:
webview.loadUrl("javascript:window.showAndroidToast(\"Hello, World!\")");
More info is available here: https://developer.android.com/guide/webapps/webview.html

Resources