I have added a local notifications so when my app gets a push while opening there is still a popup and a sound.
It's working fine on Android, but on iOS the local notification doesn't appear at all.
The push notifications are working fine on both platforms.
This is my code in the push callback that should trigger the notification (if the app is open):
if(Display.getInstance().getCurrent() != null) {
LocalNotification n = new LocalNotification();
n.setId(value);
n.setAlertBody(value);
n.setAlertTitle({app name});
n.setBadgeNumber(1);
Display.getInstance().scheduleLocalNotification(n, System.currentTimeMillis() + 1000, LocalNotification.REPEAT_NONE);
}
Local notifications don't fire while the app is open in the foreground. You should use a different mechanism to make a sound while the app is running. Eg Display.vibrate()
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"DriverNotification" object:nil userInfo:userInfo];
// [[NSNotificationCenter defaultCenter] postNotificationName:#"UserNotification" object:nil userInfo:userInfo];
NSLog(#"%#",userInfo);
}
Put This Code in Your View Controller
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(receiveNotification:) name:#"DriverNotification" object:nil
];
Did you call registerUserNotificationSettings to register the fact that your app uses local notifications? If you don't do that, your request to post a local notification will be ignored.
See this text from the description of that method:
If your app displays alerts, play sounds, or badges its icon, you must
call this method during your launch cycle to request permission to
alert the user in these ways. (You must also make this request if you
want to set the applicationIconBadgeNumber property directly.)
Typically, you make this request if your app uses local or remote
notifications to alert the user to new information involving your app.
The first time your app launches and calls this method, the system
asks the user whether your app should be allowed to deliver
notifications and stores the response. Thereafter, the system uses the
stored response to determine the actual types of notifications you may
use.
After calling this method, the app calls the
application:didRegisterUserNotificationSettings: method of its app
delegate to report the results. You can use that method to determine
if your request was granted or denied by the user.
It is recommended that you call this method before you schedule any
local notifications or register with the push notification service.
Calling this method with a new user settings object replaces the
previous settings request. Apps that support custom actions must
include all of their supported actions in the notificationSettings
object.
you need to add below code in didFinishLaunchingWithOptions method of AppDelegate.m file for register local notification
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if ([[UIApplication sharedApplication] respondsToSelector:#selector(registerUserNotificationSettings:)])
{
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
else
{
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert)];
}
}
Related
I need to be able to send my GPS-location to a server every time I receive a silent-push notification from Firebase. The timer for sending a notification is currently set to every 10 minutes. When the phone is charging this is not a problem, but when it's idle and the application is in the background, the onMessageReceived from FirebaseMessagingService is only called every few hours. This leads me to believe it has something to do with the new power management rules for Android 9.0. But for my application to work I need to be able to send my location every 10 minutes. Not just sometimes.
I have tried to set the battery optimisation to 'not optimised' using Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
This does not seem to have any effect.
I also tried setting the priority of the Firebase notification to High. This works, but only for 10 messages per day, which means it's not a solution for my application. (Source: Power Management restrictions)
I am now trying to always have the application in the 'Active' bucket by opening a foregroundService. This should make sure the app is never in any other bucket, where the notifications can be deferred for a few hours.
An app is in the active bucket if the user is currently using the app, for example:
The app has launched an activity
The app is running a foreground service
The app has a sync adapter associated with a content provider used by a foreground app
The user clicks on a notification from the app
If an app is in the active bucket, the system does not place any restrictions on the app's jobs, alarms, or FCM messages.
(Source: Power Buckets Android9).
This does not seem like a solution I should want, though, since it might not be best practice. And it doesn't seem to work either anyways.
This is my onMessageReceived function:
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "From: " + remoteMessage.getFrom());
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
Map<String, String> params = remoteMessage.getData();
JSONObject object = new JSONObject(params);
PushNotificationManager.getInstance().handlePushNotification(object, getApplicationContext());
}
}
Right now I am clueless as to why the Firebase messages do not enter the onMessageReceived function.
Tim,
I think that the main problem is with how you send the push notification and what is its content.
If you check here - https://firebase.google.com/docs/cloud-messaging/android/receive
you will see that if the message contains notification data and the app is at background then the push notification goes to the Notification area.
You need to send a push notification that contains only data:
(Here you can find more information about the different types - https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages)
Here is what is the explanation how to trigger it-
In a trusted environment such as Cloud Functions or your app server, use the Admin SDK or the FCM Server Protocols: Set the data key only.
Please note that if you need to do a long running operation, then you will need to start a separate service (the service should present a notification in the notification area that it is running, otherwise you will get a crash on the newer Android versions)
Fixed by using AlarmManager. Schedule an alarm in 10 minutes, and when completing the code within the alarm, schedule a new alarm in 10 minutes.
AlarmManager can wake the phone if it is in doze mode, which means all code inside the trigger will be executed properly.
I am new to FCM and mobile coding. This is what I am trying to achieve:-
Develop an app to allow users to select some events.
I have a site that will loop through the events for users. When an event is close to its start time or some messages were created for
that event, I will send a FCM message to all the devices that
registered to that event.
I am confused on the implementation. This is what I am thinking:
When my app starts, I can register for push notification and it will return a devicetoken.
When user saves an event I can pass the devicetoken back to the server to re remember it.
In my site's code, I have some code to detect if an event is close and sends notification base on the devicetoken linked to
that event.
Is this about the right way to code? But if the user restarts the app or restarts the phone, isn't that I will get a new devicetoken? So I need to store some other identifier to identify a user (e.g. google plus user name)?
Is this about the right way to code? But if the user restarts the app or restarts the phone, isn't that I will get a new devicetoken? So I need to store some other identifier to identify a user (e.g. google plus user name)?
Yes it is right, and check the below for the questions:
You need to use FirebaseInstanceIdService it is used to handle the creation, rotation, and updating of registration tokens.
To retrieve the token of a device use this:
FirebaseInstanceId.getInstance().getToken()
The above token that you get may change in the following situations:
Instance ID is stable except when:
App deletes Instance ID
App is restored on a new device
User uninstalls/reinstall the app
User clears app data
Then using this method inside FirebaseInstanceIdService, it will refresh the token whenever any one of the situation happens:
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Log.d(TAG, "Refreshed token: " + refreshedToken);
// If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the
// Instance ID token to your app server.
sendRegistrationToServer(refreshedToken);
}
After you've obtained the token, you can send it to your app server and store it using your preferred method.
more info here: https://firebase.google.com/docs/cloud-messaging/android/client
I'm using azure-notificationhubs-java-backend to send notifications to Azure hub. I have Azure tags created per application user. Business require me to send notification to multiple users (this part is achieved), and report back the execution status, i.e. whom Azure was able to deliver the notification, and who all were missed (so that other communication can be made with those users). We've this scenario that not all users are yet registered with Azure. Below is the call I am making:
SyncCallback<NotificationOutcome> callback = new SyncCallback<>();
notificationHub.sendNotificationAsync(templateNotification, recipientTags, callback);
NotificationOutcome outcome = callback.getResult();
// outcome has just the notificationId, and trackingId
Any suggestion how can I get success and failed tags. Or there's some other call I can make using the notificationId or trackingId to meet the desired. Thanks!
You can get this data from per message telemetry. Please see below blog for more information.
https://azure.microsoft.com/en-us/blog/retrieve-platform-notification-system-error-details-with-azure-notification-hubs/
This has been asked a couple of times on Unity Questions, but never answered.
All I need to do is creare an Android pluugin which downloads few files from given urls and show a downloading progress in notification panel. Downloading should continue even if my Unity application is out of focus.
(source: cuelogic.com)
Here is a peice of code that I have right now:
void DownloadFiles(string[] urls)
{
foreach(var url in urls)
{
StartCoroutine(DownloadFile_CR(url));
}
}
IEnumerator DownloadFile_CR(string url)
{
WWW www = new WWW(url);
while(!www.isDone)
{
yield return null;
}
if(www.error == null)
{
//file downloaded. do something...
}
}
These are some texture files. So How do I get the texture result back from native android code?
Any king of help is appreciated.
I had the same problem. At first, I used a service that worked in the background and downloaded the files I needed, including calculating progress and on complete events.
Then, I made my plugin a little more simple and easy to use. You make an instance of a Java object, providing it with the GameObject name and method name for the responses. I used json to serialize and deserialize java and C# objects, because only strings can be passed between Unity's MonoBehaviour objects and java objects.
Here is how the downnload looks in the android plugin:
Uri Download_Uri = Uri.parse(url);
DownloadManager.Request request = new DownloadManager.Request(Download_Uri);
//Restrict the types of networks over which this download may proceed.
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
//Set whether this download may proceed over a roaming connection.
request.setAllowedOverRoaming(true);
//Set the local destination for the downloaded file to a path within the application's external files directory
String[] split = url.split("/");
request.setDestinationInExternalFilesDir(activity, null, split[split.length-1]);
//Set the title of this download, to be displayed in notifications (if enabled).
request.setTitle("Downloading " + title);
//Set a description of this download, to be displayed in notifications (if enabled)
request.setDescription("Downloading " + name);
request.setVisibleInDownloadsUi(false);
//Enqueue a new download and get the reference Id
long downloadReference = downloadManager.enqueue(request);
Then you could send back to unity the reference Id so you can get the progress and check if a file is still downloading once your app is been restarted (use SharedPreferences \ PlayerPrefs to store them)
If you want it to continue even when unity is not in focus then you cannot do it in C# in Unity with the WWW class.
If i wanted to do this i would probably write a native Android plugin that starts a download service.
From the official google docs:
A Service is an application component that can perform long-running
operations in the background, and it does not provide a user
interface. Another application component can start a service, and it
continues to run in the background even if the user switches to
another application.
Services are not that complex, you start them with Intents just as you would an activity and there are lots of examples online for this type of service.
Here is the official Android documentation regarding services: https://developer.android.com/guide/components/services.html
I am programming a mobile app using Cordova. I am implementing the push notifications using Push Plugin. The app is meant to run on all platforms but right now I am testing on Android and Windows.
In a particular javascript file I am saving a value call it 'category' in the localstorage:
localStorage.setItem("category", JSON.stringify(categoryarray));
Now when sending a push notification, the category is essential to decide whether to show the notification or not. If a user is subscribed to that particular category, then, the notification is to be shown, otherwise not. For this I simply create a condition and check whether the user has subscribed to the category included in the notification (but this is not really relevant to the point of the question). When the app is running this condition can be handled in javascript. When the app is not running, this is handled in java code:
else {
extras.putBoolean("foreground", false);
// Send a notification if there is a message
if (extras.getString("message") != null && extras.getString("message").length() != 0) {
createNotification(context, extras);
}
}
Now I want to get the value from the local storage at that instance that the notification is being pushed when the app is not running (and be able to check whether the notification should be shown or not).
I came into this link: Android Service reads localStorage?
But it seems to be meant for Android native code (reference to the webview). Apart from that I haven't really understood how it works and furthermore if it is applicable for my problem.
What do you suggest? How can I do it?
Edit: I didn't initially realise that the Push plugin java code won't be compiled with the Cordova app. So editing the code that is retrievable from the Cordova directory is in reality useless. Unless, someone can still suggest something, I know that this is an unanswerable question. Will have to re-attempt to create an API for this purpose and handle who to receive which notification at server side! (The reason why I resorted to this method was because I wasn't managing to create an API for notification purposes)
I didn't initially realise that the Push plugin java code won't be compiled with the Cordova app. So editing the code that is retrievable from the Cordova directory is in reality useless. Unless, someone can still suggest something, I know that this is an unanswerable question.
This isn't true, Cordova plugin code is compiled when you compile your Cordova app. All Cordova plugin's provide native source code that gets compiled into the app when you run cordova build (or cordova run <platform>).
If you wanted to solve this completely on the client side (rather than managing the categories that a user is subscribed to on the backend and only sending a notification if the user is subscribed to a category), you could extend the PushPlugin to manage subscriptions to categories.
As a rough sketch:
In PushNotification.js, add a method to subscribe to a channel:
PushNotification.prototype.subscribeToChannel(successCallback, errorCallback, channel) {
cordova.exec(successCallback, errorCallback, "PushPlugin", "subscribeToChannel", [{channel: channel}]);
}
In PushPlugin.java catch the subscribeToChannel action in the execute function:
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) {
...
if ("subscribeToChannel".equals(action)) {
//get the attached data
JSONObject jo = data.getJSONObject(0);
String channel = (String) jo.get("channel");
addChannelToSubscriptions(channel);
}
...
}
public void addChannelToSubscriptions(String channel) {
//store as a list in a sharedpreferences list
}
Then when a notification is received, you can check if the channel is a channel that has been subscribed to.
// Send a notification if subscribed to the channel
if (extras.getString("channel") != null && isSubscribedTo(extras.getString("channel"))) {
createNotification(context, extras);
}
public boolean isSubscribedTo(String channel) {
//see if the channel is in the shared preferences.
}
Personally, I think it'd be easier to manage subscriptions on the backend as to manage it in the app, you'd have to implement this logic for each platform you support. It would be easier to just add a webservice call in your Javascript. As a further alternative, if you don't want to handle the subscription logic on your backend, you could look at a service like Parse where the concept of subscribing to channels is built into the service.