I am trying to send push notification using RHMAP to iOS devices. Can anyone please let me know how to send push notification to specific device ID using RHMAP. I am able to send notification to all the devices but not to a specific device.
I couldn't find anything regarding this in RHMAP documentation also.
RHMAP has a lot of documented material and examples about push notifications.
The information that you are looking for is in the section "2.3.4.2. Recipient filtering"[1] of the Product features documentation.
"alias - user identification, such as a user name or an e-mail representing a single person (with possibly multiple devices). Intended to enable a unicast communication model."
For more information and examples you can check to fh.push client API[2] and fh.push cloud API[3]. There you can find the following example with filter criteria in the push notifications.
Push a message for specific deviceType in a specific Client App
var message = {
alert: "hello from FH"
},
options = {
apps: ["3uzl1ebi6utciy56majgqlj8"], // list of App IDs
criteria: {
deviceType: "android"
}
};
$fh.push(message, options,
function (err, res) {
if (err) {
console.log(err.toString());
} else {
console.log("status : " + res.status);
}
});
In the example above, for you implement your method using alias, you need to change the deviceType for alias as the following example.
alias: [] // Set here the alias that you are looking for
The following is an example for Android.
import com.feedhenry.sdk.PushConfig;
..........
......
...
private void register() {
PushConfig p = new PushConfig();
p.setAlias("my-alias");
FH.pushRegister(p, new FHActCallback() {
#Override
public void success(FHResponse fhResponse) {
startActivity(new Intent(RegisterActivity.this, MessagesActivity.class));
}
#Override
public void fail(FHResponse fhResponse) {
Toast.makeText(getApplicationContext(),
fhResponse.getErrorMessage(), Toast.LENGTH_SHORT).show();
finish();
}
});
}
[1] - https://access.redhat.com/documentation/en-us/red_hat_mobile_application_platform_hosted/3/html-single/product_features/#sending-notifications
[2] - https://access.redhat.com/documentation/en-us/red_hat_mobile_application_platform_hosted/3/html-single/client_api/#fh-push
[3] - https://access.redhat.com/documentation/en-us/red_hat_mobile_application_platform_hosted/3/html-single/cloud_api/#fh-push
You can set an alias for the device and use that alias to send the notification to it.
As you don't mention which SDK (Objective-C, Swift, Cordova) are you using I can't help you on how to set the alias as it's different for each of them, if you provide more information I can try to help you.
Related
I am having absolutely no luck getting push notifications to work in iOS in a Xamarin Forms project.
In AppDelegate.cs, I am calling the following in the FinishedLaunching override:
MSNotificationHub.Start("Endpoint=sb://[redacted].servicebus.windows.net/;SharedAccessKeyName=DefaultListenSharedAccessSignature;SharedAccessKey=[redacted]",
"[redacted]");
After the user logs in further in the app lifecycle, I also register the user with their user tag as follows:
public async Task UpdateTags(string token)
{
await Task.Run(() =>
{
try
{
// No point registering tags until the user has signed in and we have a device token
if (CurrentAccount == null)
{
Console.WriteLine($"UpdateTags cancelled: Account is null");
return;
}
var tag = $"user:{CurrentAccount.UserName}";
Console.WriteLine($"Registering tag: {tag}");
MSNotificationHub.AddTag(tag);
}
catch (Exception e)
{
Console.WriteLine($"Error registering tag: {e.ToString()}");
}
});
}
I have properly configured the Apple (APNS) settings in the notification hub, using the Token authentication mode (verified the four fields several times). The certificate (signing identity) is "iOS Distribution", the identifier bundle matches exactly what I have in the configuration (not using wildcard), the key has Apple Push Notifications service (APNs) enabled, and the provisioning profile has Platform: iOS and Type: App Store.
I pushed the application to TestFlight, as I don't have access to a physical Mac (we use a Cloud mac for development). When I view the device logs from my personal iPhone with the app installed, I see the following when I run it:
<Notice>: Registered for push notifications with token: [redacted]
<Notice>: Registering tag: user:[redacted]
There are no instances of "Error registering tag" or "UpdateTags cancelled" in the logs at all, which tells me that the method calls are succeeding without an exception. However, when I attempt to send a test notification to either a blank/empty tag, or the specific tag for my test user, no notifications are received and the messaging simply shows "Message was successfully sent, but there were no matching targets."
Also, when I pull all of the registrations with var registrations = await hub.GetAllRegistrationsAsync(0);, I only see the FCM (Firebase/Android) registrations from my successful testing on the Android side of things.
I am at a complete loss and have hit a wall, as there are no exceptions being thrown, and seemingly no way to troubleshoot what is going on behind the scenes.
This is also my 2nd attempt - I was using a more complex SBNotificationHub implementation and had the same results - no exceptions and everything looked fine at face value.
Thanks to a comment pointing to another question, I have determined that all I needed to do was to ensure that my tag registration ran on the main UI thread. My updated code below is working:
public async Task UpdateTags(string token)
{
await Task.Run(() =>
{
Device.BeginInvokeOnMainThread(() =>
{
try
{
// No point registering tags until the user has signed in and we have a device token
if (CurrentAccount == null)
{
Console.WriteLine($"UpdateTags cancelled: Account: {Trico.OrbitalApp.App.CurrentAccount};");
return;
}
var tag = $"user:{CurrentAccount.UserName}";
Console.WriteLine($"Registering tag: {tag}");
MSNotificationHub.AddTag(tag);
}
catch (Exception e)
{
Console.WriteLine($"Error registering device: {e.ToString()}");
}
});
});
}
You can try implementing the MSInstallationLifecycleDelegate interface which will allow you to check and see if the installation is being saved on the back end with either success or failure.
// Set a listener for lifecycle management
MSNotificationHub.SetLifecycleDelegate(new InstallationLifecycleDelegate());
// Implementation of the lifecycle listener.
public class InstallationLifecycleDelegate : MSInstallationLifecycleDelegate
{
public InstallationLifecycleDelegate()
{
}
public override void DidFailToSaveInstallation(MSNotificationHub notificationHub, MSInstallation installation, NSError error)
{
Console.WriteLine($"Save installation failed with exception: {error.LocalizedDescription}");
}
public override void DidSaveInstallation(MSNotificationHub notificationHub, MSInstallation installation)
{
Console.WriteLine($"Installation successfully saved with Installation ID: {installation.InstallationId}");
}
}
I'm currently trying to get push notifications working for my mobile app using Azure Notification Hubs. Android is working fine and the initial iOS set up in AppDelegate works ok with a sample tag.
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
if (deviceToken == null)
{
return;
}
SBNotificationHub hub = new SBNotificationHub(CommonConstants.LISTEN_CONNECTION_STRING, CommonConstants.NOTIFICATION_HUB_NAME);
// update registration with Azure Notification Hub
hub.UnregisterAll(deviceToken, async (error) =>
{
if (error != null)
{
System.Diagnostics.Debug.WriteLine($"Unable to call unregister {error}");
return;
}
string[] tags = new[] { "iostestpush" };
NSSet userTags = new NSSet(tags);
hub.RegisterNative(deviceToken, userTags, (error) =>
{
if (error != null)
{
System.Diagnostics.Debug.WriteLine($"Unable to call register {error}");
return;
}
});
var templateExpiration = DateTime.Now.AddDays(120).ToString(System.Globalization.CultureInfo.CreateSpecificCulture("en-US"));
hub.RegisterTemplate(deviceToken, "defaultTemplate", CommonConstants.APN_TEMPLATE_BODY, templateExpiration, userTags, (errorCallback) =>
{
if (errorCallback != null)
{
System.Diagnostics.Debug.WriteLine($"RegisterTemplateAsync error: {errorCallback}");
}
});
});
}
The issue I'm having is I need to register the UserId after a successful login. So I set up a service with the above code, saved the token to the device as string so it can be retrieved in the service and turned back into an NSData token
NSData deviceToken = new NSData(token, NSDataBase64DecodingOptions.None);
After a successful login I send the token string and the tag array to my service.
string[] userTag = new[] { loginResponse.UserId.ToString() };
await this._azureReg.SendRegistrationToServer(deviceToken, userTag);
Which, other than turning the token back into NSData and the user tag into an NSSet, is the same as above other than the name change. But Azure is claiming there is no registration even though my output shows
Registered for push notifications with token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
I thought it was the string conversion back and forth, so tested that in the AppDelegate and it worked fine.
So, I'm at a loss at how to register the UserId after a successful login and why it works in one place but not the other.
I hope that's clear and thanks for any advice in advance.
You probably ran into the same bug as me and several others.
Basically SBNotificationHub method overloads like UnregisterAll and RegisterTemplate with the callback signature do not work when you use them off the main thread, using the libraries to date. I was also using a Service for the same purpose (to handle push across platforms with different tags, especially for user id) but my implementation involved switching off the main thread for this.
The bug we logged and is now being addressed is here: https://github.com/Azure/azure-notificationhubs-ios/issues/95
The solution, for now, is to ditch SBNotificationHub completely. The Xamarin / Azure documentation is out of date, and SBNOtificationHub is legacy code. The recommended library is MSNotificationHub. https://github.com/azure/azure-notificationhubs-xamarin
As workarounds you can use the SBNotificationHub method overloads that do not involve callbacks (they return an error message instead) or the workaround in the 95 issue above.
I have integrated Firebase into Unity project and it all works. I would like to integrate disabling of push notifications if user wants to disable them in his app. I haven't found solution in code for this, also there is one unanswered question same as mine, so I am posting new one just in case someone has come with a solution for this.
I managed to do this by using Firebase Messaging Topic and calling SubscribeAsync() and UnsubscribeAsync().
private void Start()
{
if ( notificationsAreOn )
InitFirebaseMessaging();
else
DisableFirebase();
}
private void DisableFirebase()
{
Firebase.FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith( task =>
{
var dependencyStatus = task.Result;
if ( dependencyStatus == Firebase.DependencyStatus.Available )
{
FirebaseAnalytics.SetAnalyticsCollectionEnabled( false );
Firebase.Messaging.FirebaseMessaging.UnsubscribeAsync("VeryCoolTopic");
Firebase.Messaging.FirebaseMessaging.TokenReceived += null;
Firebase.Messaging.FirebaseMessaging.MessageReceived += null;
}
else
{
UnityEngine.Debug.LogError(
System.String.Format("Could not resolve all Firebase dependencies: {0}", dependencyStatus)
);
}
});
}
private void InitFirebaseMessaging()
{
Firebase.FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith( task =>
{
var dependencyStatus = task.Result;
if ( dependencyStatus == Firebase.DependencyStatus.Available )
{
FirebaseAnalytics.SetAnalyticsCollectionEnabled( true );
Firebase.Messaging.FirebaseMessaging.SubscribeAsync("VeryCoolTopic");
Firebase.Messaging.FirebaseMessaging.TokenReceived += OnTokenReceived;
Firebase.Messaging.FirebaseMessaging.MessageReceived += OnMessageReceived;
}
else
{
UnityEngine.Debug.LogError(
System.String.Format("Could not resolve all Firebase dependencies: {0}", dependencyStatus)
);
}
});
}
Then in the Firebase console when creating a message, use Topic as a target instead of User Segment.
You could also use disable whole Firebase by deleting the Firebase token using DeleteTokenAsync() but I haven't tested this because the the method with using subscribe and unsubscribe worked for me.
There are two types of messages that you can send with FCM: notifications messages, and data messages.
If your app is active, notification messages are delivered to your application code, which can decide what to do with it. When the app is not active, notification messages are automatically displayed by the system. There is not way to suppress this behavior.
Data messages are always delivered to your application code, which can decide what to do with them.
So if you want to allow the user to suppress the display of messages, you'll want to only send data messages, and then display them from within your application code.
Note that alternatively, you can find a way to not deliver messages to a user who has disabled notifications. How exactly to do this depends on your implementation. For example: if you're sending directly to FCM Instance ID tokens, you can skip the tokens of users who have disabled push notifications. And if you're using topic subscription to send messages, you can create a topic that users subscribe to to disable notifications, and then create conditions to exclude delivery to that topic.
I am sending Push notification from Azure Notification hub. I want to navigate to particular page on tap of received Toast Push Notification. I am receiving Push notification but unable to navigate to a particular page.
Here is my insert code:
function insert(item, user, request) {
var payload = '<?xml version="1.0" encoding="utf-8"?><toast><visual>' +
'<binding template="ToastText01"> <text id="1">' +
item.subject + '</text></binding></visual></toast>';
request.execute({
success: function () {
// If the insert succeeds, send a notification.
push.wns.send(null, payload, 'wns/toast', {
success: function (pushResponse) {
console.log("Sent push:", pushResponse);
request.respond();
},
error: function (pushResponse) {
console.log("Error Sending push:", pushResponse);
request.respond(500, { error: pushResponse });
}
});
}
});
}
Can any one please help?
There is a number of steps here and you didn't give very much detail on your problem. I'll try to explain the concept in full of anyone who might need the whole thing. Be sure you've set up all the steps in this article first: https://azure.microsoft.com/en-us/documentation/articles/mobile-services-javascript-backend-windows-phone-get-started-push/
First, you need to send the push notification with the page you want to load. So let's say you have a page that shows some details about an item. When you get a push notification, it automatically opens up that item. You could send a payload like:
var payload = '<?xml version="1.0" encoding="utf-8"?><toast><visual>' +
'<binding template="ToastText01"> <text id="1">' +
item.id + '</text></binding></visual></toast>';
Then you need to respond to the push notification. You can see the documentation page for this here: https://msdn.microsoft.com/en-us/library/hh221550.aspx
Your set up code would look something like this:
ShellToastNotificationReceived +=
new EventHandler<NotificationEventArgs>(httpChannel_ShellToastNotificationReceived);
public static HttpNotificationChannel CurrentChannel { get; private set; }
// This is from the tutorial linked in the first paragraph
private void AcquirePushChannel()
{
CurrentChannel = HttpNotificationChannel.Find("MyPushChannel");
if (CurrentChannel == null)
{
CurrentChannel = new HttpNotificationChannel("MyPushChannel");
CurrentChannel.Open();
CurrentChannel.BindToShellToast();
}
CurrentChannel.ChannelUriUpdated +=
new EventHandler<NotificationChannelUriEventArgs>(async (o, args) =>
{
// Register for notifications using the new channel
await MobileService.GetPush()
.RegisterNativeAsync(CurrentChannel.ChannelUri.ToString());
});
CurrentChannel.ShellToastNotificationReceived +=
new EventHandler<NotificationEventArgs(async (o, args) =>
{
RootFrame.Navigate(new Uri("/ItemPage.xaml"), args.Collection['1']);
});
}
I haven't tested any of this code, but it should be good enough to point you in the right directions. Basically,
Send the info you need to react in the Push Notification
Listen for event on your Client
Navigate to the frame you want to be on
Be sure to checkout this tutorial on Navigation: https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh771188.aspx
Is there a strategy that would work within the current Firebase offering to detect if the server connection is lost and/or regained?
I'm considering some offline contingencies for mobile devices and I would like a reliable means to determine when the Firebase data layer is available.
This is a commonly requested feature, and we just released an API update to let you do this!
var firebaseRef = new Firebase('http://INSTANCE.firebaseio.com');
firebaseRef.child('.info/connected').on('value', function(connectedSnap) {
if (connectedSnap.val() === true) {
/* we're connected! */
} else {
/* we're disconnected! */
}
});
Full docs are available at https://firebase.google.com/docs/database/web/offline-capabilities.
Updated:
For many presence-related features, it is useful for a client to know when it is online or offline. Firebase Realtime Database clients provide a special location at /.info/connected which is updated every time the client's connection state changes. Here is an example:
DatabaseReference connectedRef = FirebaseDatabase.getInstance().getReference(".info/connected");
connectedRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
boolean connected = snapshot.getValue(Boolean.class);
if (connected) {
System.out.println("connected");
} else {
System.out.println("not connected");
}
}
#Override
public void onCancelled(DatabaseError error) {
System.err.println("Listener was cancelled");
}
});
I guess this changed in the last couple of months. Currently the instructions are here:
https://firebase.google.com/docs/database/web/offline-capabilities
In summation:
var presenceRef = firebase.database().ref("disconnectmessage");
// Write a string when this client loses connection
presenceRef.onDisconnect().set("I disconnected!");
and:
var connectedRef = firebase.database().ref(".info/connected");
connectedRef.on("value", function(snap) {
if (snap.val() === true) {
alert("connected");
} else {
alert("not connected");
}
});
I'll admit I don't know a lot about how references are set, or what that means (are you making them out of thin air or do you have to have already created them beforehand?) or which one of those would trigger something on the server as opposed to something on the front end, but if the link is still current when you read this, a little more reading might help.
For android you can make user offline by just a single function called onDisconnect()
I did this in one of my chat app where user needs to get offline automatically if network connection lost or user disconnected from Internet
DatabaseReference presenceRef = FirebaseDatabase.getInstance().getReference("USERS/24/online_status");
presenceRef.onDisconnect().setValue(0);
On disconnecting from network Here I am making online_status 0 of user whose Id is 24 in firebase.
getReference("USERS/24/online_status") is the path to the value you need to update on offline/online.
You can read about it in offline capabilities
Note that firebase takes time around 2-10 minutes to execute onDisconnect() function.
firebase for web
firebase.database().ref(".info/connected").on("value",(snap)=> {});
The suggested solution didn't work for me, so I decided to check the connection by writing and reading 'health/check' value. This is the code:
const config = {databaseURL: `https://${projectName.trim()}.firebaseio.com/`};
//if app was already initialised delete it
if (firebase.apps.length) {
await firebase.app().delete();
}
// initialise app
let cloud = firebase.initializeApp(config).database();
// checking connection with the app/database
let connectionRef = cloud.ref('health');
connectionRef.set('check')
.then(() => {
return connectionRef.once("value");
})
.then(async (snap) => {
if (snap.val() === 'check') {
// clear the check input
await connectionRef.remove();
// do smth here becasue it works
}
});